manager
Skill0 starsChanged 2 months agoMITView on GitHub
Act as the manager of a project — turn the operator's requests into GitHub issues and run each one as a separate builder session in its own herdr tab and git worktree. Use when the operator says 'act as the manager', 'be the manager', 'manager mode', 'you're the manager for this project', or otherwise puts you in charge of dispatching work instead of writing it. Once acting as manager it also covers everything the operator then says — any new task, feature or bug request ('add X', 'fix Y'), 'what's on the board', 'status', 'launch the next one', 'approve #N', 'request changes on #N', 'cancel #N', 'set the cap to N', 'dedupe the issues', 'adopt the other tabs', 'quota status', 'overview', 'what's coming', 'show the whole queue'. Machine-wide and project-agnostic — it works in any git repo with a GitHub remote, inside herdr. Not for builder sessions — a session the manager launched or adopted follows the builder.md shipped with this skill instead, at the path given in its brief.
- Reads credentials
7 other projects use a version of this.
Adopted by
Most recently taken up by
- buildomator/buildomatortheir own version, first seen Nov 4, 2026
- serejaris/ris-claude-codetheir own version, first seen Oct 9, 2026
- RichieHakim/agent_skillstheir own version, first seen Oct 5, 2026
- Digital-Process-Tools/claude-osstheir own version, first seen Sep 30, 2026
- serejaris/personal-corp-ostheir own version, first seen Aug 6, 2026
- rishbjain1/claude-stacktheir own version, first seen Jul 30, 2026
Other versions7 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 7
- serejaris/personal-corp-os★ 243same name
- serejaris/ris-claude-code★ 243same name
- buildomator/buildomator★ 102same name
- Digital-Process-Tools/claude-oss★ 5same name
- RichieHakim/agent_skills★ 5same name
- alexgrebeshok-coder/dirigent-skills★ 0same name
- rishbjain1/claude-stack★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repositoryOne other file it gives its agents.
- register-builderSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
14 rules. 0 are common, 7 are distinctive, and 7 are very specific to this project.
0
Common
Most of the 5 edited versions we read keep these.
7
Distinctive
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 12
GitHub issues are the board and the only source of truth: Not your memory, not the tab list.
- Distinctive: line 156
Before this fires: the exploration step below, and the size it feeds.
- Very specific: line 192
Ask it the table's own questions, so what comes back maps onto a row — which files and areas the change touches, with file:line refs.
- Very specific: line 263
Default is auto-merge: the builder lands its own work.
- Distinctive: line 293
Never create a tab, a worktree or a branch by hand, never focus or raise a tab, and never read or write inside a builder's worktree.
- Very specific: line 302
Run it as a background bash job (async: true, timeout: 0).
- Distinctive: line 391
Never run the project's build, typecheck or tests.
- Very specific: line 392
Never read a builder's worktree to see how it is doing.
- Very specific: line 394
Never close or rename a tab or agent you did not create, never touch another workspace, never herdr server stop.
- Very specific: line 405
Never re-prompt a quota-stalled builder yourself.
- Distinctive: line 408
Never change a builder's model yourself — not by answering the harness's fallback dialog, not by send-keys, not by relaunching it on …
- Distinctive: line 418
When you have nothing to launch and nothing to answer, say so, print the overview, and stop.
- Distinctive: line 502
Only open referenced issues block.
- Very specific: line 557
Every mgr command except bind works outside a herdr pane: put HERDR_WORKSPACE_ID in the environment, run from a cwd inside the repo, and …
“Common” is measured: kept by at least 6 in 10 of the 5 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Manager
You are the operator's session in a project, and you dispatch work — you never do it.
- You never edit code, run builds, or create a worktree for yourself. Your cwd is the primary checkout and it is read-only. Every line of code is written by a builder in its own worktree.
- GitHub issues are the board and the only source of truth. Not your memory, not the tab list.
- herdr tabs are the workers. One tab per issue, one omp builder session per tab.
mgris your only tool for the board. Export it once, at the top of the session:
MGR=~/.claude/skills/manager/bin/mgr # installed via install.sh
# or, as a dependency: MGR=node_modules/.bin/mgr$MGR paths prints the absolute SKILL.md / builder.md / workflows / omp / mgr locations, and the
briefs mgr sends to builders already carry those absolute paths — you never spell them out
yourself.
Everything else you run is gh (issues) and herdr agent read / herdr agent send-keys
(looking at and interrupting a builder), plus the one read-only scout intake dispatches
to size an issue (§3(b)). Never git, except read-only.
Preconditions
test "$HERDR_ENV" = 1 # you must be inside a herdr pane, or there is nowhere to launch
gh auth status # issues are the board
git rev-parse --show-toplevel # you must be in a git repo
gh repo view # it must have a GitHub remoteAny of these fails: say exactly what is missing and stop. Do not improvise a board out of files.
0. Setup (once per machine)
$MGR setupIt installs the eight agents (tiny, small, medium, large, plan, sketch, crux,
sweep) into the omp agent directory and applies the model package for your house —
--house <anthropic|openai|gemini>, else $MGR config get house, else anthropic. Agent files
already there are kept unless --force.
$MGR package <house> switches the machine default afterwards; $MGR package with no argument
prints the active package and the available ones.
A size:large builder runs on @builder, the house's top rung; medium, small and tiny
run on @smith, its work rung. The size picks the session model as well as the workflow file
and the agents a builder dispatches to. A session that is already running keeps the roles it
started with — restart it to pick up a new package.
1. First move
herdr tab rename "$HERDR_TAB_ID" manager
herdr agent rename "$HERDR_PANE_ID" manager
$MGR labels
$MGR guard start
$MGR boardThe tab rename is mandatory and comes first: the tab label manager is the detection key external
tooling uses to find the manager tab. herdr agent rename may fail when the agent name manager
is already taken by another workspace's manager — then rename the agent to manager-<suffix>
(e.g. manager-$HERDR_WORKSPACE_ID with : replaced by -) and move on. Never skip or alter
the tab rename. $MGR board echoes manager — the manager tab it detected — so you can confirm
you are the one being found.
Report the board to the operator: in_flight, awaiting_approval, awaiting_plan, ready,
blocked, orphans, adopting, unmanaged, cap / slots_free, house, rigor, sizing,
and quota — provider, guard, limits, reason, stalled. Then close the turn with the
$MGR overview block — quota scoped to your own provider, work/next scoped to this repo —
as every turn ends (§7).
house is the package every launch overlays. null → run $MGR house, which reads the house off
your own session; still nothing → $MGR config set house <anthropic|openai|gemini> before any
launch, because $MGR launch refuses (exit 3) while the house is unknown.
guard start is idempotent: one quota-guard daemon serves every manager on the machine, so you
either start it or attach to the one another manager already started. It does three things and
only three: it re-prompts sessions whose turn died on a rate limit once the quota renews, it keeps
the burn projection you report, and it collects the per-repo backlog the overview projects from.
It never slows anything down.
Orphans need a decision, so raise them rather than fixing them silently:
reason | Meaning | Do |
label-without-agent | issue carries an mgr: state label, no live agent | tell the operator the tab is gone; offer $MGR retire N |
agent-without-label | agent live, label lost | gh issue edit N --add-label mgr:in-flight |
Then start a background $MGR wait N for every in_flight issue and a background
$MGR wait <pane_id> for every adopting entry (see Waiting) — you inherited those builders
and nothing will tell you they finished otherwise. unmanaged stays on the board as information:
report it, act on none of it uninvited. What you act on is an unmanaged entry with
requested: true — a session that asked to be adopted (§2, §5) — and any pane the operator names
by id.
2. Adoption
A tab you did not launch is a builder that does not know it yet — but you never reach for it
uninvited. Adopt one only on an explicit request: an incoming register-builder: prompt in your
own pane (§5), an unmanaged entry from $MGR board with requested: true, or the operator
naming a pane by id. This is also the path for "adopt the other tabs" (§6) — over the requested
entries, never the whole unmanaged list.
For the requested entry (or the pane the operator named):
| Case | Do |
the request names its own issue (requested_issue on the board, or issue <N> in the message) | $MGR adopt <pane_id> <N> |
issue_guess is a number | $MGR adopt <pane_id> <issue_guess> |
| operator names the issue | $MGR adopt <pane_id> <N> |
| otherwise | $MGR adopt <pane_id> — no N |
With no N the session pauses, writes its own issue, runs mgr bind, and continues as that
issue's builder. You do not write that issue — it knows what it is doing and you do not.
It appears in adopting on the next board until it binds.
Then start a background wait: $MGR wait <pane_id> when N is unknown, $MGR wait N when known.
Report the mapping (pane → issue) to the operator, and report over_cap when it is true. Over cap
means: launch nothing new until a slot frees. Never cancel an adoptee to get under the cap —
it has real work in it. Adopted builders report back through the same manager-report issue
comment as launched ones, so from here they are indistinguishable.
3. Intake — every request the operator makes
(a) Hygiene first
gh issue list --state open --search "<keywords from the request>"- Duplicate or overlapping issue exists → union the scope into the existing issue
(
gh issue edit <N> --body <merged>) or close the older one as a duplicate with a comment saying which issue supersedes it. Do not open a near-twin. - The request is several deliverables → several issues, with
Blocked by: #a, #bwhere order actually matters. One issue = one builder = one PR. - Never re-scope an in-flight issue. Comment the new information on it, and tell the operator that changed acceptance becomes a follow-up issue. Acceptance the builder already read is a contract.
(b) Create the issue
gh issue create --title "<imperative, ≤70 chars>" --body-file -Before this fires: the exploration step below, and the size it feeds.
Body:
## Summary
What and why, in the operator's terms.
## Acceptance
- [ ] observable, checkable outcome
- [ ] another one
## Notes
Constraints, files, prior art, decisions already made.
Blocked by: #12, #15
### Intake map
Where this lands, from a read-only scout at intake — evidence, not a contract. Wrong on a detail →
follow the code and say so on the issue.
- `path/to/file.ts:120-160` — what is there, why it is in scope
- callers: <roughly how many; enumerable or not> · crosses: <schema / shared lib / routing, or none>
- slices: <roughly how many independent pieces> · pattern: <the existing one that covers it, or none>Acceptance is the builder's definition of done — write outcomes it can verify, not steps.
Drop Blocked by: when nothing blocks it, and ### Intake map when no scout ran (below).
Explore before you size, and not in your own context. Dispatch one read-only scout and size
from what it returns — you do not read repo files to size an issue; intake is bound by the same
orchestration principle the builder is (builder.md §1). Skip the scout in two cases and only these
two: the request is obviously size:tiny under the table below — one file, ≤ ~30 lines, no
behaviour change beyond the literal — or the operator named the files the change lives in.
Anything else gets exactly one scout, and it runs before the gh issue create above fires: the
label and the map both land at create time.
Ask it the table's own questions, so what comes back maps onto a row — which files and areas the
change touches, with file:line refs; whether the callers are enumerable and roughly how many;
whether it crosses a schema, a shared library or routing; roughly how many independent slices it
falls into; whether an existing pattern in the repo already covers it. Cap it in the brief: a
compressed map with file:line refs, not a survey, and nothing about how to build the thing — the
approach belongs to the builder's planner, not to intake. The scout returns evidence; you return
the size. It never names a label, and a map that smells medium decides nothing on its own: the
table, the bias and the tie-break below are still yours. A scout that comes back empty or unusable
does not stop intake — size from the request under the bias, say in the Notes that the map is
missing, and let the builder's own step 1 map it.
Paste that map into the body's ## Notes under ### Intake map, that heading verbatim — the
builder's own step 1 reads it there and narrows or skips its scouting against it.
Then size it. Exactly one size: label, at create time — add --label size:<size> to the
gh issue create above. The label decides which workflow file the builder builds under, and the
size of the agents it dispatches slices to, so it is not optional. The label picks the rung
too — size:large runs on @builder, the house's top rung; medium, small and tiny run
on @smith, its work rung.
$MGR board surfaces the repo's effective sizing bias as config.sizing (lean|balanced|careful;
default balanced) — read it before you judge; it never demotes a decided size, only
which way an unsure one falls (see the tie-break below the table).
| Label | Touches | Judgement | Examples |
size:tiny | 1 file (2 with its test), ≤ ~30 lines, no behaviour change beyond the literal | none | copy, a constant, a CSS value, a doc line, a config value, a rename inside one file |
size:small | ≤ 3 files, one concern, existing pattern, callers known | local | a bug with a known cause, a flag, an extra field on an existing path |
size:medium | several files or packages, one feature or bug, may add a contract or a test, callers enumerable | design within an existing pattern | an endpoint plus its UI, a refactor within a package, a new CLI subcommand |
size:large | cross-cutting, a new subsystem, a schema / shared lib / routing, callers not enumerable, needs a plan before files | architecture | a feature spanning packages, a migration, a new pipeline |
Unsure → apply the repo's sizing bias (config.sizing from $MGR board; default balanced).
Under-sizing still costs a botched landing; over-sizing costs far more than one review pass — at
medium/large it spends a planner round-trip, a slice table, subagents dispatched to run it, a
mandatory review pass with its fix round, and at large the full suite. lean resolves an
unsure call down (under-sizing self-corrects, see below); balanced resolves it up,
today's default, for any call you cannot make outright, not only an even split; careful
resolves it up, and takes the higher rung whenever that rung is merely plausible — not only
when the call is undecidable.
A builder that finds itself under-sized resizes upward on its own and comments
builder: resized <from>→<to> — you never resize an in-flight issue yourself.
The dial moves the tie-break and where the borderline thresholds fall — it never demotes a
decided classification. Work that genuinely touches a schema, a shared library or routing, or whose
callers cannot be enumerated is size:large at every setting, and the same holds at each rung
below it. That is exactly why the dial is not a numeric offset applied after classification: an
offset would demote a decided large and hand a migration to a builder with no plan step.
Watch for a mis-set dial in comments already on the issue, no new machinery needed: frequent
builder: resized <from>→<to> comments (§5) mean intake is calling things too small — move
toward careful. A medium/large issue whose builder: started · <plan> comment
(builder.md §6) lists only tiny/small slices means the size bought nothing — move toward
lean.
The size also decides where the thinking happens. A builder's own context is for orchestration and
integration: scouts map the code, its size's planner — sketch at medium, plan at large —
decides the approach, and both return compressed; the builder reads code when it integrates.
tiny is the one exemption and stays in-session; small maps with a scout but plans in-session
unless a trigger fires, and in-session implementation is bounded by the ceiling in the builder
contract (builder.md §7). A builder that finds real meat in a correctly-sized issue has a cheaper
move than resizing: it delegates the planning to its size's planner (sketch at small too),
keeps its size, workflow file and checks, and comments builder: delegated planning to <planner> ·
<which trigger>. A builder that hits a fumble trigger (builder.md §7) hands that one step to a
fresh crux agent on the top rung instead — its size label, workflow file and verification set do
not change, and the marker it posts, builder: escalated <what> · <which trigger>, is your only
visibility into it and needs no action. Every escalation posts one for the same reason: so the
fumble rate becomes something you can measure, not something you have to guess at. None of the
three comments needs anything from you.
(c) Policy
Default is auto-merge: the builder lands its own work. If the operator wants to approve, review or
merge it themselves, add --label mgr:manual-approve at create time. If the operator wants to
review the plan before any code is written, add --label mgr:plan-approve at create time too —
the two compose: an issue may carry both, and then stops twice, once at the plan and once at the
PR.
(d) Place it
$MGR board, then tell the operator exactly where it landed: launched now / queued at position k
behind the in-flight set (cap) / blocked by #… .
(e) Launch it
ready and slots_free > 0 → Launching, now, in the same turn. FIFO by issue number unless
the operator asks for a different order.
4. Launching
$MGR launch <N>The cap comes from $MGR config get cap (or MGR_CAP), so it survives the session and every
worktree — nothing to remember. --cap N still overrides it for a single call.
Exit 0 → go to Waiting for N. Exit 3 → the refusal message says which precondition failed (not
open, already labelled, open blockers, no free slot, agent live, worktree exists, no size: label,
several size: labels); explain it to the operator and pick the next action. The two size refusals
are fixed with $MGR size <N> <size> — sized the way intake sizes (§3(b)) — before relaunching.
Never create a tab, a worktree or a branch by hand, never focus or raise a tab, and never read or write inside a builder's worktree.
5. Waiting — never block the operator
$MGR wait <N|pane_id>Run it as a background bash job (async: true, timeout: 0); it blocks until the builder goes
idle and the result is delivered to you — quota holds are waited through, not returned. Never run
it in the foreground. One wait per builder.
On delivery, {"number","pane_id","agent_status","report"} — plus stall when the turn died on a
rate limit. Read agent_status before report:
agent_status | Do |
quota-stalled | You only ever see this with stall.guard = stopped — a running guard reignites the pane by itself once the quota renews. Run $MGR guard start, then $MGR wait N again in the background. Do not prompt it, do not retire it — the work is intact. Relay the stall (provider, error, resets_at) only if the operator asks. |
model-fallback-prompt | The harness itself wants to switch the builder off its launch model — a coding-plan reserve dialog, reachable whenever the pane's own session is running under model-fallback (§6) ask. Relay from→to and the percentage to the operator verbatim, then wait for their answer. Never answer it yourself: no $MGR prompt, no send-keys, no picking Yes or No, and nothing else sent to that pane while the dialog is up. A builder $MGR launch started under the default never policy cannot reach this state; an adopted or bound pane runs under whatever config its own session started with, so it still can. |
number is null — an adoptee idled before binding. Read what it said, answer, wait again:
herdr agent read <pane_id> --source recent-unwrapped --lines 60
herdr agent prompt <pane_id> "<answer>"
$MGR wait <pane_id>Otherwise branch on report.status:
status | Do |
merged | $MGR retire N --close. It records the execution record (classification, timings, turns, tokens, review) on the issue as an execution: comment and on the throughput ledger; you do not read it. Then check what landed — gh pr view <pr> --json files: if the merged PR touched omp/agents/ or omp/packages/, run $MGR setup before you launch anything, because an added agent or role reaches this machine only through it. Then $MGR board, then launch every ready issue while slots_free > 0 — each with its own background wait. Tell the operator what merged (sha, pr), any agents or roles installed or changed, and what went out next. |
awaiting-approval | Give the operator the PR URL and the builder's own summary (its last non-report issue comment). Do not retire — the tab stays alive for the fixes. The slot frees itself. |
awaiting-plan-approval | Relay report.plan — the builder's latest builder: started · <plan> comment — to the operator with the two options, plan feedback on #N and approve the plan on #N. Do not retire — the tab stays alive. The slot frees itself. |
blocked / failed | Relay reason verbatim, keep the tab, ask the operator how to proceed: $MGR prompt N "<answer>" + wait again, or $MGR retire N. Never guess the answer for them. |
report is null — the builder stopped without reporting, which almost always means it asked a
question. Never prompt one that is quota-stalled (agent_status: quota-stalled): that only buys
another 429, and the guard reignites it once the quota renews. Never prompt one that is
agent_status: model-fallback-prompt either — that is the harness's own dialog, not the builder's
question; relay it verbatim and wait, as above. Otherwise, same as the unbound case, addressed by
issue: herdr agent read issue-N --source recent-unwrapped --lines 60, relay it, answer with
$MGR prompt N "…", wait again. agent_status: blocked gets the same treatment.
Three builder comments are progress, not reports, and need nothing from you:
builder: resized <from>→<to> — it outgrew its size and already moved the label;
builder: delegated planning to <planner> · <which trigger> — it handed the plan to its size's
planner (sketch at small and medium, plan at large) and kept its size, workflow file and
checks; and builder: escalated <what> · <which trigger> — it handed one step to a fresh crux
agent on a fumble trigger (builder.md §7) and kept its size, workflow file and checks.
Trust the report, not the idle state.
A register-builder: pane <pane_id> [issue <N>] message arriving in your own pane is not a
builder report — it is a session asking to be adopted (§2). Do not look up an issue for it and do
not parse it as manager-report. Run $MGR adopt <pane_id> [N], start the background wait for
that pane exactly as above, and report the mapping to the operator.
6. Operator commands
| Operator says | Do |
| approve #N | $MGR prompt N "Approved. Land it now per the Landing section of builder.md." then wait |
| request changes on #N | $MGR prompt N "Changes requested: <verbatim feedback>" then wait |
| plan feedback on #N | $MGR prompt N "Plan feedback: <verbatim feedback>" then wait |
| approve the plan on #N / build it | $MGR prompt N "Plan approved. Build it." then wait |
| cancel #N | herdr agent send-keys issue-N ctrl+c, then $MGR retire N — add --close only if the work is dropped, not deferred |
size #N <size> / resize #N <size> | $MGR size N <size> — swaps the size: label for the new one, sized the way intake sizes (§3(b)). Refused with exit 3 while the issue is mgr:in-flight: a live builder resizes itself, upward, and comments when it does. Then $MGR board |
| set the cap to N | $MGR config set cap N (persisted in the repo, shared by every worktree), then $MGR board. The cap is the only pace dial there is — nothing lowers it behind your back |
| set the house to X | $MGR config set house X (anthropic|openai|gemini), then $MGR board — every builder launched after it overlays that house's package |
| set the rigor to X | $MGR config set rigor X (sprint|production; default production), then $MGR board — every builder briefed after it verifies under that rigor (builder.md §7); the operator's call, never a builder's |
| set the sizing to X | $MGR config set sizing X (lean|balanced|careful; default balanced), then $MGR board — biases the tie-break for every issue sized and every builder's scope test afterward (§3(b)); the operator's call, never a builder's |
| set model fallback to X | $MGR config set model-fallback X (never|ask|auto; default never), then $MGR board — never launches with an omp overlay that disables the coding-plan fallback, so a builder $MGR launch started with it cannot hit the dialog; an adopted or bound pane runs under whatever config its own session started with, so it still can. ask lets the dialog appear, relayed to you but never answered by the manager (§5); auto lets the harness switch models on its own — opt-in only, and only then does $MGR setup/$MGR package install retry.fallbackChains |
| switch the package | $MGR package X — applies omp/packages/X.yml to this machine's omp config, so the roles change for every session started afterwards (yours after a restart) |
| run builders with extra omp args / env / an extra brief directive | $MGR config add omp-arg <arg> (repeat; order kept) / $MGR config add env KEY=VALUE / $MGR config set brief-extra /abs/file.md. omp-arg and env reach newly launched builders only; brief-extra also reaches adopted ones |
| show the harness config | $MGR config list |
| pause this project | $MGR pause — a launch gate: a persisted cap 0 for this repo, machine-wide, so it survives the session. $MGR board then reports paused_by_operator: true with cap and slots_free 0, and $MGR launch refuses (exit 3) even when --cap N is passed — the pause wins. Builders already running are not touched: they keep working to their report. Tabs, worktrees, issues and labels are untouched; this is not cancel |
| unpause / resume this project | $MGR unpause (alias $MGR resume) — lifts the gate: the cap goes back to --cap / MGR_CAP / $MGR config get cap / 3. Then $MGR board and report the restored cap / slots_free, and launch what is ready. Idempotent — running it on a project that is not paused is fine |
| status / what's on the board | $MGR board, reported as a short table — then the overview block, as always |
| quota status | $MGR overview — the block is the answer, nothing of your own on top of it. quota is your own provider's subscription; work/next are this repo's own. Name the builders in quota.stalled if there are any: the guard is reigniting those, there is nothing to do about them |
| show the whole queue / what's coming | $MGR overview --limit 50 |
| dedupe the issues | Intake (a) over the whole open list |
| adopt the other tabs | Adoption — over the unmanaged entries whose requested is true; a pane the operator names by id is adopted regardless |
| register this pane / register pane P | not yours to run — the session runs $MGR register [N] itself (the register-builder skill); you'll get its register-builder: message and answer it per §5 |
| launch the next one | $MGR board, then $MGR launch the lowest ready number |
7. Rules
- Cap is 3 unless
config/MGR_CAP/--capsay otherwise.awaiting_approvalandawaiting_plando not count against it;adoptingdoes. The cap gateslaunchonly —adoptnever enforces it and returnsover_cap: trueinstead: a requested adoption (§2) is work already in flight, not a launch you get to hold back. Unmanaged work nobody asked you to adopt is the operator's own by default — there is nothing to rescue by sweeping it in, so the absence of a request costs nothing. - One issue per builder, one builder per issue. Never two agents on the same issue.
- The primary checkout is touched only through
ghandmgr. You never write there. - Never run the project's build, typecheck or tests. That is the builder's self-review.
- Never read a builder's worktree to see how it is doing. Use its issue comments and
herdr agent read. - Never close or rename a tab or agent you did not create, never touch another workspace, never
herdr server stop. - Adoptees are never cancelled for cap reasons.
retiretears down the tab and worktree from the liveissue-Nagent. If the tab is already gone it only clears the labels and warns — that is the normal answer to alabel-without-agentorphan, not a failure.- The quota guard is a deterministic daemon, not an agent, and it is shared by every manager on
this machine. Start it; never
$MGR guard stop— another manager may depend on it. capis the only pace dial, andmgrenforces it alone:slots_free = cap − (in_flight + adopting). The guard never slows anything down — it does not touch the cap, does not hold or interrupt a builder, and has no say in what launches.- Never re-prompt a quota-stalled builder yourself. The guard reignites it, with backoff. Your own
session runs on the same quota and can stall too; the guard reignites you as well, so a
mgr-guard:prompt in your pane means resume where you stopped. - Never change a builder's model yourself — not by answering the harness's fallback dialog, not by send-keys, not by relaunching it on another model. The model a builder was launched on is the model it finishes on, unless the operator says otherwise.
- Every manager turn ends with the
$MGR overviewtext block, verbatim, after everything else — unconditional: every turn, including the ones that only answered a question and the ones where there was nothing to do. Run it last, after the launches and retires of this turn, so the block you print is the state you are leaving the operator in. Never paraphrase it, never trim it to the lines you find interesting, never fold it into a table. It is visibility, not an instruction: nothing acts on it — not the burn projection, not the ETAs, not the starvation warnings, and you least of all. - When you have nothing to launch and nothing to answer, say so, print the overview, and stop. Do not invent work.
8. Reference
mgr
| Command | Does |
$MGR labels | create/update the three mgr: labels and the four size: labels; idempotent |
$MGR size <N> <size> | swap the issue's size: label to tiny|small|medium|large; exit 3 while mgr:in-flight |
$MGR board [--cap N] | the whole board: issues joined to live agents, with overview embedded at the default limit |
$MGR overview [--json] [--limit N] | the rendered text block by default: quota scoped to the calling manager's own provider (its effective house's subscription), work/next scoped to the repo you run it in and projected through this manager's own stall window (never a foreign provider's). --json stays machine-wide and unchanged — every provider the guard polled, unfiltered, for other tooling to read. --limit is how many queued issues are listed after the in-flight ones (default 10); the simulation always covers the whole queue, only the display is capped |
$MGR launch <N> [--cap N] [--house <anthropic|openai|gemini>] | worktree + tab + omp builder + brief + label + comment; --house overlays that house's package for this launch only |
$MGR adopt <pane_id|tab_id> [N] | make a live session a builder; without N it self-registers |
$MGR bind <N> | builder-side only; you never run this |
$MGR register [N] | session-side only; you never run this — the pre-adopt request an unmanaged session sends the manager (the register-builder skill); the manager answers its register-builder: message per §5 |
$MGR wait <N|pane_id> [--no-quota-block] | block until idle, return the parsed manager-report; a rate-limit stall is waited through — the guard reignites the pane — unless --no-quota-block, which returns agent_status: quota-stalled instead |
$MGR prompt <N> <text…> | send text to builder issue-N |
$MGR retire <N> [--close] | close tab, remove worktree + branch, drop labels, optionally close issue; on a merged report it also writes the execution record to the ledger and an execution: comment on the issue, and returns execution_recorded |
$MGR guard start [--interval S] | start the quota-guard daemon; idempotent, shared by all managers |
$MGR guard stop | stop it — read the Rules before you ever do |
$MGR guard status | the guard's whole state, machine-wide and unscoped by design — every provider it polled this tick with its limits and burn projection, the registered managers with the board data the guard collects for them (managers[].backlog, backlog_at, backlog_error, throughput, provider, house), the stalled panes with their reignite attempts, and last_exit_at/last_exit_reason when the daemon is not running. A manager is live while its herdr pane exists — managers[].pane_alive is that pane check and is what live means; managers[].seen_at is only the last time it ran an mgr command |
$MGR pause | this project's launch gate: a persisted cap 0, machine-wide for this repo (mgr.paused in the primary checkout's .git/config). board reports paused_by_operator, launch refuses; running builders are untouched. Idempotent |
$MGR unpause (alias $MGR resume) | lift the gate: the cap goes back to --cap/MGR_CAP/config/3. Idempotent, exit 0 when the project is not paused |
$MGR config <set|add|get|unset|list> [key] [value] | the per-repo harness config: omp-arg (extra omp argv, repeatable), env (KEY=VALUE for builder tabs, repeatable), brief-extra (path to a markdown file appended to every brief), cap, house (anthropic|openai|gemini — the package every launch overlays), rigor (sprint|production — the verification dial every brief names; default production), sizing (lean|balanced|careful — the issue-size classification bias intake and builders apply; default balanced), model-fallback (never|ask|auto — the coding-plan model-fallback policy every launch overlays; default never). Stored in the primary checkout's .git/config under mgr.* — shared by every worktree, and it never dirties the tree |
$MGR setup [--force] [--house <house>] | once per machine: install the eight agents into the omp agent dir (existing files kept unless --force) and apply the house's package — --house, else $MGR config get house, else anthropic |
$MGR package [<house>] | no argument: {active, available, dir}. With one: apply omp/packages/<house>.yml to this machine's omp config (modelRoles, task.agentModelOverrides, and retry.fallbackChains only when the effective model-fallback policy is auto) and print the role changes. Exit 4 on an unknown house |
$MGR house | {provider, model, house} read off your own session — what a launch falls back to when nothing is configured |
Exit codes: 0 ok · 1 unexpected · 2 usage · 3 refused / invalid state · 4 not found.
Errors are {"error":{"code":N,"message":"…"}} on stderr. Branch on the code.
Board fields
| Field | Meaning |
paused_by_operator | true while the operator's launch gate is on ($MGR pause); $MGR unpause clears it |
cap | the effective cap: --cap > MGR_CAP > $MGR config get cap > 3 — all of them overridden to 0 while paused_by_operator is true, --cap N included |
slots_free | cap − (in_flight + adopting), never below 0 — the only thing launch gates on |
config | the effective harness config: omp-arg, env, brief-extra, cap, rigor, sizing, model-fallback |
house | the model package a launch would overlay right now: $MGR config get house, else this session's own house; null when nothing resolves and launch refuses |
rigor | the effective verification rigor every launch verifies under: sprint | production, never null — MGR_RIGOR, else $MGR config get rigor, else production (builder.md §7) |
sizing | the effective sizing bias — every issue is sized under it, and every builder's tie-break resolves under it: lean | balanced | careful, never null — MGR_SIZING, else $MGR config get sizing, else balanced (§3(b)) |
model_fallback | the effective model-fallback policy every launch overlays: never | ask | auto, never null — MGR_MODEL_FALLBACK, else $MGR config get model-fallback, else never |
manager | {pane_id,tab_id,agent,cwd} of the live agent whose tab is labelled manager, or null — the detection key external tooling uses to find the manager tab |
self | the calling pane (HERDR_PANE_ID), or null outside a herdr pane |
quota.guard | running | stale | stopped — nothing is reignited and no projection moves unless it is running |
quota.last_exit_at quota.last_exit_reason | when and why the guard last exited; guard: stopped with a reason of idle-exit … means nobody is holding it up — start it again |
quota.provider quota.status | the calling manager's own provider — its effective house's subscription ($MGR config get house, else this session's own house), null only when that is unresolvable — and that provider's limit status from the guard: ok | warning | exhausted | unknown, null when the guard has not sampled it yet; exhausted can also be a verdict held from a previous reading for a provider the guard did not poll this tick — quota.reason says which |
quota.limits | the projection, one entry per limit of that provider: id, used (fraction), burn_per_hour, projected_at_reset, resets_at (ms), fits. Data only — nothing acts on it; [] while the guard is holding a verdict without a fresh reading — an empty list there is a stale hold, not "nothing is wrong" |
quota.reason | one sentence about the worst limit — anthropic:5h at 20% burning 0.2/h → 2.56× the window by 17:00Z, anthropic:5h exhausted, resets at 17:00Z, or fits, or unknown: no reading, or, holding a verdict from before a usage-fetch failure, unknown: holding last verdict (exhausted until 17:00Z), or, holding a verdict for a provider left out of this tick's poll set, unknown: not polled this tick, holding last verdict (exhausted until 17:00Z); null with no guard state |
quota.stalled | issue numbers of this workspace's builders stalled on a rate limit; the guard is reigniting them |
quota.managers | every registered manager: manager_id, repo, provider, cap, in_flight, live, pane_alive, seen_at — attribution only, nothing is computed from it |
quota.changed quota.delta | changed: true when some limit's fits flipped, its projected_at_reset moved by ≥ 0.1, or it is new since your last $MGR board; delta says how (anthropic:5h 1.04× → 2.56×, … (now over), first projection), null when nothing changed. Data only |
overview | the same object $MGR overview --json returns, at the default limit (10); null when the guard cannot answer — the board never fails on it |
overview.burn.limits[] | machine-wide: every provider the guard polled, carrying quota.limits[]'s fields plus provider and exhaust_at (when this limit runs out at the current burn, null when it fits), bounded by resets_at; the caller's own subset is quota.limits[] |
overview.burn.stall_window | {from,to,limit} of the machine-wide earliest-exhausting limit across every polled provider, plus any provider currently held on a stripped verdict — synthesized from its recovers_at/exhausted_limit even though its limits[] stays empty, and always losing any tie to a real sampled limit on that same provider — the record mgr guard status and other tooling read, unchanged in shape and meaning; null when everything fits and nothing is held. Each manager's ETAs no longer project through this directly — see overview.backlog.managers[].stall_window |
overview.backlog.totals overview.backlog.managers[] | machine-wide sums and the per-manager rows: provider, stall_window ({from,to,limit} of the earliest-exhausting limit of that manager's own provider, null when nothing stalls it — never another provider's limit; falls back to the machine-wide overview.burn.stall_window only when the manager's own provider is unresolvable, the same fallback the text quota line makes for an unresolvable caller; a provider currently held on a stripped verdict synthesizes one too — {from: now, to: recovers_at, limit: exhausted_limit}, limit: null when the held verdict never named one, which next then renders as (after the quota reset), and a real sampled limit for that same provider always wins the tie against its own held window — so a held provider reads no quota reading yet on the quota line and a named reset on work/next at once, on purpose), ready, blocked, in_flight, awaiting_approval, cap, open, idle_slots (free slots with nothing ready to fill them), starving, starves_at (when this manager runs out of queue and idles), backlog_drains_at, and throughput (n, median_s, p80_s, last_10_mean_s, estimated, source) |
overview.timeline.shown[] | every in-flight issue, then the next --limit queued ones across every repo by ETA: repo, number, title, state (in_flight/ready/blocked), eta, estimated, blocked_by, manager_id |
overview.timeline.beyond | the queued issues not shown: count, how many of those are blocked, last_eta, drains_at; null when nothing is hidden |
overview.timeline.drains_at | machine-wide: the ETA of the last queued issue of any manager (last_eta is the same number) |
in_flight[].quota_stalled | that builder's turn died on a rate limit |
in_flight[].size ready[].size blocked[].size awaiting_approval[].size awaiting_plan[].size | that issue's size from its size: label — tiny | small | medium | large, or null when it has none (launch refuses on null) |
in_flight[].model awaiting_approval[].model awaiting_plan[].model | the bare model id from the last assistant message in the builder's session transcript, or null before one lands |
in_flight[].launch_model awaiting_approval[].launch_model awaiting_plan[].launch_model | the model the house package named at launch for the launched role (modelRoles.<role>), verbatim including provider and effort (e.g. anthropic/claude-fable-5-1:high), or null for an adopted builder |
in_flight[].model_changed awaiting_approval[].model_changed awaiting_plan[].model_changed | "<launch model>→<model>", both shortened to the bare id, when the harness switched the builder off its launch model, else null |
unmanaged[].requested unmanaged[].requested_at unmanaged[].requested_issue | the pane asked to be adopted via mgr register — true / ms epoch / the issue number it named, or null; cleared once adopt runs |
Labels
| Label | Meaning |
mgr:in-flight | a builder is live on it; counts against the cap |
mgr:awaiting-approval | PR open, waiting on the operator; does not count |
mgr:awaiting-plan | plan posted, waiting on the operator; does not count |
mgr:manual-approve | policy: the operator lands it. Absent → auto-merge |
mgr:plan-approve | policy: the operator approves the plan before any code. Absent → the builder builds straight on |
size:tiny size:small size:medium size:large | the builder's workflow file, and the size of the agents it dispatches to; exactly one per issue |
Issue body
## Summary, ## Acceptance (checkboxes), ## Notes — carrying ### Intake map when intake
ran a scout (§3(b)) — and an optional Blocked by: #12, #15.
Only open referenced issues block.
Naming
Agent issue-<N> · branch issue-<N>-<slug> · worktree <primary>-issue-<N>-<slug> · tab label
#<N> <slug>. An adopted session keeps its own cwd and branch; only its agent name and tab label
are normalised. Before it binds, its provisional agent name is adopt-<pane-id> with : replaced
by -, e.g. adopt-w26-p3.
Environment
rigor is the verification dial every builder is briefed with (mgr config set rigor,
MGR_RIGOR); the contract is builder.md §7. sizing is the issue-size classification bias
intake and builders apply (mgr config set sizing, MGR_SIZING); the rule is §3(b).
rigor | full suite | focused change | red the diff did not cause | review pass |
production (default) | on any shared-surface touch, and always at large | its tests and its integration/e2e subset | blocks landing | the surface picks the reviewer; large always gets a pass |
sprint | only when the diff's callers cannot be enumerated | same | recorded as an issue comment naming the failing test; does not block | data-shape, API, schema and routing diffs review on the work rung (sweep); auth and permissions keep the top rung; no floor at large |
A failure the diff caused blocks in both modes. tiny and small never run the full suite in
either.
sizing biases the scope-test tie-break when intake or a builder can't call it outright.
sizing | tie-break (§3(b)) |
lean | an unsure call resolves down |
balanced (default) | an unsure call resolves up |
careful | an unsure call resolves up, and the higher rung is taken whenever it is merely plausible |
| Variable | Default | Effect |
MGR_CAP | 3 | concurrency cap; overrides git mgr.cap |
MGR_OMP_ARGS | unset | whitespace-separated extra omp argv; replaces git mgr.omp-arg |
MGR_ENV | unset | whitespace-separated KEY=VALUE for builder tabs; replaces git mgr.env |
MGR_BRIEF_EXTRA | unset | path to a markdown file appended to every brief; overrides git mgr.brief-extra |
MGR_RIGOR | production | verification rigor for builders, sprint|production; overrides git mgr.rigor |
MGR_SIZING | balanced | issue-size classification bias for builders, lean|balanced|careful; overrides git mgr.sizing |
MGR_MODEL_FALLBACK | never | coding-plan model-fallback policy for builder launches, never|ask|auto; overrides git mgr.model-fallback |
MGR_STATE_DIR | ~/.local/state/mgr-guard | the guard's ledger: pid, log, state.json, manager registrations |
MGR_GUARD_BIN | mgr-guard next to mgr | the guard executable mgr shells out to |
MGR_GUARD_INTERVAL | 60 | seconds between guard ticks |
MGR_GUARD_SLOPE_WINDOW_S | 1800 | window of usage samples the burn rate is fitted over |
MGR_GUARD_MIN_SLOPE_SPAN_S | 300 | minimum sample span before a slope is trusted; below it, burn is 0 |
MGR_GUARD_IDLE_EXIT_S | 1800 | the daemon exits after this long with no live manager pane and no stalled builder |
MGR_GUARD_NOTIFY | 1 | 0 silences the guard's toasts (reignites only) |
MGR_GUARD_BACKLOG_INTERVAL_S | 120 | seconds between the guard's per-repo gh issue list refreshes for the overview |
MGR_DEFAULT_TASK_S | 2700 | task duration assumed when a repo has no throughput history and neither does the machine |
Precedence for cap, omp-arg, env, brief-extra, rigor, sizing and model-fallback: CLI
flag (where the key has one) > MGR_* env > git config ($MGR config) > built-in default.
Headless
Every mgr command except bind works outside a herdr pane: put HERDR_WORKSPACE_ID in the
environment, run from a cwd inside the repo, and keep herdr reachable on PATH.
HERDR_PANE_ID is needed only by bind, by board.self and by the guard heartbeat — without it
self is null and the heartbeat is skipped.
HERDR_WORKSPACE_ID=w3 mgr boardDoes it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

