@mychiefmind/ai-maestro

How AI Maestro works

AI Maestro conducts a roster of AI coding agents against a work board. You describe the project once and keep a board of tickets; the orchestrator picks the next unblocked ticket, runs it through a pipeline of specialised agents in an isolated git worktree, gates it, and lands it.

The idea

The board is the source of truth, not the chat

A conversation is lost on the next context reset. A board is not. Work lives in board/data.json, so a run can be interrupted, resumed, handed to a different model, or split across parallel sessions without losing where things stand. Every ticket carries the information needed to execute it — which agents touch it, on which model tier, and what must be true before it can start.

You maintain two files

config.json (roster, skills, areas, model policy) and context.md (the brief every agent reads). Plus the board itself.

Everything else is generated

Claude's .claude//CLAUDE.md and Codex's .agents//.codex//AGENTS.md are rendered from those files plus the kit. Never hand-edit them — change the source and re-render.

How a ticket runs

Plan once, then one ticket per run

SELECTorchestratorPicks the next ticket whose dependencies are all done and which carries no human gate.
PLANpePrincipal engineer turns the ticket into an implementation plan.
BUILDbackend / frontend / …The implementer works in an isolated worktree and writes the tests that prove the change.
GATEqa → pdIndependent review against the acceptance criteria, then the delivery gate.
LANDmergeMerge, record evidence, move the ticket to archive.json, remove the worktree.

A ticket names its own pipeline in agent_plan, e.g. ["pe","backend","qa","merge"]. You cannot skip review by omission: whatever you write, qa and merge are always appended if absent, and pd is added automatically when the ticket is multi-agent or carries a human_gate.

The board is never hand-edited

Every write goes through maestro ticket — locked, validated, atomic. add files one ticket; import lands a whole planned board in a single write and only ever adds, so it cannot overwrite work already there. retrace fixes a ticket the scope gate refused; drop retires one that will never be done, recording why.

How the levels nest

Project plan   the boundary — nothing outside it may run
└── Initiative an independently valuable outcome, several epics — OPTIONAL
    └── Epic   a demonstrable delivery outcome, made of tickets
        └── Ticket  the executable, independently verifiable unit

Initiatives are optional, and most projects should not use them. Reach for them only when a project holds several outcomes that are each independently worth shipping and each need multiple epics. Then each initiative owns its own slice of the plan's requirements; anything that applies to all of them stays project-wide. An epic belongs to one initiative and a ticket derives its initiative through its epic — never storing one of its own. A project that defines none behaves exactly as it did before the layer existed.

Two commands do almost everything

/project-plan writes the project plan, then turns it into epics and dependency-ordered tickets, stopping for your review at each step. /orchestrator runs one ticket — and refuses any ticket the plan doesn't cover. That is the loop. /plan-update fills the plan in later, section by section.

Layout

What you own, and what is generated

my-app/
  src/ …                        your application code — never touched
  maestro/                      the kit + your settings
    config.json                 roster, skills, areas, model policy
    context.md                  the brief every agent reads
    board/
      data.json                 live epics + tickets
      archive.json              completed tickets + evidence
      specs/<id>.md             long-form spec for a ticket
      reports/                  generated reports, shown in the web dashboard
    custom/                     YOUR agents & skills — never touched by an update
      agents/*.md
      skills/<name>/SKILL.md
    agents/ skills/ render/ …   kit files — replaced wholesale on update
  .claude/ + CLAUDE.md          GENERATED — Claude agents, skills & guidance
  .agents/ + .codex/ + AGENTS.md GENERATED — Codex skills, subagents & guidance
  .maestro.lock                 content hashes of everything generated

The lock file is what makes the renderer safe: it records exactly which files this tool produced, so it only ever removes its own. Unmanaged runtime files are either adopted into custom/ or left alone — never silently overwritten.

The board

Anatomy of a ticket

FieldWhat it drives
id requiredUnique across data.json and archive.json.
status requiredbacklog → todo → in-progress → review → done, plus blocked.
epicIdGroups the ticket under an epic.
descThe short source of truth. Anything longer belongs in board/specs/<id>.md.
areabackend / frontend / infra / docs… Selects the area's model floor and test command.
depends_onThe ticket is eligible only when every id listed is done.
agent_planThe ordered pipeline of agent codes. Terminal gates are appended if absent.
modelhaiku / sonnet / opus. The run uses the stronger of this and the area floor; Codex maps them to low / medium / high reasoning effort.
execution_modemulti-agent runs the full gated pipeline; single-agent a lighter path.
human_gateWhen set, the orchestrator never auto-picks it — a person must clear it first.
testCmdOverrides the area's default test command for this ticket only.
evidenceRecorded when the ticket lands: commit SHA, test output, what was verified.

Check the board's integrity any time with maestro validate. It verifies the schema, the dependency graph, agent codes against the roster, status consistency, and id uniqueness across both files.

The roster

Agents

Each agent is one role with one handoff contract. agent_plan routes by the short code, which is not always the filename — that mapping is the one thing worth memorising.

CodeFileRole
orchestratororchestrator.mdRuns the loop: reads the board, picks the next unblocked ticket, dispatches, gates, lands or files a blocker.
peprincipal-engineer.mdThe planning agent. Turns a ticket into an implementation plan.
backendbackend-developer.mdServer-side, data-layer and API work, in an isolated worktree.
frontendfrontend-developer.mdUI and client work.
pipelinepipeline-developer.mdData-pipeline jobs, extraction schemas, scoring, migrations. Holds the idempotency invariant.
devopsdevops.mdInfrastructure, CI, build and release tooling.
docstechnical-writer.mdUser-facing documentation: guides, READMEs, references, runbooks.
qaqa.mdIndependent review gate. Returns a pass or a specific list of defects — never rubber-stamps.
pdprincipal-delivery.mdFinal delivery gate before a change lands.
repo-auditrepo-audit.mdAudits one repo per run and writes a graded Security / Gaps / Improvements report. Not a pipeline stage.

The code is board data

Renaming an agent changes how every ticket routes. If a plan names a code with no agent behind it, maestro validate rejects the board rather than letting the run fail mid-dispatch.

The toolkit

Skills

Skills are procedures an agent (or you) invokes by name — several are also slash commands in your coding tool. Agents are who; skills are how.

SkillWhat it does
project-planWrites the project plan from a brief (goal, scope, deliverables, use cases, functional and non-functional requirements), then turns it into 3–6 epics and 5–15 dependency-ordered tickets that each trace to a plan item. Stops for review at each step.
release-gate (invariants)Runs the enforce command of every plan item the ticket traces to. A non-zero exit is a hard no-go — the difference between a rule agents are asked to honour and one they cannot violate.
plan-updateFills in the project plan section by section as a conversation, and triages the gaps other skills raised. Raises the plan's completeness percentage.
orchestratorStarts a board run: pre-flights the board and working tree, then hands off to the orchestrator agent.
board-validateChecks the board for structural and logical integrity.
delivery-hygieneKeeps the board small, clear, and close to the real delivery shape.
release-gateThe gate a ticket must pass to land. Fails closed — a red or placeholder gate blocks.
security-reviewA focused security pass over a change, with concrete findings at file:line.
test-coverageConfirms the change is actually covered; blocks on untested critical paths.
frontend-qualityBuild + lint always; Lighthouse, accessibility and bundle budgets when the project declares them.
pipeline-qualityPipeline tests, stage idempotency, extraction fixtures, schema coverage, migration safety.
git-branchBranch conventions for ticket work.
worktree-cleanupCreates and tears down per-ticket worktrees so parallel work never collides.
land-and-archiveMerge, record evidence, move the ticket to the archive, clean up.
gcGit catch-up — sync a stale checkout before trusting what it says.
dev-setupBootstraps a repo for local development from a clean checkout.
dev-reportRead-only status snapshot across repos and worktrees, correlated against the board.
orchestration-healthDiagnoses a stuck run: phantom in-progress tickets, orphaned worktrees, unknown codes.
repo-auditAudits one repo and writes a graded report under the board.

Making it yours

Three ways to customise — and what each costs

Everything of your own lives in maestro/custom/. It is not a kit folder, so an update cannot reach it. What differs between the three options is what happens to your work the next time the kit improves.

Add your own

custom/agents/my-agent.md

A name the kit doesn't ship. Renders alongside the kit roster, is never filtered by roster, and nothing can collide with it. No cost.

Extend a kit agent

custom/agents/qa.overlay.md

Appended to the kit's agent under a ## Project overlay heading. The kit's half keeps updating; your half is never touched. No cost — prefer this.

Replace a kit agent

custom/agents/qa.md

Your file wins entirely. Right when you genuinely want a different agent — but this project then stops receiving kit improvements to that name. Cost: a permanent fork.

sync reports these separately — N added, N replacing a kit agent, N extended — and warns on each replacement, because a replacement is invisible in the output afterwards: it looks exactly like a kit agent.

Already using Claude Code or Codex before installing?

Your existing .claude/agents and .claude/skills are adopted, not overwritten. On the first render they move into maestro/custom/, which both preserves them and keeps them the thing that renders — so your setup behaves after the install exactly as it did before. Your own CLAUDE.md is kept in place untouched. Existing unmanaged Codex files under .agents/skills and .codex/agents are likewise preserved in place.

Lifecycle

Install, render, update

# set up in your repo — asks a short questionnaire and renders Claude + Codex targets
npx @mychiefmind/ai-maestro setup

# re-render after editing config.json or context.md (from the maestro/ folder)
npm run sync

# bring the kit up to date; your config, context, board and custom/ are kept
npx @mychiefmind/ai-maestro@latest update

# check the board
maestro validate

# change the board — locked, validated, atomic. Never edit data.json by hand.
maestro ticket set-status T-010 in-progress
maestro ticket archive   T-010 --evidence "merged abc123: suite green"

Why a command and not an editor: reading data.json, changing a ticket and writing the file back destroys any change another writer made in between — silently, with no conflict and no error, leaving valid JSON that passes validation. maestro ticket applies the change to the file as it is at write time, under a lock. Exit 2 means someone beat you to it: run the same command again.

What an update touches: only the kit's own folders. Anything of yours it finds among them — an agent you added, or a kit file you hand-edited — is moved into custom/ and named in the output before anything is replaced. Nothing is ever deleted.

Keeping generated files honest

sync --check exits non-zero if committed generated runtime files no longer matches what would be rendered. Useful in a pre-commit hook or CI so generated files can't go stale.

Scale

Many repos, and groups of repos

A registry lists the projects that cross-project commands operate on. It replaces "the repos that happen to sit in the same parent folder" with an explicit list — and it is the allowlist: a tool may only touch a project named in it.

// maestro-registry.json
{ "projects": [
  { "name": "my-app",   "path": "~/code/my-app" },
  { "name": "platform", "path": "~/code/platform", "kind": "ops" },
  { "name": "old-tool", "path": "~/code/old-tool", "status": "parked" },
  { "registry": "./labs/maestro-registry.json" }        ← a group of groups
] }
  • status: parked keeps a repo on the list but out of every sweep — use it instead of deleting the entry, so "deliberately not being worked" stays recorded.
  • kind: ops marks portfolio tooling that has no delivery pipeline of its own.
  • An entry with registry includes another registry, resolved relative to the file naming it. Names must be unique across the whole tree; cycles are reported with the chain that formed them.
maestro drift  --registry maestro-registry.json        version + hand-edit report per project
maestro update --all --registry maestro-registry.json  update every project (--dry-run to preview)
node maestro/render/sync.mjs --all --registry maestro-registry.json --check

Each project runs in its own subprocess, so one broken project reports and the batch continues. A repo that hasn't adopted the kit is skipped, not counted as a failure.

When something looks wrong

Troubleshooting

SymptomCause & fix
Orchestrator reports idleNo ticket is eligible: every todo ticket has an unmet depends_on or a human_gate. Run maestro validate — it prints the eligible count.
A ticket routes nowhereIts agent_plan names a code with no agent behind it. Check the code table above — the code is not always the filename.
My agent isn't renderingIf it's a kit agent, add it to roster in config.json. Your own agents in custom/ are never roster-filtered and always render.
An edit to a generated runtime folder disappearedPut the change in maestro/custom/ — as an .overlay.md if you only wanted to add rules — and re-render.
sync --check reports driftA generated file was edited, or config.json/context.md changed without re-rendering. Run sync without --check.
An agent stopped improving with the kitYou have a full replacement for it in custom/. sync names these under "replacing a kit agent". Convert it to an .overlay.md to get updates back.
A stuck or suspicious runUse the orchestration-health skill — it finds phantom in-progress tickets, orphaned worktrees and unresolved dependencies.