6.2 — Kanban tracker API reference
On this page
6.2 — Kanban tracker API reference
If you've gone through the user guide, you already know the kanban tracker as the live board on the Track tab. Under the hood it's also a fully-scriptable API — every move on the board is one HTTP call, and every MCP tool your IDE agent uses for kanban work calls these endpoints.
This page is the reference for those endpoints: the seven-state lifecycle, the MCP tool signatures, the HTTP API, the audit log shape, the real-time subscription, and the error codes.
If you just want your IDE agent to work through criteria, you don't need any of this — the MCP server handles it. Read this when you're:
- Building a custom UI on top of the kanban data
- Wiring up CI to resolve reviews
- Writing automations that watch the audit log
- Debugging why a transition got rejected
The lifecycle
Every acceptance criterion moves through these seven states:
┌──────────┐ user approves ┌──────────┐ agent claims ┌──────────────┐
│ draft │ ──── (web only) ──▶ │ ready │ ──── (atomic) ──▶ │ in_progress │
└──────────┘ └──────────┘ └──────┬───────┘
▲ │
│ │ agent submits
system auto-reverts after 24h idle │ (with git SHA + diff URL)
│ ▼
│ ┌─────────────┐
└──────────────────────────│ in_review │
└──────┬──────┘
│
ci runner or web user resolves │
┌──────────────────────┐ │
│ passed (terminal) │ ◀──────┤
└──────────────────────┘ │
┌──────────────────────┐ │
│ failed │ ◀──────┤
└──────────┬───────────┘
│ user sends back
▼
┌──────────┐
│ ready │
└──────────┘
any active state → blocked (agent or user) ↔ unblock restores prior state
| State | What it means | Who can move out of it | Move it where |
|---|---|---|---|
draft | AI just generated the AC; not yet vetted by you | You (web) | → ready |
ready | You approved the spec; available for an agent to pick up | Agent (claim) · Auto-revert lands here from in_progress | → in_progress · → blocked |
in_progress | An agent is actively implementing it | Agent (submit / block) · System (auto-revert) | → in_review · → blocked · → ready (system) |
in_review | Implementation done, awaiting verification | CI runner or you (web) | → passed · → failed · → blocked |
passed | Verified — terminal state | — | — |
failed | Verification failed; needs rework | You (web) | → ready |
blocked | Agent (or human) flagged something preventing progress | Agent or you (unblock) | → prior state (whatever it was when blocked) |
Key principle: the agent owns the work-in-progress states (claim, submit_for_review, block) but cannot resolve its own review. Final acceptance is always gated by either a CI result or a human click. Even if an agent calls the resolve endpoint with the right token shape, it gets 403 agents_cannot_self_resolve.
Roles & permissions
| Action | You (web session) | Agent token (agent scope) | CI token (ci_review scope) | System |
|---|---|---|---|---|
approve (draft → ready) | ✅ | ❌ | ❌ | ❌ |
claim (ready → in_progress, atomic) | ❌ | ✅ | ❌ | ❌ |
report_progress (heartbeat) | ❌ | ✅ | ❌ | ❌ |
submit_for_review (in_progress → in_review) | ❌ | ✅ | ❌ | ❌ |
resolve_review (in_review → passed/failed) | ✅ | ❌ | ✅ | ❌ |
block (* → blocked) | ✅ | ✅ | ❌ | ❌ |
unblock (blocked → prior) | ✅ | ✅ | ❌ | ❌ |
auto_revert (in_progress → ready) | ❌ | ❌ | ❌ | ✅ |
list_events (read audit log) | ✅ | ✅ | ✅ | — |
MCP tool reference
Each tool below is exposed by @vibemap.ai/mcp-server and callable from your IDE.
vibemap_get_next_ready_criterion
Find the highest-priority AC in ready state. Use this at session start or after finishing the previous AC.
Input: { projectId: string }
Output: the criterion record (or null if nothing is ready).
{
"criterion": {
"id": "abc-...",
"project_id": "...",
"story_id": "...",
"title": "User can reset password via email",
"description": "...",
"status": "ready",
"created_at": "..."
}
}
vibemap_claim_criterion
Atomically transition an AC from ready → in_progress. Race-safe: two parallel callers will see one succeed and the other receive 409 race.
Input: { criterionId: string }
Output: the new event row.
Errors: 409 race if another agent already claimed it; 422 illegal_transition if the AC isn't in ready.
vibemap_report_progress
Append a progress note to the AC's timeline without changing status.
Input: { criterionId: string, summary: string } (summary 1–2000 chars)
Output: the new event row (from_status === to_status).
vibemap_submit_for_review
Mark the implementation done and request review. Transitions in_progress → in_review. Requires a git SHA and a diff URL as audit evidence.
Input:
| Parameter | Type | Required | Description |
|---|---|---|---|
criterionId | string | ✅ | |
gitSha | string | ✅ | Commit SHA (≥7 chars) where the work landed |
diffUrl | string (URL) | ✅ | PR link or compare URL the reviewer can open |
notes | string | ❌ | Free-text notes (max 2000 chars) |
vibemap_resolve_review (CI / human only)
Resolve a criterion in review — in_review → passed or in_review → failed.
Input:
| Parameter | Type | Required | Description |
|---|---|---|---|
criterionId | string | ✅ | |
outcome | 'passed' | 'failed' | ✅ | |
testRunUrl | string (URL) | ❌ | CI run / report URL |
notes | string | ❌ | Reviewer notes |
Errors: 403 agents_cannot_self_resolve — agents can't self-pass their own work. Use a ci_review-scoped token (CI runners) or have a human click "Pass" on the web.
vibemap_block_criterion
Flag a criterion as blocked. Transitions any active state → blocked and captures the prior status so unblock can restore it.
Input:
| Parameter | Type | Required | Description |
|---|---|---|---|
criterionId | string | ✅ | |
category | enum | ✅ | One of spec_unclear, missing_dep, external_blocker, other |
reason | string | ✅ | Human-readable explanation (1-2000 chars) |
vibemap_unblock_criterion
Restore a blocked criterion to its prior state.
Input: { criterionId: string, resolution: string }
vibemap_list_kanban_events
List the project's transition history, newest first. Use since for incremental fetches.
Input:
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | string | ✅ | |
since | ISO timestamp | ❌ | Only events strictly after this |
limit | number | ❌ | Max events to return (default 200, max 1000) |
HTTP API reference
Every MCP tool is a thin wrapper around an HTTP endpoint. You can call these directly from CI scripts, custom integrations, or curl. All endpoints require Authorization: Bearer <vm_token>.
| Method | Path | Auth scope | What it does |
|---|---|---|---|
| POST | /api/mcp/kanban/criterion/[id]/approve | session-only | draft → ready |
| GET | /api/mcp/kanban/projects/[projectId]/next-ready | agent or ci_review | Returns oldest ready AC |
| POST | /api/mcp/kanban/criterion/[id]/claim | agent | Atomic ready → in_progress |
| POST | /api/mcp/kanban/criterion/[id]/progress | agent | Heartbeat event, no status change |
| POST | /api/mcp/kanban/criterion/[id]/submit-for-review | agent | in_progress → in_review |
| POST | /api/mcp/kanban/criterion/[id]/resolve-review | ci_review or session | in_review → passed/failed |
| POST | /api/mcp/kanban/criterion/[id]/block | agent or session | * → blocked |
| POST | /api/mcp/kanban/criterion/[id]/unblock | agent or session | blocked → prior |
| GET | /api/mcp/kanban/projects/[projectId]/events | agent or ci_review | Audit log with since/limit |
Request/response shape
POST endpoints accept either:
- Bare object:
{ "git_sha": "...", "diff_url": "..." } - Wrapped:
{ "payload": { "git_sha": "...", "diff_url": "..." } }
Success response (status-changing routes):
{
"event": {
"id": "uuid",
"project_id": "...",
"entity_type": "criterion",
"entity_id": "...",
"from_status": "in_progress",
"to_status": "in_review",
"actor_kind": "mcp",
"actor_id": "env_token:agent",
"payload": { "git_sha": "...", "diff_url": "..." },
"created_at": "..."
}
}
Curl examples
# Find the next ready AC
curl https://vibemap.ai/api/mcp/kanban/projects/$PROJECT_ID/next-ready \
-H "Authorization: Bearer $VIBEMAP_API_KEY"
# Claim it
curl -X POST https://vibemap.ai/api/mcp/kanban/criterion/$AC_ID/claim \
-H "Authorization: Bearer $VIBEMAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
# Submit for review with evidence
curl -X POST https://vibemap.ai/api/mcp/kanban/criterion/$AC_ID/submit-for-review \
-H "Authorization: Bearer $VIBEMAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"git_sha":"a1b2c3d","diff_url":"https://github.com/me/proj/pull/42","notes":"green tests"}'
# Block it
curl -X POST https://vibemap.ai/api/mcp/kanban/criterion/$AC_ID/block \
-H "Authorization: Bearer $VIBEMAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"category":"spec_unclear","reason":"AC says \"fast\" — what latency target?"}'
# Replay history (incremental from last seen)
curl "https://vibemap.ai/api/mcp/kanban/projects/$PROJECT_ID/events?since=2026-05-09T00:00:00Z&limit=50" \
-H "Authorization: Bearer $VIBEMAP_API_KEY"
CI integration
Wire your test runner to the resolve-review endpoint with a ci_review-scoped token.
GitHub Actions example
# .github/workflows/resolve-vibemap-review.yml
name: Resolve VibeMap reviews
on:
workflow_run:
workflows: ["Tests"]
types: [completed]
jobs:
resolve:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Map commit SHA to AC IDs
id: map
# Pull AC IDs from your commit message convention, e.g. "feat: ... (AC-abc-123)"
run: |
AC_IDS=$(git log -1 --pretty=%B | grep -oE 'AC-[a-z0-9-]+' | tr '\n' ' ')
echo "ac_ids=$AC_IDS" >> "$GITHUB_OUTPUT"
- name: Resolve as passed (or failed)
env:
VIBEMAP_CI_TOKEN: ${{ secrets.VIBEMAP_CI_TOKEN }}
OUTCOME: ${{ github.event.workflow_run.conclusion == 'success' && 'passed' || 'failed' }}
run: |
for ac in ${{ steps.map.outputs.ac_ids }}; do
curl -X POST "https://vibemap.ai/api/mcp/kanban/criterion/${ac#AC-}/resolve-review" \
-H "Authorization: Bearer $VIBEMAP_CI_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"outcome\":\"$OUTCOME\",\"test_run_url\":\"${{ github.event.workflow_run.html_url }}\"}"
done
Convention for linking commits to ACs
Include the AC short ID in your commit messages (or PR titles) so CI can derive which ACs to resolve:
feat(auth): password reset via email (AC-abc-123)
The agent's submit_for_review call already attaches the git SHA to the AC's audit log; this convention is just for CI to know which AC to update post-test-run.
Audit & event log
Every transition produces an event you can query via the events endpoint above. Event shape:
| Field | Type | What it captures |
|---|---|---|
id | uuid | Primary key |
project_id | uuid | Scope |
entity_type | 'feature' | 'story' | 'criterion' | What kind of thing changed |
entity_id | uuid | The AC (or feature/story) ID |
from_status | text | null | Status before; null only on creation events |
to_status | text | Status after |
actor_kind | 'user' | 'mcp' | 'ci' | 'system' | Who did it |
actor_id | text | User UUID, env_token:agent, env_token:ci, or system:auto-revert |
payload | jsonb | Type-specific evidence (see below) |
created_at | timestamptz | When |
Payload shapes by transition
| Event | Payload contents |
|---|---|
approve | {} |
claim | {} |
progress (no status change) | { summary } |
submit_for_review | { git_sha, diff_url, files_changed?, notes? } |
resolve_review | { outcome, test_run_url?, notes? } |
block | { category, reason, prior_status } |
unblock | { resolution } |
auto_revert (system) | { idle_hours: 24 } |
Real-time subscription (for custom UIs)
The events feed is published in real time. You can subscribe from a browser client to stream transitions as they happen — useful for building your own kanban UI or a status dashboard. Your client only sees events for projects you can access.
Operational behavior
| Background job | Schedule | Effect |
|---|---|---|
| Stuck-claim detector | Hourly | Finds ACs in in_progress with last event >24h old; auto-reverts to ready |
| Long-blocked metric | Daily at 09:00 UTC | Emits an analytics event for ACs in blocked >7 days |
If you'd like the long-blocked metric to also notify Slack/email, wire your own alerting against the events feed — VibeMap doesn't push notifications natively in v1.
Error reference
| Error | When it fires | What to do |
|---|---|---|
agents_cannot_self_resolve | Agent token tried to call resolve_review. | Resolve with a ci_review-scoped token (CI) or a session cookie (human). |
race | CAS claim lost — another caller already moved the AC. | Call get_next_ready_criterion again to find a different one. |
illegal_transition | Target status not legal from current state for this actor. | The response includes a legalNextStates array showing valid moves. |
entity_not_found | Criterion ID doesn't exist (or you don't have access). | Verify the ID; check project membership. |
not_blocked | Tried to unblock an AC not in the blocked state. | Read the current state via list_kanban_events first. |
invalid_payload | Validation failed. | The response's issues array shows which fields failed and why. |
forbidden | Session user not a member of the project. | Add the user to the project, or use a different account. |
unauthenticated / invalid_api_key | Bearer token missing or wrong. | Recheck VIBEMAP_API_KEY env in your IDE config. |
Notes on terminal states
passedis terminal by design. To "reopen", edit the AC's content and approve a new draft, or open a follow-up AC. This intentional friction keeps the audit log trustworthy.submit_for_reviewrequiresgitShaat the schema level. Local-only experiments can pass a placeholder (e.g.local-plus the first 7 chars of a hash). See the local-only scenario in the user guide.
Related docs
- 6.1 — Step-by-step user guide — practical setup + day-to-day workflows + scenarios
- 5.1 — MCP server overview — the broader MCP integration
- 5.2 — Full tools reference — every MCP tool, including non-kanban ones
- 4.1 — API overview — general API conventions