로컬 칸반을 통한 계획 추적
칸반은 서로 다른 프로젝트와 서로 다른 날짜에 걸친 Claude 세션이 계획 상태를 세션 간에 유지할 수 있도록 존재합니다: 계획을 할당(claim)하고, 상태를 이동시키고, 노트를 남깁니다. 여러 Claude 인스턴스가 하나의 보드를 공유할 수 있습니다 — 항상 프로젝트 슬러그(slug) 아래에 작업을 버킷화하여 서로 다른 저장소의 계획이 충돌하지 않도록 하세요.
칸반이 실행 중인 머신에서 프로젝트의 중요한 계획을 작업 중이라면, 작업 진행 중에 칸반과 계속 소통해야 합니다.
보드
출처: https://github.com/hechtch/kanban — Angular SPA와 Go API over SQLite입니다. 로컬에서 실행되며, 호스팅된 인스턴스는 없습니다.
git clone https://github.com/hechtch/kanban.git
cd kanban
make container-build && make container-run # CONTAINER_RUNTIME=podman (podman 사용 시)
make container-run은 -p 8000:8000을 게시하고 ~/.kanban/data를 마운트하여 영속성을 제공하므로, 단일 컨테이너가 UI와 API를 모두 포트 8000에서 제공합니다.
| 모드 | 사람용 UI | 에이전트 API 기본 주소 |
|---|---|---|
컨테이너 (make container-run) | http://localhost:8000/board | http://localhost:8000/api/agent |
개발 (make run) | http://localhost:4200/board | http://localhost:8000/api/agent |
에이전트 API는 두 모드 모두 포트 8000에 있습니다 — 사람용 UI 링크만 다릅니다. make run은 Angular 개발 서버를 4200에서 별도로 제공하기 때문입니다. 사용자가 make run을 실행 중인지 알지 못한다면 컨테이너의 8000 UI 링크를 사용하세요.
만약 사용자가 칸반을 다른 곳(리버스 프록시 뒤, 다른 게시 포트)에 배포했다면, 그들이 기본 URL을 알려줄 것입니다 — 기본값보다 그들의 것을 사용하고 /api/agent 접미사를 유지하세요.
실행 중인가요?
KB=http://localhost:8000/api/agent
curl -sS http://localhost:8000/api/health
# {"status":"ok"}
실패하면 칸반이 실행 중이지 않은 것입니다. 직접 시작하지 마세요 — 칸반은 ~/.kanban/data/kanban.db에 쓰며, 두 번째 프로세스가 해당 DB를 놓고 경쟁하는 것은 추적이 없는 것보다 더 나쁩니다. 사용자에게 다운되었다고 알리고, 위의 make container-run 명령줄을 제안한 후, 추적 없이 실제 작업을 계속하세요.
표준 명세 — 엔드포인트 세부 사항을 위해 이것을 읽으세요
API는 타입이 지정된 Go 핸들러에서 생성된 전체 OpenAPI 3.1 명세를 제공합니다. 경로, 요청/응답 형태, 상태 코드 및 유효성 검사 규칙에 대한 진실의 원천(source of truth)입니다 — 의심스러울 때는 추측하거나 오래된 문서에 의존하지 말고 이것을 가져오세요:
- 명세 (JSON):
http://localhost:8000/api/openapi.json - 명세 (YAML):
http://localhost:8000/api/openapi.yaml - Swagger UI (사람용):
http://localhost:8000/api/docs
이 파일의 나머지 부분은 에이전트 워크플로우(슬러그, 규칙, 레시피)를 제공하여 API를 처음부터 배울 필요가 없도록 합니다. 여기에 포함되지 않은 엔드포인트 세부 사항은 명세를 읽으세요.
응답에는 응답의 JSON 스키마를 가리키는 $schema URL 필드가 포함됩니다(huma의 규칙). 응답을 스키마에 대해 검증하지 않는 한 무시하세요.
이 스킬이 가정하는 계획 파일 규칙
보드는 **계획(plans)**을 추적하며, 계획은 저장소의 마크다운 파일입니다:
plans/<topic>.md— 진행 중인 각 개별 계획당 하나의 파일로, 이유와 무엇을 설명합니다. 실행 가능한 작업에는 체크박스(- [ ]/- [x])를 사용하고 작업이 진행됨에 따라 제자리에서 개선하세요.plans/done/<topic>.md— 작업이 출시되거나 중단되면 파일이 이동하는 곳이며, 상단에 짧은 "Delivered in <버전> — <날짜>" 헤더가 있습니다.CHANGELOG.md— 공개적인 "무엇이 변경되었는지"이며,plans/done/이 이유를 제공합니다.
저장소가 아직 이 레이아웃을 사용하지 않는다면, 보드에서 계획을 할당하기 전에 plans/를 생성하고 파일을 시드(seed)하세요 — 아래 slug 규칙은 파일 이름에 의존합니다.
슬러그 규칙
모든 것은 숫자 ID가 아닌 **슬러그(slug)**로 키가 지정됩니다. 프롬프트나 코드에 task.id를 저장하지 마세요.
- 계획 슬러그 =
.md를 제외한 계획 파일 이름, 소문자화.plans/photo-import.md→photo-import. - 프로젝트 슬러그 = 케밥-케이스(kebab-case)의 저장소 또는 이니셔티브 이름.
~/projects/photo-organizer→photo-organizer. (프로젝트 이름이 "Photo Organizer"인 경우, 서버가 이름에서 자동으로photo-organizer를 파생합니다; 명시적 슬러그를 전달할 수도 있습니다.) - 형태(서버 측에서 강제):
^[a-z0-9]([a-z0-9-]*[a-z0-9])?$. 잘못된 슬러그는400을 반환합니다. 소문자, 단어 사이는 하이픈, 밑줄이나 대문자 없음.
작업 본문 = 계획
처음으로 계획을 할당(claim)할 때, 계획 마크다운을 body 필드로 보내세요. 그 순간부터 칸반 DB가 표준이 됩니다 — 진행 중에 파일에 다시 편집 내용을 동기화하지 마세요. 디스크의 plans/<slug>.md 파일은 시드(한 번 사용됨)입니다; plans/done/<slug>.md는 작업이 출시될 때 작성하는 보관 스냅샷입니다.
나중에 새 body로 다시 PUT하면, 당신의 버전이 우선합니다. 사람도 UI의 /task/<task_id>에서 렌더링된 보기에서 오타를 수정할 수 있습니다; 두 편집 모두 같은 열에 기록됩니다.
계획을 할당(claim)하는 것이 "Claude의 것"으로 만듭니다
설정할 담당자(assignee) 필드는 없습니다. 보드가 파생합니다: plan_slug를 가진 작업 — 정확히 PUT /plans/<slug>가 생성하는 것 — 사이드바의 담당자 필터 아래 Claude 아래에 렌더링되고 카드에 Claude 칩을 얻습니다. 사람이 직접 만든 작업에는 plan_slug가 없으며 you 아래에 남습니다.
따라서 이 API를 통해 계획을 할당하는 것은 가시적인 행위입니다. 사람이 직접 수행하는 작업에 단지 노트를 남기기 위해 할당하지 마세요.
상태(Statuses)
다섯 개의 보드 열, 고정됨:
todo → doing → blocked → awaiting_merge → done
추가로 backlog(보드 외, 선택적 6번째).
blocked— 작업을 진행할 수 없음; 노트에 이유를 설명하세요.awaiting_merge— 코드가 작성되고 푸시되었으며, PR이 병합되거나 수동 병합을 기다리는 중입니다. 작업이 아직 출시되지 않았기 때문에done과 다릅니다.- 브랜치가 실제로 메인라인에 병합된 경우에만
done으로 전환하세요. 자동 전환하지 마세요.
'waiting'은 유효한 상태가 아닙니다 — 마이그레이션에서 'blocked'로 이름이 변경되었습니다.
Git 브랜치
계획(및 모든 작업)은 git_branch 필드를 가질 수 있습니다 — 작업이 진행 중인 브랜치입니다. 기능 브랜치를 생성할 때 설정하여 사람이 카드에서 볼 수 있도록 하세요:
curl -sS -X PUT $KB/plans/photo-import \
-H 'Content-Type: application/json' \
-d '{"git_branch":"feat/photo-import"}'
{"git_branch": null}으로 지웁니다. 브랜치는 카드에 고정폭 칩으로 렌더링됩니다.
제안된 모델 및 노력(Effort)
모든 작업은 model과 effort를 가질 수 있습니다 — 다음에 작업을 선택할 에이전트를 위한 힌트입니다. 사람이 티켓에서 설정하거나(또는 계획의 무게를 알 때 당신이 설정할 수 있음), 카드에 fable / xhigh 칩으로 렌더링됩니다. 이를 존중하세요: 작업이 sonnet / high라고 말하는 계획을 재개할 때, 소유자가 지출하기를 원하는 등급입니다; fable / xhigh 감사 계획은 큰 모델을 높은 노력으로 원합니다.
curl -sS -X PUT $KB/plans/security-audit \
-H 'Content-Type: application/json' \
-d '{"model":"fable","effort":"xhigh"}'
model은 자유 형식 약어입니다 —fable,opus,sonnet,haiku가 기본 세트입니다; 서버는 소문자화하고 공백을 제거하며, 40자를 초과하면 거부합니다.effort는 반드시low,medium,high,xhigh,max(Claude Code의 reasoning-effort 계층) 중 하나여야 합니다; 다른 것은422입니다.- 둘 다 선택 사항이며 독립적입니다;
null로 지웁니다. 없음은 "선호도 없음 — 세션 기본값 사용"을 의미합니다.
프로젝트: 보관 및 기본 태그
프로젝트는 이름/색상 외에 두 개의 필드를 가지며, 둘 다 동일한 PUT $KB/projects/<slug> 업서트(upsert)에서 설정 가능합니다:
-
archived— 프로젝트가 완료되었습니다. 해당 계획은 사이드바와 보드에서 사라지지만(사람이 확장할 수 있는 "archived" 섹션으로 접힘), 아무것도 삭제되지 않으며 모든 엔드포인트는 여전히 이를 반환합니다. 프로젝트의 작업이 출시되었을 때 설정하세요:curl -sS -X PUT $KB/projects/photo-organizer \ -H 'Content-Type: application/json' -d '{"archived":true}' -
tags— 프로젝트의 모든 작업이 가지는 태그입니다. 서버는 읽기 시 각 작업의tags에 이를 병합(merge)하므로,["infra"]로 태그된 프로젝트 아래의 계획은 개별적으로 태그되지 않고infra로 태그되어 반환됩니다. 작업 태그와 마찬가지로 전체 세트를 대체합니다:curl -sS -X PUT $KB/projects/photo-organizer \ -H 'Content-Type: application/json' -d '{"tags":["media","infra"]}'병합이 읽기 시 발생하므로, 프로젝트에서 태그를 제거하면 모든 작업에서 한 번에 제거됩니다. 프로젝트의 태그를 개별 작업에 설정하지 마세요 — 서버는 작업 자체 세트에서 상속된 태그를 제거하므로, no-op만 작성하게 됩니다.
세션별 워크플로우
KB=http://localhost:8000/api/agent
# 1. 프로젝트가 존재하는지 확인 (멱등적 — 처음에는 201, 이후에는 200).
curl -sS -X PUT $KB/projects/photo-organizer \
-H 'Content-Type: application/json' \
-d '{"name":"Photo Organizer","color":"#d4654a"}'
# 2. 계획 할당 + 현재 본문 전송 + 프로젝트 아래에 배치.
# 첫 PUT은 status=todo로 생성; 이후 PUT은 패치.
BODY=$(jq -Rs . < plans/photo-import.md)
curl -sS -X PUT $KB/plans/photo-import \
-H 'Content-Type: application/json' \
-d "{\"title\":\"Photo Import\",\"project_slug\":\"photo-organizer\",\"body\":$BODY}"
# 3. 기능 브랜치를 생성하고 칸반에 알림.
git checkout -b feat/photo-import
curl -sS -X PUT $KB/plans/photo-import \
-H 'Content-Type: application/json' \
-d '{"git_branch":"feat/photo-import"}'
# 4. 노트와 함께 doing으로 전환. 상태 PUT은 멱등적 — 노트 없이 같은 상태는 no-op; 노트가 있으면 활동 항목을 기록.
curl -sS -X PUT $KB/plans/photo-import/status \
-H 'Content-Type: application/json' \
-d '{"status":"doing","note":"Phase 2 시작"}'
# 5. 진행 중에 노트 남기기 (상태 전환보다 저렴).
curl -sS -X POST $KB/plans/photo-import/notes \
-H 'Content-Type: application/json' \
-d '{"text":"phase 2 완료; 테스트 실행 중"}'
# 6. PR이 열리면 awaiting_merge로 이동.
curl -sS -X PUT $KB/plans/photo-import/status \
-H 'Content-Type: application/json' \
-d '{"status":"awaiting_merge","note":"PR #123 열림"}'
# 7. 병합되면 done으로 전환하고 파일을 보관.
curl -sS -X PUT $KB/plans/photo-import/status \
-H 'Content-Type: application/json' \
-d '{"status":"done","note":"v0.3.0에 병합됨"}'
# 그런 다음 `git mv plans/photo-import.md plans/done/photo-import.md`
계획을 생성하거나 이동했을 때 사람의 UI 링크를 언급하세요 — http://localhost:8000/board (또는 개발 모드에서 :4200).
규칙 및 주의사항
- 상태 열거형은 고정됨:
todo,doing,blocked,awaiting_merge,done,backlog. 새로운 것을 만들지 마세요. - 알 수 없는
project_slug는422 unknown project_slug "X"를 반환 — 할당하기 전에 프로젝트를 생성하세요. 자동 생성 없음. - **
project_slug: ""**은 프로젝트를 지우며,project_id: null과 동일합니다. - 업서트(upsert)는 실제 업서트 —
{}와 함께PUT /plans/:slug는 "부재 시 할당, 존재 시 패치" 호출입니다. 다시 실행해도 중복되지 않습니다; 첫 번째 호출만create활동 항목을 기록합니다. - 같은 상태의 상태 PUT은 no-op입니다. 단,
note를 전달하는 경우는 예외입니다. 이를 활용하세요 — 안전하게 재시도할 수 있습니다. - **활동 로그는 추가 전용(append-only)**이며
$KB/plans/<slug>/activity에서 볼 수 있습니다. 본문에서 서술하는 대신 노트를 사용하여 빵 부스러기(Phase 2 완료; Phase 3 시작)를 남기세요. - 본문은 UI의
/task/<task_id>에서 렌더링되는 마크다운입니다. 표준 마크다운을 사용하세요: 제목, 목록(- [ ]/- [x]포함), 코드 블록, 링크. 표와 인용구도 렌더링됩니다.
사용하지 않아야 할 때
- 일회성 버그 수정, 리팩터링, 문서 변경. 칸반은 계획(plans) — 여러 세션에 걸쳐 있거나 의미 있는 컨텍스트를 전달하는 다단계 이니셔티브를 추적합니다. 단일 커밋 작업은 티켓이 필요하지 않습니다.
- 칸반 저장소 자체가 작업 중인 프로젝트라면, 자체 규칙을
CLAUDE.md에 문서화합니다 — 대신 그것을 읽고 이 파일을 무시하세요. - 상태 확인(health check)이 실패하면 보드가 실행 중이 아닙니다. 시작하려고 하지 말고; 그냥 계속하고 사용자에게 알리세요.