tracker.md — your project's policy file
Every project Pigeon connects to gets a tracker.md file at its repo root. It’s the project’s policy contract — a small Markdown file with YAML frontmatter that tells Pigeon how agents should behave when they’re working on this project specifically.
If the human can’t see it and edit it in the surface where they’d naturally encounter it, the agent shouldn’t trust it. tracker.md is that surface.
What goes in it
Section titled “What goes in it”A tracker.md is a single Markdown file with two parts:
- Frontmatter (YAML) — structured policy: which write tools require an
intent, per-column prompts the agent should respect when a card sits in that column. - Body (Markdown) — your project’s general orientation prompt. The current phase, key constraints, what the agent should know to make good calls.
---schema_version: 1project_slug: my-projectintent_required_on: - moveCard - deleteCardcolumns: In Progress: prompt: | Limit to 2-3 cards. Move here when you start writing code, not when planning. Review: prompt: | Code is written and needs human verification. Don't move to Done without explicit approval in a comment.---
# Project policy for my-project
Current phase: shipping the v2 onboarding flow. Treat anythingoutside that as backlog unless it's blocking the release.
Start every session with `briefMe`. Prefer `source: 'pinned'`work over `source: 'scored'`. End every session with `saveHandoff`(or `/handoff` in Claude Code).Where it lives
Section titled “Where it lives”At the repo root of every connected project — alongside package.json, CLAUDE.md, README.md. Pigeon resolves it from Project.repoPath, which is set when you run scripts/connect.sh from inside the project (or call registerRepo from your agent).
Directoryyour-project/
- tracker.md
- CLAUDE.md
- AGENTS.md
- package.json
Directorysrc/
- …
It’s git-versioned. It rolls back like any other file. It diffs in pull requests. The version your agent sees is exactly the version on the branch you’re working on.
How agents read it
Section titled “How agents read it”Pigeon’s MCP tools call loadTrackerPolicy(projectId) whenever they need policy context. That’s:
briefMe— surfaces the body prompt as part of session startgetCardContext— includes the relevant column prompt when you ask about a specific cardplanCard— feeds both the body and the column prompt into the planning protocol so the plan respects project constraints- Every write tool in
intent_required_on— checks the call has a non-emptyintentand refuses if not
The file is hot-reloaded on every tool call. Edit it, save, and the next agent call sees the change. No restart required.
Writing a good tracker.md
Section titled “Writing a good tracker.md”The best tracker.md files share three properties.
1. Short
Section titled “1. Short”If your file scrolls more than a screen, it’s too long. The body is read in full at session start; long bodies inflate every conversation. Keep it to:
- A one-line statement of the project’s current focus
- Two or three constraints the agent should default to
- Any “rules of the house” specific to this project
If you find yourself writing tutorials or rationale, that belongs in AGENTS.md or docs/. The tracker.md is for runtime decisions.
2. About behavior, not context
Section titled “2. About behavior, not context”tracker.md answers: what should the agent do, and not do, in this project?
It does not answer:
- “How do I install this project?” →
README.md - “What’s the build command?” →
CLAUDE.md - “Why did we choose Postgres?” → architectural decisions (
recordDecision) - “What does this codebase look like?” → the codebase
Crossing those lines makes tracker.md long, stale, and load-bearing for the wrong reasons.
3. Phase-aware
Section titled “3. Phase-aware”Projects move through phases. The constraints that mattered in week 1 are noise in week 8. Update the body when the project does:
# Project policy
Current phase: **post-launch stabilization (week 3 of 4)**.
- Bug fixes only. No feature work without explicit go-ahead in a comment.- All `moveCard` to In Progress requires linking to the GitHub issue.- The reliability dashboard (link) is the source of truth for SLO regressions.A future agent reads that and knows the right defaults without you re-explaining.
Per-column prompts
Section titled “Per-column prompts”The columns.<name>.prompt block lets you teach the agent how each column behaves in your workflow. The prompt is surfaced when the agent reads or writes a card in that column.
columns: In Progress: prompt: WIP limit 2. Anything more is a smell — finish or unstick. Review: prompt: | Don't merge without an approval comment from a human. Auto-moves to Done when the linked PR merges.columns: Investigating: prompt: | Time-box every spike to 2 hours. If you're not making progress at the deadline, write up the dead-end and move to Parking Lot. Spike Done: prompt: | Every card here needs a comment summarizing what we learned. Move to Backlog only after a follow-up card is created.intent_required_on: - moveCardcolumns: {}The minimum viable tracker.md. Just enforces intent on moves, nothing else.
Migration from projectPrompt
Section titled “Migration from projectPrompt”Pigeon v4.x stored project policy as a projectPrompt DB column. v5.0 dropped that column and replaced it with tracker.md.
If you’re upgrading from v4.x:
-
On v4.x, run
briefMe()in any agent session. If_warnings[]mentionsprojectPrompt, you have content that needs migrating. -
For each project with content, call:
runTool('migrateProjectPrompt', { projectId: '<your project id>' })The tool writes a
tracker.mdto the project’srepoPathcontaining whatever was in the column. Idempotent — refuses to overwrite an existingtracker.md. -
Review the new file, edit it for clarity, and commit it to your repo.
-
Then pull v5.0. The column is dropped on
npm run db:push. Anything still in the column when you pull is lost.
The full migration walkthrough lives in docs/archive/MIGRATING-TO-PIGEON.md.
Why this and not a database column?
Section titled “Why this and not a database column?”The v4 model stored project policy as a DB string (Project.projectPrompt). The thinking was “one less file to manage.” In practice it had three problems:
- Not reviewable. Edits happened invisibly, in the web UI or via an MCP tool call. No diff, no PR, no rollback.
- Not versioned with the code. Branch out a feature; the policy didn’t follow. Merge back; the policy might have drifted under you.
- Not visible. A new contributor didn’t know it existed. The agent appeared to have opinions out of nowhere.
tracker.md solves all three by making the policy a normal file in your repo. The agent reads from disk; the human reads the same file; both see the same thing.
The shared-surface principle: if the human can’t see it and correct it where they’d naturally encounter it, the agent shouldn’t trust it.
See also
Section titled “See also”- Plan a card — how
planCarduses yourtracker.mdto inform structured plans - The session loop — where
briefMereads the body prompt from docs/SURFACES.md—tracker.mdvsCLAUDE.mdvsAGENTS.mdcheat sheet