Skip to content

Latest commit

 

History

History
570 lines (473 loc) · 29.9 KB

File metadata and controls

570 lines (473 loc) · 29.9 KB

Participants And Sessions

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.

Choose During Setup

After installing Code Mower, run this in the repository:

code-mower init --interactive

The 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 --apply

The 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.yml

Participant 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.

Start From Any Agent

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 codex

From 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_ID

Replace 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.

Bind One Work Item For Guided Context

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-123

The 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.json

The 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.json

The 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.json

When 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 42

The 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 claude

Both 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.

Find The Current Session

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/REPO

session 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.

Single Orchestrator Lease

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 --force

The 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.

Common Roles, Explicit Product Differences

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_v3

Both 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 --json

Replace 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.

Jira Tracker Contract

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 mutate or code-mower tracker pr-sync commands; see Jira Cloud Setup for the double write-guard.
  • At implementation start, the orchestrator previews and applies the configured in_progress claim/transition. When a non-draft PR is ready for human review, it previews and applies the ready_for_review PR-sync milestone, which uses the configured review transition.
  • 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 Orchestrator Posture

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.

Jira Access For Cursor

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.

Noninteractive CLI Readiness

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.

Remote Work (Contributor Checkout)

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 --apply

The 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 --apply

If 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.