Choose the tools you want to work with. Claude Code and Codex are the default pair; Devin and other participants are explicit additions. The agent hosting your conversation is the default orchestrator when its role is eligible.
The participant picker, host-led session brief, single-orchestrator lease,
shared Jira tracker brief, controller host telemetry, and explicit Cursor
qualification documented below are included in code-mower==1.6.0.
Install that pin when following release documentation, or use a
contributor checkout when testing later source changes. Role-specific admission
and startup lease commands described here are included in the same release;
the historical v1.4.0 artifacts remain unchanged.
After installing Code Mower, run this in the repository:
code-mower init --interactiveThe terminal shows checkboxes with Claude and Codex selected. Type a number to
toggle a participant, Enter to preview the configuration, or q to cancel.
For example, toggle 3 to add Devin. To choose and write the reviewable setup
in one pass, use code-mower init --interactive --apply.
Agents and scripts use the same selection model without a terminal:
code-mower init --with claude,codex,devin
code-mower init --with claude,codex,devin --applyThe generated .code-mower.generated/code-mower.yml contains the selected
reviewer profile and session_defaults.participants. Review and install it
with the generated support files following the first-audit guide.
Later changes can start from your existing config:
code-mower init code-mower.yml --interactive --apply
code-mower next-steps --config .code-mower.generated/code-mower.ymlParticipant selection configures review lanes and remembers session defaults.
Builder automation is enabled separately with the existing init --builders
flow after the first review works. Existing lane definitions and their promotion
flags are retained. The selected profile's active reviewer list changes to match
your selection: the preview explicitly lists removed reviewers and flags any
that currently have merge authority. Review those removals before installing the
generated files, since they change which reviewers the generated gate requires.
When editing interactively, known reviewers already active in the profile are
preselected alongside saved participants. Custom lanes absent from the picker
are still reported if the selection would remove them.
You can give the hosting agent this request:
Start a Code Mower session with Claude, Codex, and Devin on OWNER/REPO.
Check your role eligibility before becoming the orchestrator. If eligible, use
code-mower session start with your own --host identity, read the resulting
operating brief, and verify participant readiness before assigning work.
Keep one writer per branch and independent current-head peer reviews. Record
the lease session ID and release that exact lease when this session finishes.
If your orchestrator role is ineligible, report the diagnostic and hand off to
an eligible supervisor before coordinating changes.
From Codex, the corresponding command is:
code-mower session start --repo OWNER/REPO --with claude,codex,devin --host codexFrom Claude, only --host claude changes. The same convention works for
cursor, grok-bot, and antigravity under their existing repository policy.
Devin is qualified only for bounded builder work and informational review;
--host devin and a Devin orchestrator handoff are rejected before acquiring a
lease or saving a brief. Selecting Devin as a participant does not grant
orchestration authority. The same role check applies to --dry-run and
--no-lease: those modes remove mutation and lease acquisition, but they do
not let an ineligible host claim the orchestrator role. Use a qualified host to
render the read-only brief. The agent supplies its own
identity; the user does not have to choose the orchestrator every time.
Wrappers can set CODE_MOWER_HOST instead. A plain shell with no host context
requires an explicit host rather than guessing from installed CLIs.
Omit --with to reuse the repository's saved participants, or Claude + Codex
when no selection has been saved. An orchestrator can coordinate participants
without also being selected as a builder or reviewer. --orchestrator claude
explicitly requests a handoff to Claude if the session starts in another tool.
The command writes a local brief under .code-mower/sessions/ and reports its
path. session show PATH reads it; session start ... --dry-run previews it.
From anywhere inside the checkout, session show --current finds the brief the
live lease names without a filename (see Find The Current
Session). A successful mutating start takes a lease
with a default 12-hour lifetime. Human output lists the exact inspection and
release commands. Save the session ID and release the lease when work ends:
code-mower session lease show
code-mower session lease release --session-id SESSION_IDReplace SESSION_ID with the ID from this startup or lease inspection. A later
shell process should pass it explicitly; it cannot infer ownership from a
previous process. Releasing a lease does not cancel provider work. Quiesce any
active writer before an authorized handoff, and do not use --force as routine
cleanup.
This is an agent-coordinated session: the hosting agent drives work through
its available tools, manual handoffs, or Code Mower's existing dispatcher.
Creating the brief does not launch provider processes, authenticate tools, or
prove they are available. Readiness remains unchecked until the agent verifies
the chosen execution path. Live PR progress remains in code-mower lanes status.
When one authoritative work item will carry optional organizational context, select it as the mutating session starts:
code-mower session start --repo OWNER/REPO --host codex --work-item EXAMPLE-123The saved operating brief records only that a work item was selected. Its
identity and configured context policy live in protected local context state
outside the repository. Account/workspace identity, credentials, query text,
packets, citations, review findings, and future PR bindings are not added to the
brief. A read-only --no-lease session cannot bind work; --dry-run previews
the selection without writing private state.
Inspect the resumable lifecycle without displaying its private identifiers:
code-mower session context status .code-mower/sessions/SESSION.jsonThe closed status reports whether a work item and context are configured, the
current lifecycle stage, whether dependent work may continue, and the next
action. It rechecks the working copy's live lease and trusted repository context
configuration. A changed repository or connection fails closed and requires a
new session. Existing sessions without a selected work item report
not_selected; repositories without context report not_configured and keep
the ordinary workflow usable.
Prepare bounded evidence and its work order from the same session:
code-mower session context prepare .code-mower/sessions/SESSION.jsonThe default private search is the selected work-item identity, so a Jira key or
other authoritative ticket reference does not need to be copied into a request
file. To supply more precise retrieval language without placing it in shell
history or local state, pipe it with --query-stdin. An optional
--work-order-body-file supplies the local objective and acceptance criteria;
otherwise Code Mower creates a bounded generic work order for the selected
item. The hosting agent is the builder by default. Use --builder claude (or
another selected builder) when the orchestrator is handing implementation to a
different participant; review lanes then exclude that builder. --output
accepts a repository-relative path only.
The command rechecks the session lease and trusted context policy, authorizes
the calling Claude, Codex, or Devin host, fetches through the existing bounded provider
contract, drafts through the existing work-order contract, and saves only a
request hash plus opaque packet and work-order references in private session
state. Its output does not contain the work-item identity, query, connection,
account, packet handle, citations, or provider diagnostics. The work order is
local under .code-mower/ and names only the opaque packet needed by approved
participants. Custom private-state roots move any G1 flat session association
into the sessions/ namespace under the same protected locks when first read.
Repeating a completed prepare reauthorizes and reuses the packet without
another organization search. A packet retrieved before a local work-order
write was interrupted is also reused on resume. A search that failed or was
interrupted before its packet was recorded remains reserved; verify access and
rerun with explicit --refresh. Changed query text also requires --refresh.
Builder handoffs and refreshes write a new generated work-order path, preserving
the prior work order and any local edits. A crash after all work-order artifacts
were written reuses those matching artifacts rather than overwriting them.
Optional context failure leaves ordinary work usable, while required context
failure pauses dependent work. A session with no context provider reports
not_configured and keeps its ordinary workflow.
Deliver the prepared packet to the selected builder without copying its handle or constructing a private request file:
code-mower session context deliver .code-mower/sessions/SESSION.jsonWhen a pull request exists, bind that same protected session input to its current head:
code-mower session context attach .code-mower/sessions/SESSION.json --pr 42The attachment revision is reserved locally before GitHub is changed. A normal
retry reconciles the saved revision from trusted comments and never creates a
duplicate after success. An uncertain remote response pauses review; use
--retry-uncertain only after checking that the saved revision is not current.
The retry republishes that same revision. A new code head creates a new input
revision and needs a fresh independent review.
Running prepare while publication is pending or uncertain preserves the saved
intent and directs the session back to attach; it never drops the revision or
repeats provider authorization while publication recovery is unresolved.
After a selected Claude, Codex, or Devin reviewer finishes, give its private findings to the selected builder without copying the revision:
code-mower session context feedback .code-mower/sessions/SESSION.json \
--reviewer claudeBoth delivery commands write private content to stdout. Session status remains redacted and has closed states for pending or uncertain publication, expired evidence, failed authorization, attached input, and retrieved feedback.
A cold operator in a checkout does not need to know a session filename to ask "is there an active local Code Mower session here?":
code-mower session show --current
code-mower session lease show
code-mower lanes status --repo OWNER/REPOsession show --current resolves the working copy's live orchestrator lease to
its saved brief and prints that brief exactly as session show SESSION_FILE
would. It works from the repository root or any subdirectory and is strictly
read-only: it takes no lock, creates no directory, and renews nothing. It looks
only at .code-mower/sessions/<lease session id>.json (or the same filename
under an explicit --state-dir DIR for a brief that was saved elsewhere); it
never picks a file by modification time or scans another directory. The brief
must match the lease's repository, session id, and orchestrator, must not be a
symlink or escape the state directory, and the lease is re-read after the brief
so a takeover or expiry during the read is rejected.
The command exits zero only for one active, exact-matching brief. No lease, an
expired or malformed lease, a missing or mismatched brief, a symlinked brief, or
a lease that changed mid-read exit nonzero with one line of guidance -- for
example, a live lease whose brief is not in the default directory asks for the
session file or its --state-dir. --json also prints a closed
code_mower.currentSession.v1 diagnostic with the lease's state, provider, and
expiry and no session id or local path. session show SESSION_FILE is
unchanged; pass either the file or --current, not both.
lanes status includes the same metadata-only orchestrator_lease telemetry
(state, provider, expires_at) the Board shows, bound to the requested
--repo: a checkout leased for a different repository reports
other_repository. The remote-participant session status ALIAS command is
unrelated; it reports hosted session lifecycle, not the local checkout.
session start takes a local lease before it saves anything, so one repository
working copy has one mutating orchestrator at a time. The lease lives at
.code-mower/orchestrator-lease.json at the working-copy root (not under
.code-mower/sessions/, which only holds briefs), is written under a file lock
through a temporary file, and holds coordination metadata only: the repository
slug, the normalized orchestrator id, the session id, the acquired/renewed/
expires UTC timestamps, and a schema version. It is never uploaded or exported.
The maintained default lease duration is 12 hours. Renewal from another process uses the same live session ID, just like release.
A second agent that starts a mutating session while the lease is live is refused and told what the owner can do:
error: another session already holds the mutating orchestrator lease for owner/repo
holder: claude (session 4f1c...)
expires: 2026-01-01T18:00:00+00:00 (about 5h 42m left)
owner actions:
inspect it: code-mower session lease show
let its owner release: code-mower session lease release --session-id <id>
take it over on purpose: code-mower session lease release --force
read-only briefs need no lease: add --dry-run or --no-lease to session start
Manage the lease directly when a session ends or stalls (session lease show
reports the lease alone; session show --current resolves it to its brief):
code-mower session lease show
code-mower session lease renew --session-id <id>
code-mower session lease release --session-id <id>
code-mower session lease release --forceThe holding session renews with its own session id; the brief reports that id
and the expiry. A lease past expires_at is free again, so an abandoned or
crashed session recovers on the next session start with no owner action. An
expired lease is not renewed — start a fresh session instead. Taking over a
live lease is always explicit: session lease release --force, or
session start --force-lease, only after the owner decides the holding session
is gone.
Read-only work needs no lease. session start --dry-run previews a brief
without touching the lease, and --no-lease saves one for reading, planning, and
reporting. Both mark the brief "lease": {"state": "absent", "mutating": false}
and say so in the instructions. session show still reads briefs saved before
leases existed. The lease coordinates sessions only; it does not change the
one-writer-per-branch rule in the build loop, repository merge
policy, or the generated workflows.
| Concept | Rule |
|---|---|
| Participant | A selected product identity, independent of a particular execution transport. |
| Orchestrator | An eligible hosting agent; coordinates assignments, evidence, and recovery. |
| Builder | One writer per branch, using an available execution path. |
| Reviewer | An independent current-head verdict through a supported review lane. |
| Merge authority | Qualified role and repository policy; selecting or coordinating a tool does not grant it. |
Devin defaults to the local devin_cli transport and remains informational under
the starter policy. Select hosted Devin explicitly with --with devin_api_v3
(legacy devin_cloud is also accepted), or save the choice in the configuration:
session_defaults:
participants: [claude, codex, devin]
transports:
devin: devin_api_v3Both transports have product identity devin. Local review uses lane devin_cli;
hosted review retains lane devin and its existing labels. Aliases that name a
transport preserve it through setup and session creation. Selecting both
transports in one product session fails with a bounded selection message. An
existing recommended profile containing only the hosted lane retains that choice.
If both lanes are active, set session_defaults.transports.devin explicitly. That
setting is repository-wide: it applies to every profile, so align each Devin
profile's lanes with it, or leave it unset when profiles intentionally keep
different Devin transports and let each profile's lane declaration select its own.
Briefs expose an execution block with versioned capability metadata, unchecked
readiness, and explicit gaps. The modes describe maintained Code Mower paths:
| Capability | devin_cli |
devin_api_v3 |
|---|---|---|
| Coordinate | Agent handoff | Unavailable |
| Build | Local runner | External agent handoff |
| Review | Local runner | Evidence only |
| Message | Unavailable | Remote session |
| Cancel | Unavailable | Remote session |
| Authorized context delivery | Unavailable | Agent handoff (authorized packet in hosted builder input) |
| Structured results | Local runner | Remote session |
These declarations describe the current integration; they do not launch a
process, verify credentials, enable a session lifecycle, or confer merge
authority. Neither Devin transport has an orchestrator qualification; use a
qualified host such as Claude or Codex. Required work that depends on an
unavailable capability pauses. The same contract is reported by doctor and
specified in the packaged
provider_capabilities.schema.json.
One command reports the whole optional Devin setup for the selected posture:
code-mower doctor --profile recommended --devin --repo OWNER/REPO --jsonReplace recommended with the profile you selected; pinning it keeps the check
on that profile's Devin lane instead of another profile's.
It names the selected transport and its authentication, the create/view/manage
permissions the account owner must grant, the capabilities the transport does not
support, and the lifecycle recovery commands, without reporting credential
values, identities, the configured repository inventory, or raw provider output.
Repositories that never selected Devin get no Devin checks; --devin also lists
the local CLI, hosted API, and unavailable postures before selection. See
Troubleshooting for the
per-symptom next actions.
Legacy lane configurations infer product and transport in memory without
rewriting files. A legacy Devin lane with merge_authority: true and no explicit
product/transport declaration fails with instructions to set
merge_authority: false and informational: true. Explicit product/transport
fields or merge_authority: true do not qualify a Devin reviewer. Promotion
requires separately maintained evidence for that role and supported transport;
no such reviewer or orchestrator record currently exists. See
Participant Qualification for the shared
role_eligibility decision, narrowing policy, and future promotion contract. Contradictory driver/transport pairs or
capability overrides fail validation; remove capabilities to use maintained
defaults. The exceptions are the exact earlier maintained hosted declarations
(devin_api_v3 before remote-session message, cancel, and structured results,
with or without context: unavailable), which earlier templates wrote: they are
read as the current declaration in memory, again without file writes, and any
other deviation still fails. Keep provider: devin_cli for local execution and provider: devin
for hosted compatibility, with product: devin in both cases.
Devin Cloud needs its own execution setup. Cursor's agent and Cursor Bugbot are separate selections. Grok Bot retains its own identity; it is not silently translated into Cursor or Grok Build. Where there is no dedicated transport, the brief calls for an agent handoff and makes no automatic execution claim. Optional reviewer services such as Gitar cannot orchestrate or build.
Session selection uses the same participant definitions as installation. The reviewer registry and repository config continue to define execution and trust policy, so a new participant does not require another orchestration algorithm.
When the repository's tracker.kind is jira_cloud, session start adds a
tracker section to the brief. Codex and Claude, or any other selected
orchestrator host, receive the same rules from that section regardless of
which one calls --host:
- Code Mower's Jira REST transport is authoritative for queue reads and every Jira mutation.
- Atlassian Rovo MCP, if the host has it connected, is optional local read/context enrichment only. It has no queue or mutation authority.
- Every Jira write must go through the guarded
code-mower tracker mutateorcode-mower tracker pr-synccommands; see Jira Cloud Setup for the double write-guard. - At implementation start, the orchestrator previews and applies the configured
in_progressclaim/transition. When a non-draft PR is ready for human review, it previews and applies theready_for_reviewPR-sync milestone, which uses the configuredreviewtransition. - The brief names the configured Jira project by key or ID only. It never includes issue body text, comments, attachments, or credentials.
Sessions for the default GitHub tracker, or a repository with no tracker
block, omit this section entirely; existing GitHub-only briefs are unchanged.
Cursor is qualified as an interchangeable orchestrator host under the same participant session, controller-provider telemetry, and canonical working-copy lease contracts as Codex and Claude. Cursor-hosted sessions receive identical Jira tracker authority instructions when configured, and all controller events (queue snapshots, controller decisions, owner interventions, and merge decisions) correctly tag the orchestrator identity without changing policy decisions or tool provenance.
The official Atlassian MCP server provides optional local read and context enrichment when connected to Cursor. Broad Atlassian OAuth capability does not grant Code Mower mutation authority; the session brief and guarded tracker commands remain authoritative for every Jira mutation. Code Mower's Jira REST transport is authoritative for queue reads.
Cursor's noninteractive CLI requires authenticated and approved Atlassian MCP
plus read-tool auto-review (--auto-review) or an equivalent interactive
approval path. Without auto-review enabled, Cursor denies MCP read calls even
when the MCP server is authenticated. This is a host-readiness requirement,
not a Jira reliability issue.
Optional organizational context uses the context setup policy. Session briefs report redacted readiness and pause dependent work when required context is unchecked; account identity is never inferred from the host account.
session start continues to create an operating brief. The separate remote-work
commands use a private local alias, not a brief filename; they do not acquire,
renew, or confer a repository orchestrator lease. The coordinating host remains
responsible for that lease and one writer per branch.
Preview and dispatch a bounded task using a private UTF-8 file:
code-mower session dispatch example --provider fake --repo OWNER/REPO --input-file task.txt
code-mower session dispatch example --provider fake --repo OWNER/REPO --input-file task.txt --apply
code-mower session status example --provider fake
code-mower session message example --provider fake --request followup-1 --input-file message.txt --apply
code-mower session cancel example --provider fake --request cancel-1 --apply
code-mower session collect example --provider fake --applyThe default provider is the fully offline fake simulator. Select --provider devin for the reusable organization-scoped Devin v3 adapter. Live dispatch
requires existing Devin credentials and the exact repository acknowledgement
CODE_MOWER_DEVIN_REPOSITORIES; --max-acu-limit defaults to 10 (range 1–100).
Live Devin dispatch and new-work message also require --config code-mower.yml --runtime-readiness ready, supplied by the trusted supervisor
after checking the selected execution path. The same bounded builder decision
as the hosted work-order library runs before credential/prose/state access.
Omitted readiness, disabled policy, or missing/stale qualification rejects new
work. Preview retains its no-I/O behavior; status, collect, and cancel
remain available for existing bindings without these admission options.
There are no automatic provider mutation retries. Credentials are resolved for
each invocation and never saved in remote-session records. Keep the same
provider and organization on subsequent calls; changed bindings fail closed.
The fake provider persists its simulated remote state across CLI processes;
its Python set_state seam supports waiting, completion, and private-result fixtures.
All mutating commands default to preview; live mutations require --apply.
--dry-run is mutually exclusive with --apply and performs no input-file,
credential, state, or provider access. status performs provider reads only,
while saving observations/reconciled bindings locally under the lock. It may
therefore require writable private local state. status --dry-run performs
neither reads nor writes. collect --apply reads the provider and saves a
private result only after normalized completion; approval blocks collection.
It never prints result content. Repeated collection keeps the first result.
JSON metadata output is the same with or without --json.
The versioned code_mower.remote_session.v1 contract has a closed
public schema. Normalized states
include distinct waiting_for_user / user_input_required and
waiting_for_approval / approval_required pairs. Provider is the small
create/reconcile/get/message/cancel adapter seam; RemoteSessions.run is the
common lifecycle for both adapters. RemoteSessions.private_result(alias) is
an explicitly private local consumer API, never a telemetry source.
Devin can return a schema-bound private result while its resumable raw session
still reports running or waiting_for_user. The remote lifecycle treats that
result as complete. Explicit failure, suspension, and waiting_for_approval
remain authoritative even when an intermediate result exists. A result also
wins over terminated or archived, matching release-campaign collection. With
no result, provider-neutral status preserves those terminal states so operators
can distinguish them; collection returns no private result.
Storage defaults to ~/.local/share/code-mower/remote-sessions. An explicit
--remote-state-dir must be an absolute, owner-protected directory outside
Git repositories, without symlinks. Directories are mode 0700 and files 0600;
unsafe existing permissions, links, and unsupported file protection platforms
fail closed. Each alias has an OS lock and atomically replaced, fsynced state.
Provider bindings, account identifiers, request fingerprints, reconciliation
checkpoints, and private results stay there. Input prose is transient. Private
results are bounded to 256 KiB by the local store; oversized results fail closed.
A session accepts at most 128 message/cancel request keys.
Use the same alias and identical task/repository/budget to retry dispatch.
The intent is durably reserved before create; the Devin reconciliation tag is
fsynced before its paid POST. After a lost response or process death, status
or repeated dispatch only tries read-only reconciliation. A unique match
recovers the binding. No match, multiple matches, incomplete pagination, or
an intent without a checkpoint requires inspecting the provider account;
none authorizes another create. Preserve the original state. Only after
account inspection establishes that a separate dispatch is appropriate should
the operator deliberately choose a new alias (which can incur another charge).
There is no automatic abandonment, paid retry, or manual binding import.
Messages and cancellation require stable --request keys. A completed key
returns without repeating the mutation; a changed message under the same key
fails. An interrupted request blocks new message/cancel mutations. Check the
provider directly, then, only after confirming delivery/cancellation, acknowledge
that same request without replaying it:
code-mower session message example --provider devin --request followup-1 --acknowledge-delivered --apply
code-mower session cancel example --provider devin --request cancel-1 --acknowledge-delivered --applyIf delivery cannot be established, leave the request unresolved. Acknowledgement is an operator assertion, not a remote verification or approval grant.
Board/cloud consumers may use only public_projection: fixed schema,
normalized state, counters, and closed reason/next-action codes. Neither alias,
request keys, bindings, account IDs, task prose, provider messages, repository
paths, credentials, raw provider errors, nor results enter that projection.
These commands emit no Board/cloud events automatically. Future adapters must
bind the closed projection, never serialize a private record. The contract has
no Slack-specific fields and does not change release-campaign behavior or the
capability declarations for operating briefs.