CodeCrew CLI reference¶
Every gh codecrew verb: what it takes, what it reads, what it writes, what
it prints, what it refuses, and what it exits with. The protocol these verbs
implement is SPEC.md; the refusal-code catalogue is
SPEC §10, which every code below links to.
Every verb is safe to run by any role from any repo in the project: the pointer file resolves the hub.
- Invocation
- Exit status
- Output channels
- Common refusals
- Verbs:
init·migrate·status·milestone new·milestone close·milestone evidence·task new·task start·task finish·checkpoint·role·roles diff·roles show·identity new·identity webhook·identity token·version
Invocation¶
Installed as a gh extension the command is gh codecrew; the binary built
from source takes the same arguments without the gh prefix. gh 2.50.0 or
later must be on PATH.
--help or -h anywhere in the arguments prints the verb list on stderr and
exits 0, before the verb runs. gh codecrew help prints the same list on
stdout. --version and -v are version. An unknown verb or subcommand
prints the verb list on stderr and exits 1.
An issue reference — the <ref> argument of task start, task finish and
checkpoint — is N, #N or owner/repo#N; a bare number resolves against
the repository the verb runs in. A milestone number is <n>, and
milestone close also accepts M<n>. Where a verb takes options as well as
a leading argument, the argument may be given before or after them;
roles diff and roles show want the role name first, and task start and
milestone evidence take their argument and nothing else.
Exit status¶
0 when the verb did what it was asked, 1 on every failure — a refused
gate, an unusable flag, an unreachable GitHub, a gh that failed. There is
no exit-code taxonomy: 1 says only "this did not happen". --dry-run
follows the same rule and exits 1 when it reports a gate that would refuse.
Output channels¶
stdout carries everything a verb prints as it works: what a caller
consumes — a minted token, role <name>'s identity — and the report or
receipt, with the note: and warning: lines that qualify it. A note: is
advisory and never a failure: it stands beside a verb that goes on to
succeed. Each verb's own section says which lines it writes.
stderr carries three things, and only these. The refusal line, once, as
the verb exits 1:
The code is a fixed vocabulary, catalogued in SPEC §10;
the detail is prose for a human and may be reworded in any release. The
note: lines raised while the pointer is read — a pointer, or a hub's
pointer, carrying no codecrew: version, and a gh whose version could not
be read — which precede anything the verb itself prints. And identity
token's receipt, which is on stderr so that stdout carries the token alone.
Under --dry-run the gate lines and the plan are stdout; a dry run that ends
in a refusal prints that one line on stderr like any other.
Common refusals¶
Every verb that loads the working repo's .codecrew/config.yml can raise
these, before its own work begins. The verbs that load no pointer are
version, help, init, migrate, identity token and
identity webhook; init and migrate raise the layout codes themselves.
| Code | Condition |
|---|---|
LAYOUT_LEGACY |
The repo is still on the protocol 1.x layout: a root .codecrew.yml, or a root roles/ holding one of the five contracts, with no .codecrew/config.yml. The detail names what was found and gh codecrew migrate. |
PROTOCOL_MISMATCH |
The pointer's protocol major differs from the one this binary implements — the local pointer, or the hub's on a spoke's fetch. |
IDENTITY_UNTYPED |
A routing row's identity carries no type prefix; the detail names the row and the four forms. |
SPOKE_ROUTING |
A spoke's pointer carries a roles: block; the hub carries the one routing table. |
HUB_UNREADABLE |
In a spoke: the hub's pointer could not be fetched or parsed, so no role resolves. Routing fails closed. |
GH_TOO_OLD |
The installed gh is below 2.50.0, checked once, up front. |
GH_UNREACHABLE |
gh never reached GitHub — no route, no DNS, no credentials. Never folded into another condition. |
A hub reads its own pointer from disk and resolves roles with no network.
version, help, and roles show / roles diff in a hub need no network
at all.
gh codecrew init¶
Scaffolds a repository into a CodeCrew project and creates the protocol's
labels. Hub mode — the default — writes the pointer with the full ~-routed
roles table, a ROADMAP.md seed, the role contracts embedded in the
installed release under .codecrew/roles/, and a blank
.codecrew/roles/<role>.local.md extension beside each. Spoke mode writes
the pointer alone of those. Both modes write the entry point,
.codecrew/AGENTS.md, and the two root files that reach it: an AGENTS.md
naming the path and importing it, and a CLAUDE.md importing AGENTS.md.
Existing files are kept and reported. It then commits exactly the files it
wrote and ensures the three cc: labels exist. Rerunning it writes no file
it already wrote, commits nothing when it wrote nothing, and creates no label
it already created.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--hub |
owner/repo, or self |
self |
Spoke mode: the pointer names that hub and nothing else is scaffolded. self is hub mode. |
Reads. The working directory, which must be the repository root; the
repository's default branch and its pull-request requirement, through gh;
the repository's existing labels.
Writes. .codecrew/config.yml, .codecrew/AGENTS.md, AGENTS.md,
CLAUDE.md, and in hub mode ROADMAP.md, .codecrew/roles/<role>.md and
.codecrew/roles/<role>.local.md — each only when it is absent. One commit
of exactly those paths, on the current branch, or on codecrew-bootstrap cut
from the default branch when the default branch requires pull requests; it
never pushes. In GitHub: the missing cc:task, cc:milestone and
cc:needs-decision labels, with the protocol's colour and description; an
existing label is left exactly as it is. Everything it prints is on stdout:
a line per file written or kept, the commit, a line per label, each note:,
and last an action needed block naming any kept root entry point that does
not reach .codecrew/AGENTS.md, with the lines to add to it. It reads no
pointer, so nothing but a refusal reaches stderr.
Refusals. LAYOUT_LEGACY — the repo is on the 1.x
layout; gh codecrew migrate moves it. A directory that is not the
repository root, and a scaffold that cannot be written, exit 1 without a
code. A label step that cannot reach GitHub is a note:, not a refusal, and
the scaffold stands; so is a directory that is not yet a git repository, and
the labels arrive on the rerun once it is one.
Exit status. 0 when the scaffold is complete, including a rerun that writes nothing; 1 on a refusal or an unusable argument.
gh codecrew init # this repo is the hub
gh codecrew init --hub myorg/platform # a spoke pointing at that hub
gh codecrew migrate¶
Moves a repository from the protocol 1.x layout to 2.0. git mv takes
.codecrew.yml to .codecrew/config.yml and, out of a root roles/, the
five role contracts and their <role>.local.md extensions into
.codecrew/roles/, removing the emptied directory. The pointer is then
rewritten in place: codecrew: "2.0", a coordinator row when the table
declares none, and every identity typed by asking GitHub what each bare 1.0
login is. Comments, blank lines and key order are kept. It writes
.codecrew/AGENTS.md when the repo has none, and does for the root
AGENTS.md and CLAUDE.md what init does. Every refusal is raised before
anything is written. A repo already on the 2.0 layout says so, moves nothing
and commits nothing — the label step still runs.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--dry-run |
none | off | Prints every file step and every label creation and restyle; writes nothing. |
Reads. The working directory, which must be the repository root of a git
repository; .codecrew.yml; a root roles/, and only when it already holds
one of the ten CodeCrew names; GitHub, for the account behind each bare 1.0
identity (users/<login>, then users/<login>[bot]).
Writes. The moved and rewritten files above, in one commit of exactly
those paths on the current branch; it never pushes. In GitHub: the missing
cc: labels created, and the existing ones restyled to the protocol's colour
and description, each reported; every other label untouched. Everything it
prints is on stdout: a line per step, each note:, and last an action
needed block for a kept root entry point that does not reach the
instructions. It reads no pointer, so nothing but a refusal reaches
stderr.
--dry-run. The same steps in the same order, the same refusals, and the
same label lines; nothing written.
Refusals. BOTH_LAYOUTS — the 1.x and 2.0 layouts
overlap. FOREIGN_ROLES_DIR — a CodeCrew-owned root
roles/ holds an entry outside the ten names.
MIGRATION_UNSUPPORTED — the pointer's protocol major
is not 1. SPOKE_ROUTING — a 1.x spoke's pointer
carries a roles: block. IDENTITY_UNRESOLVED — a
bare identity answers to nothing, to both a user and an App, or to an
organization. GH_UNREACHABLE — the lookup could not
reach GitHub at all. A directory that is not a git repository, or not its
root, exits 1 without a code. A label step that cannot reach GitHub is a
note:; the rerun completes it.
Exit status. 0 when the repo is on the 2.0 layout, including a rerun that
moves nothing; 1 on a refusal. --dry-run exits with the first refusal it
reports.
gh codecrew migrate --dry-run # every step, nothing written
gh codecrew migrate # the move, in one local commit
gh codecrew status¶
Reports where the project is: the open milestones and their tasks, each
task's inferred state, and every raised gate — on tasks and on milestone
issues alike, the latter marked (milestone). A task in progress or in
review names its holder, taken from the login in its latest **Started by**
record and falling back to the first assignee only when nothing records a
start. It then reports the stale task branches of the repository it runs in —
every task/<n>-… branch on the remote whose task issue is closed — with the
delete-or-keep verdict the next milestone close would give it. With no open
milestone it says so in place of the board and the gates.
Options. None.
Reads. The pointer and, from a spoke, the hub's; the hub's open
milestones, their sub-issues, labels and comments; the running repository's
remote task/<n>-… branches and one issue per branch; the repository's
delete-branch-on-merge setting; the local .codecrew/roles/ contracts, for
the drift note.
Writes. Nothing. The report and every note: line it carries — the
delete-on-merge setting, the contract drift, a branch listing it could not
read or could not finish — go to stdout.
Refusals. The common ones. Nothing in the report
refuses: an ID that is not the milestone's own prints as a line and the
report carries on, a branch whose task cannot be read is a note: and is
left, a listing that held more than one page says it is partial, and a
repository that could not be read at all replaces the branch report with a
note: — the report's silence means clean and nothing else.
Exit status. 0 when the report printed; 1 on a common refusal.
gh codecrew milestone new¶
Creates a milestone tracking issue in the hub from the template, labelled
cc:milestone and titled M<n>: <title>. Each --requirement becomes a
bold-ID line under ## Requirements, numbered M<n>-R1, R2, … in the
order given — the section the close gate reads. The number n is derived
twice: before creating, as one past the highest M<k>: title across the
hub's label-filtered milestone listing and its newest unfiltered issues; and
after creating, when both listings are read again and the number must be the
new issue's alone. Another issue already carrying the prefix has the new
issue renumbered to the next free number, title and M<n>-R<k> IDs, printed
as a renumbered: line.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--title |
text | none; required | The milestone's title. A title carrying an M<k> prefix that disagrees with the derived number is refused; one that agrees is stripped. |
--goal |
text | _To be written._ |
The ## Goal paragraph. |
--requirement |
text | none | One requirement, repeatable. The CLI numbers them; text that brings its own ID is refused. |
--dry-run |
none | off | Prints the number, title and requirement IDs the milestone would get; creates nothing. |
Reads. The pointer and, from a spoke, the hub's; the hub's milestone listing and its newest issues.
Writes. One issue in the hub, labelled cc:milestone. No file: the
milestone's ROADMAP.md row is added, Done, by its document PR. On stdout:
the issue reference, the title, the requirement IDs counted, any
renumbered: line, and a note: when the requirements section it wrote
yields no bold ID.
--dry-run. The number, title and requirement IDs; no issue.
Refusals. MILESTONE_NUMBER_TAKEN — the issue was
created and another milestone holds its M<n>: prefix, and the renumbering
did not settle it; the detail names both issues and the hand fix. A missing
--title, a title whose own M<k> prefix disagrees, and a --requirement
carrying an ID exit 1 without a code. Plus the common
refusals.
Exit status. 0 when the issue exists as described; 1 otherwise.
gh codecrew milestone new --title "Greeting service" --dry-run
gh codecrew milestone new --title "Greeting service" --goal "…" \
--requirement "visiting the app's URL returns a greeting" \
--requirement "the greeting is configurable"
gh codecrew milestone close¶
Closes a milestone once every gate passes, then sweeps the task branches it
leaves behind. The gates, in order: the milestone issue carries no
cc:needs-decision; every task under it is closed; its ## Requirements
section declares at least one bold requirement ID; every ID it declares is
the milestone's own; every requirement's latest QA verdict is satisfied —
only verdicts from the qa role's holder count, and the latest comment
carrying a verdict for an ID wins; and the milestone document is on the
default branch. It then deletes each task branch whose PR merged and which
still sits at the merged commit, or which has no open PR and carries nothing
beyond the default branch, reporting every branch it keeps and why. A second
pass reaches the branches earlier closes left behind, across the hub and
every repo the milestone's tasks name, and names them in the closing comment
under Swept from earlier closes:. It gathers the milestone's
Decision and Deviation comments as raw material for the doc-synthesizer.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--dry-run |
none | off | Prints every gate in order with its outcome, then every branch either sweep would delete or keep and why, then the closing comment; writes nothing; exits with the first refusal's code. |
Reads. The pointer and, from a spoke, the hub's; the milestone issue, its
sub-issues, their labels and comments; docs/milestones/<n>-*.md on the
hub's default branch; the task/<n>-… branches of the hub and of every repo
the tasks name, and the pull requests whose head each candidate branch is.
Writes. In GitHub: the closing comment on the milestone issue, the issue
closed, and the branches the two sweeps delete. Nothing on disk. The report,
the gate lines and the sweep's note: lines all go to stdout.
--dry-run. The same gates in the same order, the same sweep verdicts
and the same closing comment; nothing written.
Refusals. NOT_FOUND — no open milestone with that
number. MILESTONE_GATED — the milestone issue carries
cc:needs-decision. OPEN_TASKS — tasks under it are
still open. NO_REQUIREMENTS — the ## Requirements
section declares no bold ID. REQUIREMENT_ID_MISMATCH
— an ID declared there is not the milestone's own; the grammar is
M<milestone>-R<k>. VERDICT_MISSING — a requirement
has no QA verdict from the qa seat's holder.
VERDICT_UNSATISFIED — the latest verdict on a
requirement is not satisfied. DOC_MISSING — no
docs/milestones/<n>-*.md on the default branch. Plus the
common refusals. Nothing in the sweep refuses: a branch
the verb could not read is a note: and is left standing, and a repo
carrying more task branches than one listing holds is swept in part and says
so.
Exit status. 0 when the milestone is closed; 1 on the first refusal,
whose code it exits with under --dry-run too.
gh codecrew milestone evidence¶
Walks the milestone's record — the tracking issue and every sub-issue, bodies and comments — and verifies that every citation resolves: github.com references through the API under the caller's auth, everything else by HTTP. A citation is a URL in prose or in a Markdown link outside code; a URL inside an inline code span, a fenced block, or a block indented four columns where it does not continue a paragraph is content and is not checked. It checks the milestone's own requirement-ID grammar before the walk. The milestone resolves whatever its state: a closed one resolves too and is reported as closed before the citation report.
Options. None.
Reads. The pointer and, from a spoke, the hub's; the hub's milestone listing in every state; the milestone issue and its sub-issues, bodies and comments; each cited URL.
Writes. Nothing. The report goes to stdout, including the note: that
says the milestone is closed and a warning: line per unresolved external
citation.
Refusals. NOT_FOUND — no milestone carries that
number, open or closed. REQUIREMENT_ID_MISMATCH — an
ID under ## Requirements is not the milestone's own, checked before the
walk. EVIDENCE_UNREACHABLE — a github.com citation
does not resolve. An external citation that does not resolve prints a
warning: and does not block. Plus the common refusals.
Exit status. 0 when every github.com citation resolved; 1 when one did not, or on any other refusal.
gh codecrew task new¶
gh codecrew task new --milestone N --title T
[--repo owner/repo] [--goal G] [--requirements IDs]
[--adopts <ref>[,<ref>]]
Creates a task issue from the template, labelled cc:task, in the spoke
named by --repo or in the current repository, and attaches it to the
milestone as a sub-issue. --adopts names the backlog captures the task
takes up: they are written under an ## Adopts section of the body, each
capture is commented on to say this task carries it, and task finish closes
them after the merge. Every adopted ref must be an open issue and is checked
before anything is created, so a refusal leaves no half-adopted task;
duplicates collapse. The milestone resolves by number from the hub's
open-milestone listing, then from the hub's newest issues regardless of
label, then again after a short wait — three reads in all, and a milestone
found by either fallback is named in the output.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--milestone |
number | none; required | The milestone the task links into. |
--title |
text | none; required | The task's title. |
--repo |
owner/repo |
the current repository | The spoke the task issue is created in. |
--goal |
text | _To be written._ |
The ## Goal paragraph. |
--requirements |
comma-separated IDs | None directly. |
The ## Requirements line: the milestone requirement IDs this task serves. |
--adopts |
<ref>[,<ref>] |
none | A backlog issue this task adopts and task finish closes; repeatable, and each value may be a comma-separated list. A bare number resolves against the task's own repo. |
Reads. The pointer and, from a spoke, the hub's; the hub's milestone listing and newest issues; each adopted issue's state.
Writes. In GitHub: one issue in the target repo labelled cc:task,
linked to the milestone as a sub-issue, and one comment on each adopted
capture. Nothing on disk. On stdout: the issue reference, the adoptions
recorded, and a note: for a comment that could not be posted or a milestone
found by one of the fallback reads.
Refusals. NOT_FOUND — no open milestone with that
number, after all three reads. ADOPT_NOT_OPEN — an
adopted ref could not be read, or is already closed; checked before the task
is created. GH_UNREACHABLE — GitHub could not be
reached. Plus the common refusals. A comment on a capture
that fails once the task exists is a note:; the body carries the link
either way.
Exit status. 0 when the task issue exists and is linked; 1 otherwise.
gh codecrew task start¶
Starts a task: it verifies that the issue is an open cc:task whose ## Plan
section is not empty, posts the **Started by** @<login>. record that makes
the caller the task's owner — the record task finish holds to — assigns the
caller when the routing table types them as a human, and creates the linked
development branch task/<n>-<slug>. An app:-typed caller, and any login
carrying the [bot] suffix, is not assigned: GitHub does not accept a GitHub
App as an issue assignee, and the record is the fact. A caller whose role
routing resolves to a contract that forbids commits — qa, reviewer — gets
no branch.
Options. None.
Reads. The pointer and, from a spoke, the hub's routing table; the task
issue, its labels, its body's ## Plan section; the caller's login.
Writes. In GitHub: the **Started by** comment on the task issue, the
assignment where the caller is human, and the linked branch. Nothing on disk
— the branch is created on the remote, and the printed line names the
git fetch && git switch that brings it local. On stdout: the branch
created, the local command, the start record, and a note: for an assignment
or a branch creation that failed.
Refusals. CLOSED — the task issue is already
closed. NOT_A_TASK — the issue is not labelled
cc:task. NO_PLAN — the task's Plan section is
empty. Plus the common refusals. A failed assignment is a
note:.
Exit status. 0 when the record is posted; 1 on a refusal.
gh codecrew task finish¶
The gatekeeper: it checks every gate, merges the closing pull request by
rebase, closes the task and the captures it adopted, deletes the head branch
and tidies the clone it runs in. The gates, in order: the task is open; it
carries no cc:needs-decision; every gate raised on it has a
**Gate resolved:** answer; the caller is the seat that started it — the
login in the latest **Started by** record, the same login with the [bot]
suffix ignored, or the same routed seat, a team-held role being any member; a
pull request closes the task; its CI checks exist and are green; the reviewer
role's holder has approved when that role routes to a distinct principal, and
otherwise any non-doer has; and GitHub's own required-review rule counts the
approval. Before the merge it prints a note: naming every issue the pull
request's closing references would close besides the task itself. After the
merge it closes each adopted capture with a comment naming the task, the pull
request and the merge commit, deletes the head branch, and — in a clone of
the task's own repo that holds the merged branch — fetches with prune,
switches to the default branch if that branch is checked out, fast-forwards
it, and deletes the local task branch. Nothing after the merge refuses.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--operator-confirm |
none | off | Solo tier: records an explicit operator confirmation on the pull request in place of a non-doer approval. A crew identity is refused. |
--bypass |
none | off | Merges with the ruleset's administrator bypass when GitHub does not count the recorded approval, recorded as a comment on the pull request. For a human operator the ruleset lists as a bypass actor; a crew identity is refused. |
--dry-run |
none | off | Prints every gate in order — ok, refused with its code, not reached, not applicable — then the comments, merge, adopted captures, head deletion and local cleanup it would perform; writes nothing, the clone included; exits with the first refusal's code. |
Reads. The pointer and, from a spoke, the hub's routing table; the task issue, its labels and comments; the pull requests that close it, their checks, reviews and review decision; the closing references GitHub parsed from the pull request body; the local clone's branches and remotes.
Writes. In GitHub: the operator-confirmation or bypass comment where one
applies, the rebase merge, the task closed, a comment on each adopted capture
and that capture closed, and the head branch deleted. On disk, and only in a
clone of the task's own repo: a fetch with prune, a switch to the default
branch, a fast-forward of it, and the deletion of the local task branch —
forced, and allowed only when the branch sits at the merge commit or is
contained in the fetched default branch. A branch carrying anything else is
named and kept. Run anywhere else, the local half does nothing and prints
nothing. Everything it prints is on stdout: the gate lines, the merge, the
note: lines about the pull request's other closing references before it,
and every note: after it.
--dry-run. Every gate and every write above, printed and not performed;
the same note: about the pull request's other closing references; the same
exit code as the real run's first refusal.
Refusals. CLOSED — the task issue is already
closed. GATED — the task carries cc:needs-decision.
GATE_UNRECORDED — a gate was raised and the label
removed with no **Gate resolved:** comment answering it.
NOT_OWNER — the caller is not the seat that started
the task, or nothing records a start. NO_PR — no open
pull request closes the task.
NO_CHECKS_PERMISSION — the caller's installation
token cannot read the pull request's checks at all.
NO_CHECKS — the pull request reports no checks; a
check reporting skipping is a reported check and satisfies the gate, a
[skip ci] commit produces none at all, and there is no override.
CHECKS_PENDING — its checks are still
running. CHECKS_FAILING — a check failed.
NO_HOLDER_REVIEW — the reviewer seat's holder has not
approved. NO_NONDOER_APPROVAL — the reviewer seat is
operator-held and no non-author has approved.
REVIEW_NOT_COUNTED — the protocol's review gate
passed and GitHub's own required-review rule has not; the detail names the
supported paths. SELF_CONFIRM — --operator-confirm
was given by a crew identity. CREW_BYPASS —
--bypass was given by a crew identity. Plus the
common refusals. After the merge nothing refuses: a
capture already closed is reported, one that cannot be closed is a note:,
and so is a failed deletion.
Exit status. 0 when the merge happened and the task is closed; 1 on the
first refusal, whose code --dry-run exits with too.
gh codecrew task finish 12 --dry-run
gh codecrew task finish 12
gh codecrew task finish 12 --operator-confirm # solo tier, human operator
gh codecrew checkpoint¶
Raises a human gate: it posts the question as a comment and applies
cc:needs-decision, creating the label with the protocol's colour and
description if the repository does not define it yet. The ref is a task, or
the milestone issue when the question is about a requirement and no task
carries it; the comment and the receipt say which. The gate blocks
task finish until a human removes the label and a **Gate resolved:**
comment records the answer.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--question |
text | none; required | The judgment call a human must make. Posted verbatim as the comment. |
Reads. The pointer and, from a spoke, the hub's; the referenced issue and the repository's labels.
Writes. In GitHub: the question as a comment on the referenced issue, the
cc:needs-decision label created if absent, and the label applied. Nothing
on disk. On stdout: the receipt naming the issue and that the gate is
raised, and a note: for a label creation that failed.
Refusals. The common ones. A missing --question or
<ref> exits 1 without a code. A label creation that fails is a note: and
the gate is still raised: applying an unknown label creates it implicitly,
and only the colour is lost.
Exit status. 0 when the gate is raised; 1 otherwise.
gh codecrew role¶
Prints the typed identity holding a role — app:<slug>, user:<login>,
team:<org>/<slug>, or ~ for the operator — on one line. Script-consumable,
and correct from a pointer-only spoke, where the hub's routing table is
fetched at load. With --login it prints instead the handle GitHub will
accept a review request for, and nothing at all for an app: or ~ seat,
neither of which can be requested: the emptiness is the caller's whole
decision.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--login |
none | off | Prints the review-requestable handle: the login of a user: seat, <org>/<slug> for a team: seat, and nothing for an app: or ~ seat. |
Reads. The pointer and, from a spoke, the hub's routing table.
Writes. Nothing. One line on stdout, or no line at all under --login for
an unrequestable seat.
Refusals. The common ones — a hub that cannot be read
refuses rather than answering ~. A missing or unknown role name exits 1
without a code.
Exit status. 0 when the role resolved, including the empty --login
output; 1 otherwise.
gh codecrew role reviewer # app:myorg-checker
reviewer=$(gh codecrew role reviewer --login)
[ -n "$reviewer" ] && gh pr create --reviewer "$reviewer"
gh codecrew roles diff¶
Shows how the project's .codecrew/roles/<role>.md differs from the contract
embedded in the installed CLI. A .codecrew/roles/<role>.local.md extension
is never drift. Contracts are the project's own fork: reconciliation is a
judgment routed through a task and a pull request, never an overwrite.
Options. None.
Reads. The pointer; the local .codecrew/roles/<role>.md; the contract
embedded in the binary.
Writes. Nothing. The diff goes to stdout.
Refusals. The common ones. A role name the CLI does not embed exits 1 without a code.
Exit status. 0 whether or not the contracts differ; 1 on a refusal.
gh codecrew roles show¶
Prints the contract a dispatched session loads: the hub's
.codecrew/roles/<role>.md with its local extensions appended in order — the
hub's, then the spoke's. With --latest it prints the contract embedded in
the installed binary, whole and without extensions.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--latest |
none | off | Prints the contract embedded in the installed binary instead of the composed one. |
Reads. The pointer; in a hub, .codecrew/roles/<role>.md and
.codecrew/roles/<role>.local.md from disk; from a spoke, the hub's contract
and extension from its default branch through GitHub, and the spoke's own
extension from disk.
Writes. Nothing. The contract goes to stdout.
Refusals. GH_UNREACHABLE — from a spoke, the
hub's contract could not be fetched. Plus the common
refusals. In a hub the verb reads only local files and needs no network.
Exit status. 0 when the contract printed; 1 on a refusal.
gh codecrew identity new¶
gh codecrew identity new <role> --name N
[--owner O] [--with-webhook --webhook-url U]
[--with-approval-permission]
[--events E,E] [--webhook-secret S]
Mints the role's App identity through the GitHub App manifest flow: it builds
a manifest carrying the role's minimal permission set, serves a one-click
loopback URL for the operator to open, stores the private key GitHub returns,
writes the role's routing into the hub's .codecrew/config.yml in typed form
(identity: app:<slug>), and prints the steps that remain — installing the
App, which is per account, and the optional display polish. Webhooks are off
by default.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--name |
App name | none; required | The App's name — a crew member (myorg-coder), not a role. |
--owner |
account | the hub's owner | The account that owns the App. |
--no-route |
none | off | Prints the routing step instead of writing it into the hub's pointer. |
--with-webhook |
none | off | Subscribes the App to protocol traffic; requires --webhook-url. |
--webhook-url |
URL | none | The receiver for --with-webhook deliveries. |
--with-approval-permission |
none | off | Reviewer only: grants contents: write, so the App's approvals satisfy GitHub's required-review rules. |
--events |
comma-separated events | pull_request,pull_request_review |
With --with-webhook: the events to subscribe, validated against the role's permissions. |
--webhook-secret |
secret | none | With --with-webhook: sets the hook secret to the receiver's as soon as the App exists. |
Reads. The pointer and the hub it names; the owner account's type, through GitHub; the manifest conversion GitHub returns at the end of the browser flow.
Writes. On disk: ~/.config/codecrew/<slug>.<date>.private-key.pem and
the credential stub ~/.config/codecrew/<slug>.json; the hub's
.codecrew/config.yml routing row, uncommitted, unless --no-route. In
GitHub: the App itself, and its hook secret when --webhook-secret is given.
On stdout: the loopback URL to open, the stored paths, and the numbered steps
that remain.
Refusals. The common ones. A missing <role> or
--name, a manifest the flags do not make valid, --webhook-secret without
--with-webhook, and a browser flow that does not complete within the hour
exit 1 without a code.
Exit status. 0 when the App exists and its key is stored; 1 otherwise.
gh codecrew identity new implementer --name myorg-coder
gh codecrew identity new reviewer --name myorg-checker --with-approval-permission
gh codecrew identity webhook¶
Reads and sets an existing App's own hook, under the App's own key: --show
prints the URL, the content type, whether a secret is set and the App's
subscribed events; --url and --secret set them; --rotate-secret mints a
new secret, sets it and prints it once. An App hook covers every repository
its installation sees. Event subscriptions cannot be set after creation —
GitHub offers no endpoint — and the verb prints the settings page where they
are ticked.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--show |
none | off | Prints the hook's URL, content type, whether a secret is set, and the subscribed events. |
--url |
URL | none | Sets the receiver URL. |
--secret |
secret | none | Sets the hook secret to the receiver's. Never stored, never printed. Exclusive with --rotate-secret. |
--rotate-secret |
none | off | Generates a new secret, sets it, and prints it once. |
--events |
comma-separated events | none | Not settable after creation: the verb prints where they change, and what is subscribed now. |
Reads. The App's private key and credential stub — the environment
bindings first (GITHUB_APP_ID or GITHUB_CLIENT_ID, and GITHUB_PRIVATE_KEY
or GITHUB_PEM as PEM text or a path), else ~/.config/codecrew/<slug>; the
App's own record and hook configuration from GitHub. It reads no pointer and
runs from anywhere.
Writes. In GitHub: the App's hook URL and secret, where those flags are given. Nothing on disk. On stdout: the hook's configuration, and a rotated secret once.
Refusals. NO_CREDENTIALS — nothing to sign with:
no App id and key in the environment, and no key and stub under
~/.config/codecrew/. BAD_CREDENTIALS — GitHub
rejected the App JWT, or knows no App by the id it was signed as.
NO_WEBHOOK — the App was minted without a webhook and
GitHub's API cannot create one; the detail names the settings page. --secret
with --rotate-secret, and --events, exit 1 without a code.
Exit status. 0 when the hook was printed or set; 1 otherwise.
gh codecrew identity webhook myorg-coder --show
gh codecrew identity webhook myorg-coder --url https://example.test/hook --rotate-secret
gh codecrew identity token¶
Mints a short-lived installation token as the App and prints it alone on
stdout, with a receipt on stderr naming the slug, App id, installation and
account it minted for. Credentials come from the environment first, under the
names platforms bind, and otherwise from the key and stub under
~/.config/codecrew/ for the slug. It signs the App JWT, discovers the
installation from the App itself — one installation is taken, several narrow
to the hub's owner — and never writes gh's config. The <slug> argument
selects the key and stub under ~/.config/codecrew/ and is optional when the
environment binds an App id and key. It reads no pointer and runs from
anywhere.
Options
| Option | Argument | Default | Effect |
|---|---|---|---|
--installation |
id | GITHUB_INSTALLATION_ID, else none |
A hint, used only when the App can see that installation. |
Reads. GITHUB_APP_ID or GITHUB_CLIENT_ID, and GITHUB_PRIVATE_KEY or
GITHUB_PEM (PEM text or a path), then GITHUB_INSTALLATION_ID; failing
those, ~/.config/codecrew/<slug>.json and its private key. GitHub, for the
App's installations and the token. The pointer, only to learn the hub's owner
for narrowing, and never as a requirement.
Writes. Nothing on disk, and nothing in GitHub beyond the token GitHub mints. The token alone on stdout; the receipt on stderr.
Refusals. NO_CREDENTIALS — no App id and key in
the environment, and no key and stub under ~/.config/codecrew/.
BAD_CREDENTIALS — GitHub rejected the App JWT, or
knows no App by the id it was signed as.
NO_INSTALLATION — the App is installed on no account
its key can see. INSTALLATION_AMBIGUOUS — the App is
installed on several accounts and nothing selects one.
Exit status. 0 when a token was printed; 1 otherwise.
export GH_TOKEN=$(gh codecrew identity token myorg-coder)
gh codecrew identity token myorg-coder --installation 12345678
gh codecrew version¶
Prints the installed release tag and the protocol version it implements, as
<tag> (protocol <major.minor>). A build from source reports dev. The
shape is stable within a major.
Options. None. --version and -v are the same verb.
Reads. Nothing: no pointer, no network, no files.
Writes. Nothing. One line on stdout.
Refusals. None.
Exit status. 0.
Licensed under Apache 2.0.