Skip to content

Concepts

If the session loop tells you how Pigeon works day-to-day, this page tells you what the parts are — the pieces of the model and how they relate. Read this when you want to know why a feature exists, not just how to use it.

Coding-agent conversations have a natural expiration. Context windows fill, token costs climb, or you just want a clean slate. The question isn’t whether the conversation ends — it’s what carries across the gap.

Today the answer is usually “you do” — you re-explain what was planned, what’s done, what was decided, what’s stuck. Pigeon’s answer is a structured handoff written at the end of one session and read at the start of the next. No re-explaining. No lost decisions. No “wait, what were we doing?”

The metaphor is in the name: agent A wraps a session with saveHandoff; the homing pigeon flies the message across the gap; agent B catches it at briefMe and starts in-context. Humans trigger the wrap-up with the /handoff slash command — that’s the entry point. saveHandoff is the MCP tool it calls under the hood.

The handoff is a SQLite row. The wire is your local disk, not a network. The next session’s first move is briefMe; what comes back is the previous handoff, a diff of what changed since, the top three work-next candidates, open blockers, recent decisions, and a one-line pulse.

ReaderSeesReads/writes via
YouKanban board in the browser. Drag-and-drop, columns, priorities, checklists, activity, real-time updates over SSE.The web UI at localhost:3100.
Your agentStructured tools over MCP. Cards, columns, comments, handoffs, decisions, dependencies, code links.10 essential tools always-on; 65+ extended tools discoverable via getTools and called via runTool. Context footprint stays small.

The same SQLite file serves both, all the time, with no sync layer between them. If you can see it in the UI, the agent can see it. If the agent writes it, you see it live.

A session is one continuous conversation with a coding agent. It starts when you open a chat, runs until the conversation ends, and produces an output: code changes, decisions, follow-ups, or just understanding.

Pigeon doesn’t define what a session is — your agent does. Claude Code, Codex, Cursor, and Windsurf each scope conversations slightly differently. Pigeon’s job is to make the boundaries between sessions legible: what was done, what’s outstanding, what context the next session needs to pick up cleanly.

The lifecycle Pigeon cares about is not the conversation, it’s the handoff at the end of one session and the brief at the start of the next. Everything else flows from those two events.

sequenceDiagram
	autonumber
	participant S1 as Session 1
	participant T as Pigeon
	participant S2 as Session 2

	S1->>T: briefMe()
	Note over S1,T: Picks up wherever Session 0 left off
	S1->>T: moveCard / updateCard / addComment
	S1->>T: saveHandoff({ summary, nextSteps, blockers })
	T-->>S1: resume prompt for next chat
	Note over T: Handoff persisted to DB
	S2->>T: briefMe()
	T-->>S2: latest handoff + diff since

The arrows that matter are #1 and #5: briefMe at session start, saveHandoff at end (or /handoff if you’re in Claude Code — same call, slash-command alias). Everything in between is your work.

A handoff is the structured artifact that carries context across the gap between sessions. It’s a small JSON object — kept lean on purpose — that captures what the previous session decided you’d want to know.

The shape:

{
agentName: string; // who wrote it (Claude, Codex, etc.)
createdAt: string; // ISO timestamp
summary: string; // one paragraph: what just happened
workingOn: string[]; // active threads — what you'd resume
findings: string[]; // discoveries, surprises, gotchas
nextSteps: string[]; // suggested actions for the next session
blockers: string[]; // anything stuck that needs unblocking
}

Handoffs are written by saveHandoff and read by briefMe. They live in their own Handoff table (Project + Board scoped, append-only, indexed by createdAt) and roll forward — every new handoff becomes the next session’s primer.

The blockers field is special: when a handoff has open blockers, briefMe opens that section first and surfaces it in the pulse line. If a session ended with a question, the next session sees the question.

briefMe is the entry point for every session. It returns about 300–500 tokens — a tiny fraction of a getBoard call — focused on what changed since the last handoff:

  • The latest handoff (verbatim, so the agent reads what its predecessor wrote)
  • A diff since that handoff — cards moved, cards created, new comments, checklist progress
  • Top work — three highest-scored candidates for what to tackle next
  • Active blockers — any open blocker tagged across the board
  • Recent decisionsclaim rows with kind: "decision" from the last 7 days
  • Staleness warnings — anything that’s been sitting too long
  • A pulse line — single sentence summary for the agent’s first message

The token budget is deliberate. briefMe runs at the start of every session; if it’s expensive, you won’t run it. Cheap means you always run it. Always running means context never drops.

The loop:

  1. briefMe — primes the agent with what’s relevant.
  2. Work — agent calls moveCard, updateCard, addComment, planCard, etc., always with intent on writes that need it.
  3. saveHandoff — writes the next handoff, links any new commits, returns a resume prompt. (Type /handoff in Claude Code to invoke it.)
  4. Next session opens with briefMe. Goto 1.

If you only ever follow these four steps, you’ve got the loop right. Everything else in Pigeon is in service of making them cheap, structured, and useful.

Cards are units of work. Columns describe state. Boards group columns under a project. That’s it — same shape as every other kanban tool.

Where Pigeon differs is what cards carry:

  • A description that’s expected to outlive the conversation that created it. Plans, decisions, screenshots, links to the relevant code.
  • An activity feed that records every move, every intent, every comment, in order, by actor. Auditable history.
  • A checklist that the agent can tick off as work progresses, visible to you live.
  • Relationsblocks, blockedBy, relatedTo — that turn the board from a flat list into a graph.
  • A milestone — release horizon, not a date. A card without a milestone is “later.”
  • A stable number#42 stays bound to the same card across sessions and never recycles, even after deletion. Agent references resolve months later.

Priority shows as a colored stripe on each card; tags filter the view; comment and checklist counters surface card depth at a glance. The card detail panel is the single screen where humans and agents converge — description for scope, checklist for sub-state, comments for guidance from the human to the next agent, dependencies for graph structure, activity feed for the audit trail.

The agent reads cards via briefMe summaries and getCardContext deep-dives, writes via updateCard / addComment / moveCard. Same model, two clients (you and the agent), one source of truth.

Every connected project gets a tracker.md at its repo root — a Markdown file with YAML frontmatter that tells Pigeon how agents should behave on this project specifically. Hot-reloaded on every MCP tool call, git-versioned, reviewable in PRs.

---
schema_version: 1
project_slug: my-project
intent_required_on:
- moveCard
- deleteCard
columns:
In Progress:
prompt: |
Limit to 2-3 cards. Move here when you start writing code,
not when planning.
---
# Project policy for my-project
Current phase: shipping the v2 onboarding flow. Treat anything
outside that as backlog unless it's blocking the release.

The rule: if the human can’t see and edit it where they’d naturally encounter it, the agent shouldn’t trust it. Full guide: Write a tracker.md.

Pigeon distinguishes three kinds of project file at the repo root:

  • tracker.md — runtime board policy. Read by Pigeon’s MCP tools on every call. Hot-reloaded. See the tracker.md page.
  • CLAUDE.md — Claude Code’s session-start prompt. Read once per Claude Code session. Build commands, code conventions, repo-specific instructions.
  • AGENTS.md — cross-agent contributor reference. Read on demand. Tool migration history, tag conventions, “when to use the board” prose.

The principle: if the human can’t see and edit it where they’d naturally encounter it, the agent shouldn’t trust it. Each surface answers a different question; none should bleed into the others.

Pigeon’s MCP server registers under the key pigeon and runs over stdio. Ten essential tools are always-on (briefMe, saveHandoff, createCard, updateCard, moveCard, addComment, registerRepo, checkOnboarding, getTools, runTool). The remaining 65+ tools — cards, checklist, context, decisions, diagnostics, discovery, git, milestones, notes, relations, sessions, setup, tags — are discoverable via getTools and executable via runTool. The full reference, with parameter schemas: MCP tools.

In the web app, press ? anywhere to open the same catalog with deep links to docs.

Pigeon’s versioning policy is conservative on purpose: every breaking change ships with a release note, a npm run doctor check, and (where practical) a non-destructive upgrade path. The history of past cutovers:

WhenWhat happened
v5.x (completed)Dual-bin period — mcpServers.project-tracker + scripts/mcp-start.sh ran alongside the new mcpServers.pigeon + scripts/pigeon-start.sh. Legacy paths emitted a _brandDeprecation warning. The renamed wrap-up tool saveHandoff (formerly endSession) shipped in v5.2 with the old name still resolving via alias.
v6.0 (completed)The cutover. Legacy aliases removed: mcpServers.project-tracker and scripts/mcp-start.sh no longer resolve; endSession no longer aliases to saveHandoff. Note + Claim primitives replaced the legacy session_handoff table — handoffs now live in their own Handoff table.
v6.1 (today)Per-project Costs page, upgrade-comms pipeline (server-status pill, briefMe._upgrade signal, post-upgrade “what’s new” panel), connect.sh slash-command + Stop-hook installer, and the doctor-after-upgrade pass that surfaces failures via briefMe._upgradeReport.
PermanentThe tracker.db filename, the tracker.md filename, the stable MCP tool names (briefMe, saveHandoff, createCard, updateCard, moveCard, addComment, getTools, runTool), Prisma table names, and the tracker:// URI scheme. None of these change.

npm run doctor runs eight checks against your install and tells you exactly what’s drifted. Run it after install, after every git pull, and after npm run service:update. Exit code is 0 on green, 1 on any failure — CI-friendly. Full semver + schema-version policy lives in docs/VERSIONING.md.

Three deliberate calls baked in:

  • SQLite on disk. No accounts, no sync server, no tenancy. One file, owned by you. The agent reads and writes it via MCP over stdio.
  • MCP-native. Pigeon doesn’t ship a custom UI for your agent to call. Any MCP-aware agent works — Claude Code, Codex, Cursor, Windsurf, and whatever ships next.
  • Essential + catalog split. The 10 always-on tools are tiny (briefMe, saveHandoff, createCard, updateCard, moveCard, addComment, registerRepo, checkOnboarding, getTools, runTool). The other 65+ tools are discoverable via getTools and called via runTool. Your agent’s system prompt stays small.

The trade is real: no cloud sync (you sync the file via Git, Syncthing, Dropbox), no team mode (one human + N agents, by design), no network access when the file’s on a machine you’re not on. Read the design rationale for the full picture.

briefMe at session start (catch up), do the work, saveHandoff at session end (leave a trail) — repeat across sessions and the context never resets.