Skip to main content
Glama

feature-tracker-mcp — "oz"

A project-agnostic tracker for the case where one person directs several AI coding sessions at once and has become the bottleneck.

The problem is not "track features." It is: several tracks are in flight, each session is blind to the others, decisions surface constantly, and reading everything is the job. Most of those decisions are mundane and delegable. A few are genuinely yours. Nothing separates them, so you read all of it.

Each project gets its own Postgres instance in a .oz folder — the project owns its tracker outright.

Table of Contents

The model

Goals are objectives, not filing labels. Each carries what is being achieved, what done means, what is deliberately excluded, and what constrains it. A worker reads its goal before starting and declines work that falls inside the non-goals — that is the difference between executing a queue and pursuing an objective.

Features belong to exactly one goal. Ids are allocated atomically (DIP-17, GLG-4) and never change, so anything citing one in a commit message keeps resolving. They carry acceptance criteria, dependencies, and a parity record.

Gates are decisions a session must not take alone — architectural, install, spend, irreversible. Raising one banks the question and moves on; the principal answers a round of them in one sitting.

Parity is tracked across eight dimensions, because work is only done when it is done in all of them: code, unit tests, functional tests, documentation, screens, builds, infrastructure, features.

Studies are investigations whose deliverable is a document and a decision. Pre-registered, and allowed to conclude "do not build this".

Conferrals are the record of Claude working a judgement out with a peer model — ChatGPT, a harder-thinking Claude, DeepSeek. Every goal, feature, study, checkpoint and finished diff requires one, enforced by the tools rather than requested by the docs.

Commands

Driven through the /oz skill.

Working

Command

Does

/oz next [goal]

What can be worked now — not done, nothing it depends on outstanding

/oz blocked [goal]

What is waiting, and on what

/oz task <goal>

Drive a goal's features to done, here

/oz start

Spawn the backlog maintainer and a worker per goal, each in its own worktree

/oz standup

Cross-track state, including uncommitted work per worktree

/oz pause · /oz resume

Broadcast to every worker, including ones not yet running

/oz shutdown · /oz stop

Wind down leaving it resumable: stash every worktree, record where. stop also releases claims

/oz stashes · /oz restore <id>

Work interrupted by a shutdown, and putting it back

/oz workers

Who is alive, how long since each was heard from, what each holds

Shaping the work

Command

Does

/oz refine

Both passes in order — goals, then the features under them. The order matters: criteria written under an unrefined goal are written against nothing

/oz refine goals

Draft and record every unrefined goal in one pass; gate what the docs cannot settle

/oz refine features

Give every open feature acceptance criteria in one pass

/oz goal

Define a new goal — the conversation produces the name

/oz review [id]

Work through a derived checklist a page at a time

/oz gaps · /oz gaps features · /oz gaps goals

Project-wide coverage analysis — what nothing tracks, including goals that should exist. The scoped forms bound what is filed, not what is examined

/oz boundaries

What the project is not

/oz design <goal|feature>

Invention, ending in one checkpoint

/oz study <question>

Investigate; deliverable is a document and a recommendation

/oz add [text]

Record something that would otherwise be lost

/oz link <id> <depends-on>

Record a dependency

Decisions and reporting

Command

Does

/oz watch

Watches, and prompts you with the pending gates as a pickable checklist. The only path from a raised gate to a decision

/oz gates · /oz approve · /oz reject

The gate queue

/oz status · /oz table · /oz history

Counts, items, the append-only record

/oz parity [goal] · /oz scan <dimension>

Coverage, and the cheap probe that populates it

/oz goals · /oz prune

Goals and hygiene

/oz db backup · /oz db backups · /oz db restore

Dump, list, and restore the tracker — take one before any bulk pass

The peer

One reasoner cannot find its own blind spot, and the principal cannot always supply one. When the question is a derivation they would have to take on trust, asking them is not review — it is handing over an unread liability. That is the problem this exists to solve.

A conferral is an exchange, not a verdict. It runs rounds: put the actual draft and reasoning to the peer, settle what it says it lacked, check what it asserts, disagree where you disagree, keep going while it is still converging, stop when circling. How it ends decides who hears about it.

Outcome

Consequence

converged

Recorded. The principal is not involved

converged_after_revision

The peer moved Claude and the change was applied. Recorded with what changed

stalemate · regression · unresolved_context

Promoted to the principal, carrying both positions

Soft gates never reach the principal. architectural and install forks are raised into the loop — gate_raise refuses one with no conferral, because escalating instead of thinking is what made the queue unreadable. spend and irreversible are always the principal's: two models agreeing is not authorisation to spend someone's money or to take an action with no undo.

The peer drafts where it should. Study pre-registration is written by the peer and attacked by Claude, because a method is attacked best by whoever did not write it, and the falsifier is the question a single reasoner is least able to ask itself.

A feature cannot reach done until its diff has been through a peer — checked against the database, not asserted in the same call that closes the work.

Enforcement is mechanical because prose failed. The actor field has accepted the value chat since the first commit and across 76 recorded events has never once held it. A mechanism that recommends conferral is a mechanism that gets skipped.

The framing is kept verbatim. Claude chooses what the peer sees, so agreement can be manufactured with a leading question — and from outside, that is indistinguishable from independent agreement. asked and the peer's own account of what it lacked are what make it distinguishable.

Agents

Agent

Does

oz-worker

One per goal, own worktree. Claims, builds, evidences, releases. Refines its own items and gates only genuine forks

oz-backlog

What a worker structurally cannot: dependencies across goals, cross-goal duplication, staleness

oz-capture

Per turn, cheap model. Records what a turn implied that would otherwise be lost

oz-triage

Dedups; splits what peers can settle from what only the principal can

oz-study

Investigates, writes it up, links what it spawned and killed

No agent may call gate_decide. An agent approving its own gate makes the mechanism theatre.

Install

git clone https://github.com/spe-investigator/feature-tracker-mcp.git
cd feature-tracker-mcp
.\install.ps1

Builds, copies the /oz skill and the agents into ~/.claude, and registers the server. Requires Node 18+ and Docker; the database is created in the project's .oz folder on first use, and Docker is started automatically if it is not running.

Design notes

The database is the state, and the bus. Sessions cannot see each other, so coordination goes through Postgres rather than messages: a message is lost if its recipient is not running, and unauditable afterwards. Messaging is at most a doorbell.

Ids are allocated atomically. Two sessions reading a file, seeing the next free number and both taking it is how duplicate migration numbers happen. A counter incremented inside the inserting transaction makes it impossible.

Claims are leases, not flags. A worker that dies holding a flag blocks its feature forever; a lease expires and the work returns to the pool.

Counts are two numbers, never a ratio. The numerator is what converged; a growing denominator means real work was found. 12/16 → 12/20 reads as 75% → 60% — a drop — when nothing regressed and two genuine issues were named.

Standup reads working trees, not just commits. Measured here: every worktree reported zero commits ahead while two held real uncommitted work — a new crate in one, four untracked files in another. A standup built on git history calls active tracks idle.

Rejection means two things. "Not for this goal" is a routing error and the feature is moved; "not wanted" is a decision about the project. Only the second suppresses re-derivation. Every refusal keeps its rationale, and accumulated they define what the project is not — the difference between "no" and "no, because we decided X".

Drafting is derivable; decisions are not. Refinement is a batch pass over everything, with gates raised only for what the documents cannot settle. A flow that asks a question per item spends attention on the part that needed no input.

Studies are pre-registered. Method, decisive evidence and falsifier are recorded before execution, because a method chosen after seeing the data can be selected for the answer it produces. Revisions are counted rather than silent.

Thresholds are measured, not guessed. Duplicate detection uses trigram similarity at 0.30 — real restatements score 0.45–0.63, unrelated titles under 0.10, and an initial guess of 0.45 let a genuine duplicate through at 0.449.

Backups are verified, not just written. A dump is read back before it is reported as taken — the expected tables must be present and the file non-trivial. pg_dump can exit zero having written almost nothing, and an unverified dump is a file rather than a backup.

The schema has no migrations. All DDL lives in src/db.ts as idempotent statements applied on every connect, so a schema change ships with the code that needs it and lands the moment any session connects. The cost is that nothing records when a change landed, there is no down-migration, and anything destructive — dropping a column, narrowing a type — has no safe expression in this pattern and needs a real migration path first.

An objective is lifted once, not re-derived. Goals carry doc_ref — the file and heading their objective came from — and refined_commit, the tree it was read at. Without the pointer a refine pass has to re-read the whole source document to locate each goal's section, once per goal, and afterwards nothing distinguishes an objective taken from the document from one invented where the document was thin.

Incorporation, not annotation. converged_after_revision requires stating what changed, and the tool refuses the outcome without it. Feedback logged beside an unchanged draft changes nothing and reads as diligence — which is worse than not conferring, because it looks like the mechanism worked.

Derivation is goal-scoped; gap analysis is not. derive_features asks what one objective implies, so it can only find work inside a goal somebody already wrote. Work between two goals, or outside all of them, is invisible to it by construction — and a missed feature inside a goal surfaces the next time anyone reads that goal, while a missing goal never surfaces at all. /oz gaps is the only thing looking from far enough back to find one, and a missing goal is a hard gate because gate_reopen cannot unwind a goal that already has work routed into it.

A gate blocks work, and answering one has to unblock it. gate.blocks was written from the first commit and read by nothing, so a feature whose blocking question was unanswered was still handed out and coded straight past. feature_ready now skips those and reports them rather than hiding them; feature_unblocked is what a resuming worker calls, because answering a gate changes a gate row and nothing else.

What is not built

  • /oz start has never been executed. The spawn line is documented but background spawning is untested here. Try /oz task on one goal first.

  • The interactive flows are unrun. /oz refine, /oz design, /oz study and /oz goal are written and their tools are tested individually; the conversations are not.

  • Parity probes exist for documentation and code only. builds and infrastructure need a real check — a build, an applied migration — and a reference search would only pretend to answer them. screens is switched off.

  • No test suite. The conferral enforcement has 11 passing checks; nothing else does.

  • The conferral loop has never been run for real. The enforcement is tested against fabricated conferrals, which is exactly what it cannot detect. Whether the exchanges actually happen is a property of the sessions, not of this code.

  • The markdown renderer that would regenerate a human-readable tracker from the database does not exist, so a migrated markdown tracker cannot be diffed against the database to prove nothing was lost.