Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Agent Coordinator CLI

The native agent-coordinator command connects an existing harness to one Agent Coordinator project. It stores no secret in the repository and never claims work as a side effect of connect.

Client compatibility and verified updates

client-info --json reports the CLI semantic version, exact source commit and repository, build cleanliness, OS/architecture target, supported protocol versions, and capabilities. compatibility --json anonymously reads the service’s /api/v1/info contract without credentials or redirects. It compares the exact source identity, target, protocol versions, and capabilities. The preflight runs before connect, task claims, and code submissions. A missing contract or mismatch returns client_upgrade_required; read-only diagnosis and safe handling of existing attempts remain available.

Use the full source commit and repository from client_compatibility.compatible_client. Prefer an artifact in verified_packages, which lists target, release identity, trusted download, and checksums. This deployment registers no prebuilt package, so the documented fallback is a clean locked build from the exact source commit. The restartable upgrade command verifies provenance, target, capabilities, and clean build identity, saves the previous binary as a rollback, and verifies the replacement. It does not move protected credentials, local sessions, or retry journals. See startup and client upgrade for complete commands and recovery steps.

Repository and credential configuration

Commit a non-secret .agent-coordinator.toml at the repository root:

service_url = "https://coordinator.example.com"
project_id = "project-id-from-the-operator"

The file also accepts an optional non-secret project_name credential directory selector. Tokens and unknown fields are rejected. Set the token in the process environment:

export AGENT_COORDINATOR_TOKEN='token-issued-by-the-operator'
export AGENT_COORDINATOR_ORIGIN='https://coordinator.example.com'

Or create credentials.toml under the platform’s private Agent Coordinator configuration directory. On Linux the default is $XDG_CONFIG_HOME/agent-coordinator/credentials.toml, or $HOME/.config/agent-coordinator/credentials.toml when XDG_CONFIG_HOME is unset. On Unix, AGENT_COORDINATOR_HOME overrides the directory for headless installs. The override is rejected on Windows because an arbitrary directory cannot be assumed to have a private user ACL; Windows uses the current user’s platform configuration directory.

[[credentials]]
origin = "https://coordinator.example.com"
token = "token-issued-by-the-operator"

On Unix, the CLI refuses a credential file readable by group or other users; set mode 0600. On Windows, keep the file within the current user’s protected profile and restrict its ACL to that user. The configured origin is matched exactly after normalization, so changing a repository binding cannot redirect an existing credential to another service.

Project credential directories and worktrees

To select a project-specific credential file, add a stable local directory name:

service_url = "https://coordinator.example.com"
project_id = "project-id-from-the-operator"
project_name = "Billing"

Replace <project_name> in these patterns with the binding’s exact selector, such as Billing. Files use the origin/token format above.

Platform/configurationWith project_nameWithout project_name (legacy)
Windows%APPDATA%/Agent Coordinator/<project_name>/config/credentials.toml%APPDATA%/Agent Coordinator/agent-coordinator/config/credentials.toml
Linux, absolute XDG_CONFIG_HOME set$XDG_CONFIG_HOME/agent-coordinator/<project_name>/config/credentials.toml$XDG_CONFIG_HOME/agent-coordinator/credentials.toml
Linux, XDG_CONFIG_HOME unset, empty, or relative$HOME/.config/agent-coordinator/<project_name>/config/credentials.toml$HOME/.config/agent-coordinator/credentials.toml
Unix, AGENT_COORDINATOR_HOME override$AGENT_COORDINATOR_HOME/<project_name>/config/credentials.toml$AGENT_COORDINATOR_HOME/credentials.toml

On Unix, a non-empty AGENT_COORDINATOR_HOME takes precedence over XDG/default lookup. Set it to an absolute private directory. This override is rejected on Windows. Keep Unix files at mode 0600; on Windows restrict the ACL to the current user and SYSTEM. An independently configured MCP host does not automatically read these CLI files.

project_name is a local selector, not a server project rename or an access restriction. Use a single portable directory name: no path separators, reserved Windows device names, or trailing dots/spaces. It is independent of the checkout folder and remains stable when creating or moving worktrees. Changing the server’s display name does not move credentials. Names are case-sensitive on Linux.

Example Windows paths for user marsh:

Checkout/worktreeBinding project_nameCredential file
C:/src/billingBillingC:/Users/marsh/AppData/Roaming/Agent Coordinator/Billing/config/credentials.toml
C:/src/billing-reviewBillingC:/Users/marsh/AppData/Roaming/Agent Coordinator/Billing/config/credentials.toml
D:/worktrees/billing-fixBillingC:/Users/marsh/AppData/Roaming/Agent Coordinator/Billing/config/credentials.toml
C:/src/inventoryInventoryC:/Users/marsh/AppData/Roaming/Agent Coordinator/Inventory/config/credentials.toml
C:/src/agent_coordinatorAgent CoordinatorC:/Users/marsh/AppData/Roaming/Agent Coordinator/Agent Coordinator/config/credentials.toml
Any checkout with the original two-field bindingomittedC:/Users/marsh/AppData/Roaming/Agent Coordinator/agent-coordinator/config/credentials.toml

Example Linux paths for user alex, with XDG_CONFIG_HOME and AGENT_COORDINATOR_HOME unset:

Checkout/worktreeBinding project_nameCredential file
/home/alex/src/billingBilling/home/alex/.config/agent-coordinator/Billing/config/credentials.toml
/srv/worktrees/billing-reviewBilling/home/alex/.config/agent-coordinator/Billing/config/credentials.toml
/home/alex/src/inventoryInventory/home/alex/.config/agent-coordinator/Inventory/config/credentials.toml
Any checkout with the original two-field bindingomitted/home/alex/.config/agent-coordinator/credentials.toml

For either Billing worktree, setting XDG_CONFIG_HOME=/srv/alex-config selects /srv/alex-config/agent-coordinator/Billing/config/credentials.toml. Setting AGENT_COORDINATOR_HOME=/srv/coordinator-private takes precedence and selects /srv/coordinator-private/Billing/config/credentials.toml.

Without project_name, existing shared-file lookup is unchanged. With it, a missing, invalid, or mismatched project file is an error; the client does not silently use the shared file and a different agent identity. Explicit environment credentials still take precedence: AGENT_COORDINATOR_TOKEN, then the protected MCP token configuration, then the selected file. Every credential is origin-bound. Independent worktrees still need distinct session names even when sharing a file.

Subagent identities and reviews

A human can enable Who may perform agent review? → Also allow a registered, non-contributing subagent in the project’s review settings or policy. The API field is allow_subagent_reviews; it defaults to false, and agents cannot change this permission. Policy changes invalidate existing candidates through the usual revision guards. Human review requirements remain unchanged.

Connect the parent normally, then use its public session ID from connect:

agent-coordinator --session billing-parent connect --harness codex --json
agent-coordinator --session billing-review-1 connect --harness codex --subagent reviewer --parent-session PARENT_SESSION_ID --json

The server assigns a durable subagent identity keyed by project, credential principal, and subagent name. Reuse the same --subagent name across that agent’s new sessions; its recorded contributions remain attached. Each new session has its own proof. A saved session resumes without repeating these options. Parent identity is immutable; ordinary parent sessions remain the same principal identity. Session adoption and the native MCP launcher preserve the registered identity.

Before a helper contributes under the parent’s task claim, the owning session must checkpoint with contributor_session_ids containing the helper’s registered session ID. For example, pass this body with the normal checkpoint command:

{"summary":"Register implementation helper before delegation","contributor_session_ids":["HELPER_SESSION_ID"]}

Claims, checkouts, and submissions also record their contributing sessions. The service rejects a contributing subagent across all sessions of its identity, both when claiming and deciding review. Ordinary sessions sharing the contributor principal remain ineligible. A review-only subagent must inspect the immutable candidate and evidence before deciding through the existing review workflow. A subagent shares its parent’s launch, so its review of that launch’s work must not assert review_independence distinct_launch; the service refuses that claim or decision with reviewer_shares_launch.

When automatic work is authorized and this policy option is enabled, a still-running parent that cannot independently review its own or a contributor’s submission should create or reuse its stable review-only subagent and spawn it without waiting for a second user prompt. A request to perform or spawn a review does not implicitly make the session review-only; only an explicit single-task, review-only, read-only, stop, or equivalent boundary does. After the child reports, its final message is an intermediate workflow event. The parent refreshes live state, advances any eligible integration or other required workflow step, and continues task selection. Review approval alone does not complete code work.

The service cannot wake a parent after its host turn ends. A harness that requires deterministic continuation must keep the parent turn active or automatically re-prompt it until there is no eligible work or a concrete required-input, access, policy, or capability blocker.

This option trusts the harness to keep distinct agent contexts and record every helper before it works. Shared credentials cannot prove independent reasoning or detect undeclared local edits. Use the default separate-principal policy when separate credentials are required. A new name is for a genuinely separate agent, never a way to erase contribution history.

Every independent harness must use a distinct, stable session name. Pass it on every ownership command or configure it in that harness’s environment:

export AGENT_COORDINATOR_SESSION='codex-task-42'

PowerShell:

$env:AGENT_COORDINATOR_TOKEN = 'token-issued-by-the-operator'
$env:AGENT_COORDINATOR_ORIGIN = 'https://coordinator.example.com'
$env:AGENT_COORDINATOR_SESSION = 'codex-task-42'

An environment token is used only when AGENT_COORDINATOR_ORIGIN independently matches the repository service origin. The session proof and pending request state are saved outside the repository in the platform configuration directory. Separate session names always select separate files and therefore cannot silently share attempt ownership.

Session state locations and diagnostics

By default, session JSON and lock files use the sessions child of the platform configuration directory: %APPDATA%/Agent Coordinator/agent-coordinator/config/sessions on Windows and $XDG_CONFIG_HOME/agent-coordinator/sessions (or the documented $HOME/.config fallback) on Linux. This state contains the random session proof and the exact pending mutation key and body, so it is private operational state, not a cache. Never place it in a repository or discard it to work around a lock or uncertain request.

A sandboxed or otherwise isolated runner can select its own protected, durable directory with global --state-dir ABSOLUTE_PATH or AGENT_COORDINATOR_STATE_DIR. The command-line value takes precedence. Keep the same location and --session name for that runner across restarts. The directory must be dedicated to Coordinator session .json and .lock files, must not be a link, and must not be a filesystem root. The CLI refuses a non-dedicated existing directory before changing its permissions. It applies mode 0700 to the directory and 0600 to files on Unix. On Windows it installs a protected DACL granting full control only to the directory owner and SYSTEM. This override affects session proofs and mutation journals only; credential lookup remains as documented above.

Diagnose local access without contacting or mutating the service:

agent-coordinator --session RUNNER_NAME session diagnose --json
agent-coordinator --session RUNNER_NAME --state-dir ABSOLUTE_PATH session diagnose --json

The report checks the resolved directory, session JSON readability, lock-file open/create and protection, and exclusive lock acquisition separately. It never prints the credential, session proof, or pending request body. State-access failures preserve operation, io_error_kind, and the native os_error_code when the operating system provides one, in JSON and human-readable output. lock_file_open and lock_file_protection mean the runner cannot safely use that location. lock_acquisition means another process currently owns the advisory lock, or the environment denied locking. A .lock filename normally remains on disk after a clean exit; its presence alone is not an active lock and deleting it does not safely resolve contention.

To move a session between two permitted locations, first stop every MCP/native writer for that exact session and reconcile any uncertain mutation with retry. Then copy it through the guarded migration command:

agent-coordinator --session RUNNER_NAME --state-dir NEW_ABSOLUTE_PATH session migrate --from-state-dir OLD_ABSOLUTE_PATH --session-writes-quiescent --json

Migration locks both locations, verifies the source belongs to the current origin, project, credential, and session name, rejects a source with a pending mutation, and writes the destination atomically. It makes no service request, does not renew authority, never overwrites destination session JSON, and leaves the source state in place for deliberate operator cleanup after verification. Run session diagnose against the destination before resuming writes, then use that one state location consistently. If the source has an uncertain mutation, resume the source location and run retry; never copy it manually or create a fresh session to bypass the journal.

For local development only, --allow-insecure-loopback permits http://localhost or a loopback IP address. Other HTTP origins are rejected. Redirects are never followed, and the CLI accepts only /api/v1 and /healthz request paths.

Adopt an existing MCP session

An authenticated MCP connection can coordinate work without this CLI. To perform local work using the same independently provisioned session, pause MCP writes and resolve any uncertain requests using their retained keys and bodies, then run:

agent-coordinator --session LOCAL_NAME session adopt-mcp --mcp-writes-quiescent --json

The trusted host must supply these full environment variables privately:

VariableValue
AGENT_COORDINATOR_MCP_TOKENExisting service credential
AGENT_COORDINATOR_MCP_SESSION_IDExisting unique harness session ID
AGENT_COORDINATOR_MCP_SESSION_PROOFExisting secret session proof
AGENT_COORDINATOR_MCP_URLExact bound origin followed by /mcp
AGENT_COORDINATOR_MCP_PROJECT_IDProject ID from the repository binding

These variable names and command arguments work on both supported operating systems. Use the host’s protected environment/secret facility; do not put values in command arguments, repository configuration, request JSON, logs or model output. The host supplies the same protected environment for subsequent CLI operations. The CLI accepts the origin-bound MCP credential when a regular CLI credential override is not configured, without copying that token into another store.

Adoption verifies the existing open remote session, credential and workstation, reads project orientation, and atomically stores private native session state. It does not register a session, claim work, renew a lease, or migrate the MCP pending-request journal. Repeating identical adoption is safe; conflicting local identity or pending native work is rejected. The –mcp-writes-quiescent flag is an explicit assertion that MCP writes are paused, not a remote locking mechanism. The default workstation is the local host identity; use –workstation only for an explicit identity already configured for this same workstation and harness.

After adoption, inspect the attempt and its current generation before local work. Serialize native and MCP mutations. If sharing protected session state is not possible, checkpoint and release through MCP before claiming through a separate CLI session. Never use another session’s task authority or bypass recovery.

Foundation workflow

Connect creates a harness session on its first run and reconciles the saved session on later runs. It returns the session and the bound project’s complete orientation packet:

agent-coordinator connect

List projects or tasks without reserving anything:

agent-coordinator projects list --limit 50
agent-coordinator tasks list --limit 50
agent-coordinator tasks list --limit 50 --cursor opaque-cursor-from-the-response

Human operators can archive a project, which hides it from projects list while keeping its tasks and records, and restore it later. Archiving is refused while a task is claimed or a review or integration is in flight; --project defaults to the bound project.

agent-coordinator projects archive --reason "Retired" [--project PROJECT_ID]
agent-coordinator projects list --archived
agent-coordinator projects restore --project PROJECT_ID --reason "Needed again"

Create requests read JSON from a file, which avoids shell-specific quoting. Project creation requires an authorized operator role and is normally performed through the human web interface; an ordinary agent credential receives a clear permission error and exit code 4.

agent-coordinator projects create --input new-project.json
agent-coordinator tasks create --input new-task.json
agent-coordinator.exe tasks create --input .\new-task.json

Use --input - to read a JSON object from standard input. Claiming performs the required acknowledgment for the exact complete orientation returned by connect, then submits one claim. It never acknowledges incomplete instructions.

agent-coordinator claim --next
agent-coordinator claim --task task-id --revision 4
agent-coordinator claim --mode recovery --task expired-task-id --revision 7

--mode work is the default. Recovery mode atomically claims an expired or revoked attempt for inspection; it does not permit edits until recovery resolve records the required saved-work and running-job checks. --next can select the next eligible item in either mode.

Lease and checkpoint operations name the attempt and ownership generation explicitly. Checkpointing does not renew a lease, and release does not mark a task complete.

agent-coordinator renew --attempt attempt-id --generation 2
agent-coordinator checkpoint --attempt attempt-id --generation 2 --input checkpoint.json
agent-coordinator release --attempt attempt-id --generation 2 --input release.json

checkpoint --push-wip first pushes the prepared worktree’s clean commit to the create-only ref refs/agent-coordinator/candidates/wip/<attempt>/<sha> (with the same secret scan and readback as a code submission), then records that SHA as the checkpoint’s revision. Under a candidate push helper (AGENT_COORDINATOR_CANDIDATE_PUSH_SOCKET), the helper chooses its own create-only ref refs/agent-coordinator/candidates/wip/<task>/<launch>/<sha>, which never touches the launch’s candidate ref. A recorded revision lets a later recovery rest on a SHA comparison by the service instead of on local attestations.

Worktrees

Before changing code, prepare and register a separate clean worktree. The CLI first checks that the named attempt and generation still grant current work authority. It then verifies that the source checkout is clean and has a Git remote matching the repository URL configured for the bound project. The project is never inferred from a directory name.

agent-coordinator worktree prepare \
  --attempt attempt-id --generation 2 \
  --source /srv/src/project \
  --path "/srv/worktrees/task 42" \
  --branch agent/task-42 --base origin/main
agent-coordinator.exe worktree prepare `
  --attempt attempt-id --generation 2 `
  --source 'C:\src\project' `
  --path 'C:\agent worktrees\task 42' `
  --branch agent/task-42 --base origin/main

The destination’s parent must exist, while the destination itself must be new. Before invoking Git, the CLI saves the exact source, destination, branch, base selector, resolved full base commit, attempt, and generation outside the repository. Repeating the same command reconciles that saved destination even if a branch such as origin/main later advances. Different arguments are refused. The command never resets, stashes, deletes, or cleans any checkout. It records the resolved per-worktree Git directory identity, full base commit, branch, path, workstation, and clean state with the service. A lost registration response remains a normal durable pending mutation and retry reuses its body and idempotency key.

Resources

Human administrators create canonical resource definitions through the web or administrative API. Agents can list those definitions and atomically reserve a complete set for their current attempt:

agent-coordinator resources list --limit 50
agent-coordinator resources reserve \
  --attempt attempt-id --generation 2 --input reservation.json
agent-coordinator reservations list --limit 50
{
  "items": [
    {"resource_id": "resource-id", "units": 1},
    {"resource_id": "second-resource-id", "units": 2}
  ]
}

The reservation is all-or-none. An expired attempt, disconnected observer, or missing heartbeat does not release a physical resource. Once every attached job has a terminal producer result, the owning agent can release it explicitly:

agent-coordinator resources release \
  --reservation reservation-id --generation 2 \
  --reason "All attached producers have exited"
agent-coordinator.exe resources release `
  --reservation reservation-id --generation 2 `
  --reason 'All attached producers have exited'

reservations release is an equivalent spelling. Uncertain physical resources require an explicit human resolution through the web or administrative API.

Durable local jobs

jobs run accepts a local program and argument vector from JSON. It requires a held reservation and the worktree prepared for the same current attempt. The worktree must be clean at a committed revision; the job record captures the full commit and tree identities before registration.

{
  "label": "workspace tests",
  "program": "/home/agent/.cargo/bin/cargo",
  "argv": ["test", "--workspace", "--locked"],
  "environment": {
    "PATH": "/home/agent/.cargo/bin:/usr/local/bin:/usr/bin:/bin",
    "HOME": "/home/agent",
    "CARGO_HOME": "/home/agent/.cargo",
    "RUSTUP_HOME": "/home/agent/.rustup",
    "TMPDIR": "/tmp",
    "CARGO_TERM_COLOR": "never"
  },
  "check_identity": "workspace-tests",
  "check_version": "v1",
  "check_environment": "linux-x86_64",
  "log_limit_bytes": 1048576
}
agent-coordinator jobs run \
  --attempt attempt-id --generation 2 \
  --reservation reservation-id \
  --checkout "/srv/worktrees/task 42" \
  --input job.json

PowerShell uses the same JSON shape; program must be an absolute native path:

{
  "label": "workspace tests",
  "program": "C:\\Users\\agent\\.cargo\\bin\\cargo.exe",
  "argv": ["test", "--workspace", "--locked"],
  "environment": {
    "PATH": "C:\\Users\\agent\\.cargo\\bin;C:\\Windows\\System32",
    "USERPROFILE": "C:\\Users\\agent",
    "CARGO_HOME": "C:\\Users\\agent\\.cargo",
    "RUSTUP_HOME": "C:\\Users\\agent\\.rustup",
    "SystemRoot": "C:\\Windows",
    "TEMP": "C:\\Users\\agent\\AppData\\Local\\Temp",
    "TMP": "C:\\Users\\agent\\AppData\\Local\\Temp"
  },
  "check_identity": "workspace-tests",
  "check_version": "v1",
  "check_environment": "windows-x86_64-msvc",
  "log_limit_bytes": 1048576
}
agent-coordinator.exe jobs run `
  --attempt attempt-id --generation 2 `
  --reservation reservation-id `
  --checkout 'C:\agent worktrees\task 42' `
  --input .\job.json

Before registration or launch, the CLI durably saves random job, producer, runner, and reporter identities. It then stores the scoped reporter bearer only in the protected local job file. The detached guardian and producer clear their inherited environment, retaining only PATH, SystemRoot, WINDIR, TEMP, TMP, TMPDIR, SSL_CERT_FILE, and SSL_CERT_DIR when present. The producer also receives the environment explicitly listed in the JSON file, overriding those defaults. AGENT_COORDINATOR_* and COORDINATOR_* variables are rejected. Raw arguments, environment, and logs are never uploaded. Output and error streams stay in separate, bounded, protected local files shown by jobs inspect. Set log_limit_bytes to 0 to discard both streams; the maximum is 67108864 bytes per stream.

Replace the example environment values with the workstation’s actual trusted paths. Configure additional values the program and its children require, such as PATH, the user profile, toolchain directories, temporary directories, and Windows SystemRoot. Do not copy coordinator token, origin, session, or proof variables into this map.

To allow bounded attempt renewal while the job runs, name the exact current harness process and a server-limited window:

agent-coordinator jobs run ... --renew-for-seconds 1800 --watch-pid 12345

Renewal stops when that exact process exits, its authority expires, or the window ends. Job observation may continue after renewal stops. Omitting those options runs and reports the job without delegated attempt renewal.

Use the returned job ID for later inspection. Remote status and list commands do not launch or reconnect any producer:

agent-coordinator jobs list --limit 50
agent-coordinator jobs status --job job-id
agent-coordinator jobs inspect --job job-id
agent-coordinator jobs reconnect --job job-id

jobs inspect reads protected local state. jobs reconnect starts a detached observation-only guardian and works while the service is temporarily unavailable; pending observations remain durable for later delivery. It never launches a producer. If a durable launch intent exists without a recorded process identity, the state becomes unknown and the guardian refuses to launch again. A missing local journal is also treated as uncertain because the producer may already have run. PID alone is never used as producer identity.

The three check_identity, check_version, and check_environment fields are optional for ordinary jobs and must be supplied together. For a required integration check, copy the exact tuple from the project’s human-managed workflow policy and add --activity so the CLI verifies that the checkout is at that activity’s exact prepared result:

agent-coordinator checks list

agent-coordinator jobs run \
  --activity integration-activity-id \
  --attempt integration-attempt-id --generation 1 \
  --reservation reservation-id \
  --checkout "/srv/worktrees/integration 42" \
  --input required-check.json

Omit all three check fields for an ordinary producer. The service creates check receipts from registered terminal jobs. A later integration command selects those receipts by job ID; the CLI never accepts a caller-authored pass result.

Immutable submissions

Submission evidence JSON contains only the bounded result narrative. Every current acceptance criterion must appear exactly once:

{
  "summary": "Implemented and validated the requested behavior.",
  "acceptance_evidence": [
    {
      "criterion": "The exact criterion text from the task",
      "evidence": "The exact behavior and check that demonstrate it"
    }
  ],
  "handoff": "Review the candidate and its registered job evidence."
}

For code work, the CLI reads the repository, base commit, candidate commit, and candidate tree from the attempt’s registered, clean prepared worktree. These fields cannot be supplied through JSON:

agent-coordinator submissions code \
  --attempt attempt-id --generation 2 \
  --task-revision 4 --project-policy-revision 3 \
  --workflow-policy-revision 2 \
  --checkout "/srv/worktrees/task 42" \
  --candidate-ref refs/agent-coordinator/candidates/submission-id \
  --input submission.json
agent-coordinator.exe submissions code `
  --attempt attempt-id --generation 2 `
  --task-revision 4 --project-policy-revision 3 `
  --workflow-policy-revision 2 `
  --checkout 'C:\agent worktrees\task 42' `
  --candidate-ref refs/agent-coordinator/candidates/submission-id `
  --input .\submission.json

The service requires the attempt to be current and quiescent: release its reservations after every attached producer is terminal before submission. Submission ends the implementation attempt and creates the review and integration activities required by the pinned policies. It does not itself mark a code task complete.

A code submission checkpoints the candidate before sending the submission mutation. The CLI pushes the exact clean commit to a create-only ref on the configured project remote, fetches that exact ref into an isolated verification namespace, and compares both the fetched commit and tree with the registered worktree. If verification fails, no submission or review activity is created. If --candidate-ref is omitted, the CLI creates the stable ref refs/agent-coordinator/candidates/ATTEMPT_ID. Caller-selected refs must use the refs/agent-coordinator/candidates/ namespace. An existing ref is accepted only when it already names the exact same commit; the CLI never moves a prior candidate ref.

Before creating the ref, the CLI scans the patch of every commit it would push (reachable from the candidate but not from the remote’s advertised commits) for likely secrets: common cloud, GitHub, model-provider and chat token shapes, private key blocks, credential files such as credentials.toml, .env or *.pem, and the caller’s own coordinator token. A match refuses the push and names each rule, commit and path without echoing the secret; remove the secret from history (not only from the latest commit) and submit again. Supervised agents cannot run git push directly, so this scanned push is their only route to the remote.

When AGENT_COORDINATOR_CANDIDATE_PUSH_SOCKET names a Unix socket, the CLI does not push itself: a per-launch candidate push helper listening on that socket holds the push credential and writes only its own fixed candidate ref. The value is trimmed; an unset, empty or whitespace-only value keeps the direct push, and any other value must be an absolute UTF-8 path (exit 2 otherwise). Setting it on a platform without Unix sockets is also invalid input. The CLI captures the clean snapshot and scans every commit carried by the bundle, including intermediate commits and the caller’s own coordinator token, before sending anything. The launch’s base commit must exist locally: it bounds that preliminary scan and is the bundle prerequisite. The trusted helper independently scans the complete outgoing history against the authenticated remote’s advertised refs; the client’s base cannot exclude history from that authoritative scan.

The helper confirms the published remote ref names the requested commit, whose tree it verified when importing the bundle, and returns the exact commit, tree and ref in its receipt. The CLI validates that receipt and rechecks the unchanged clean local snapshot before recording it. The host-managed per-launch socket is the trust boundary for this remote evidence. Neither candidate nor WIP helper checkpoints contact the remote from the sandbox or require GitHub credentials there. Direct checkpoints retain their own remote scan and fetch verification. The helper chooses the ref, so --candidate-ref is refused with candidate_ref_fixed_by_helper before anything is sent.

Helper failures use these codes:

CodeExitRetryableMeaning
candidate_push_refused5 for lease_conflict and candidate_already_published, 7 for push_failed and internal, 2 otherwiseonly push_failed and internalThe helper refused; details.refusal_code holds its code and the message is the helper’s, with control and bidirectional formatting characters replaced by spaces. lease_conflict means the ref is not one this helper pushed. candidate_already_published means this helper already published a different commit: each launch’s helper publishes one candidate commit.
candidate_push_unavailable7yesConnecting to the socket fails.
candidate_push_failed7yesA read from or write to the connected socket fails, or the helper closes the connection without replying. A retry is safe: the helper accepts a ref that already names the same commit.
candidate_push_protocol_violation5noThe helper’s reply is malformed or acknowledges another commit, tree or ref.
invalid_client_input2noThe checkout cannot be scanned or bundled, it adds a likely secret, or the base commit is missing.

The immutable submission records the credential-free canonical project remote identity and exact candidate ref in addition to commit and tree IDs. The remote URL itself comes from project configuration; credentials are never stored in the candidate identity. Keep the ref available through review and integration. Native reviews claim and integrations claim fetch and verify the recorded ref from the configured remote before claiming code work. Integration preparation fetches and checks the ref again before creating its result or publication intent. A missing, moved, or mismatched ref fails safely with an actionable error; restore the exact ref, or revise a legacy submission with agent-coordinator revise --reason-code candidate_missing (or ask an operator to reopen it).

Use an independent clone to confirm the checkpoint is available on another workstation before review. After workflow completion, remove only the exact candidate ref after checking its observed commit and confirming no review, integration, or recovery operation still needs it. Use an expected-value --force-with-lease for cleanup; never delete a moved ref.

General work uses the same evidence JSON without any Git fields:

agent-coordinator submissions general \
  --attempt attempt-id --generation 1 \
  --task-revision 2 --project-policy-revision 3 \
  --input submission.json

The CLI fixes the workflow-policy revision to zero for general work. A general task with no configured review completes atomically; otherwise it waits for its new immutable-submission review activities.

Review activities

List the current subject workflow, then claim one exact agent-review activity. A review list grants no ownership:

agent-coordinator reviews list --task subject-task-id
agent-coordinator reviews status --activity review-activity-id
agent-coordinator reviews claim \
  --activity review-activity-id --submission submission-id \
  --project-policy-revision 3 --workflow-policy-revision 2

Add --review-independence distinct_launch (or distinct_host, distinct_vendor) to assert the review’s independence at claim. With distinct_launch the service refuses (reviewer_shares_launch) a reviewer session whose launch, the root of its parent-session chain, is also the launch of a recorded contributor to the subject or its landing range; record the same value as review_independence in the decision. Omit it to keep the ordinary contributor checks only.

The returned attempt ID and generation are required for renew, release, and decision commands:

agent-coordinator reviews renew \
  --activity review-activity-id \
  --attempt review-attempt-id --generation 1
agent-coordinator reviews release \
  --activity review-activity-id \
  --attempt review-attempt-id --generation 1 \
  --input release.json

Activity release JSON uses the activity-specific handoff contract:

{
  "summary": "Saved work and evidence are ready for the next owner.",
  "blocked": false
}

A review decision JSON contains only the decision evidence:

{
  "decision": "approved",
  "summary": "The candidate satisfies the acceptance criteria.",
  "findings": [
    {
      "severity": "advisory",
      "remedy": "Consider simplifying the helper in a later change.",
      "evidence": "The current form is correct and covered by the registered check."
    }
  ]
}
agent-coordinator reviews decide \
  --activity review-activity-id \
  --attempt review-attempt-id --generation 1 \
  --submission submission-id --input review.json

decision is approved or changes_requested; finding severity is required or advisory. An agent command cannot record a human-only review. Under the Independent agent or human project policy (review_mode: "either"), reviews list, status, claim, and decide also handle the shared either_review activity. An independent agent uses these same commands; a human uses Start human review in the dashboard, which claims the review only when the decision is recorded. One approval is sufficient, and only one session can own the review at a time. A changes-requested decision requires a new submission. Independent agent and human (both) still requires both approvals. Changing project review policy reconciles submissions still in review: newly required reviews are added and reviews no longer required are canceled if still queued; candidates are not made stale. The service checks the authenticated principal and independent contributor history, so changing a token or session cannot turn a contributor into an independent reviewer.

Integration activities

After every required approval and any human publication authorization, list and claim the exact integration activity:

agent-coordinator integrations list --task subject-task-id
agent-coordinator integrations status --activity integration-activity-id
agent-coordinator integrations claim \
  --activity integration-activity-id --submission submission-id \
  --project-policy-revision 3 --workflow-policy-revision 2

Prepare and register a separate worktree for the returned integration attempt, using the observed full target commit as its base. Then prepare the deterministic candidate-containing result:

agent-coordinator worktree prepare \
  --attempt integration-attempt-id --generation 1 \
  --source /srv/src/project \
  --path "/srv/worktrees/integration 42" \
  --branch agent/integrate-42 \
  --base 0123456789abcdef0123456789abcdef01234567

agent-coordinator integrations prepare \
  --activity integration-activity-id \
  --attempt integration-attempt-id --generation 1 \
  --submission submission-id \
  --checkout "/srv/worktrees/integration 42" \
  --expected-target 0123456789abcdef0123456789abcdef01234567 \
  --candidate 89abcdef0123456789abcdef0123456789abcdef
agent-coordinator.exe integrations prepare `
  --activity integration-activity-id `
  --attempt integration-attempt-id --generation 1 `
  --submission submission-id `
  --checkout 'C:\agent worktrees\integration 42' `
  --expected-target 0123456789abcdef0123456789abcdef01234567 `
  --candidate 89abcdef0123456789abcdef0123456789abcdef

Preparation checks fresh activity and attempt authority before local Git work, persists the exact request before creating the result, registers immutable publication intent with the exact prepublication target revision and tree before any push, and materializes the result in the isolated checkout for exact-source checks. It never updates the target branch.

Run every required check against that materialized checkout, wait for terminal successful job receipts, and release the check reservations. The checkout must remain clean at the exact prepared result. Publish with:

agent-coordinator integrations publish \
  --activity integration-activity-id \
  --attempt integration-attempt-id --generation 1

Immediately before Git starts, the library observes the configured remote, calls the service for fresh exact activity, candidate, intent, and remaining lease authority, observes the remote again, durably records push intent, and uses Git’s exact force-with-lease compare-and-swap. A moved target is reported without publishing. Once push intent is durable, a retry is observation-only and never repeats an uncertain push.

After interruption, inspect the remote without any publication capability:

agent-coordinator integrations reconcile \
  --activity integration-activity-id \
  --attempt integration-attempt-id --generation 1

This local reconciliation can confirm the exact prepared result, report that the target moved, or preserve an uncertain outcome. It observes the configured remote and uses the exact immutable local intent; it never publishes.

When the saved intent and local journal are available, the prior publisher is confirmed stopped, its integration ownership is expired or revoked, current policy and decisions still match, and no live/uncertain jobs or held reservations remain, an agent can record only an exact observation of the saved base or exact intended result:

agent-coordinator integrations reconcile-agent \
  --activity integration-activity-id \
  --attempt integration-attempt-id \
  --generation 1 \
  --publisher-stopped \
  --evidence 'Previous publisher exited and released its journal lock'

The command obtains the local journal lock, compares its intent with the current service submission, and freshly observes the configured remote before saving the exact request and idempotency key. A moved target, unavailable or mismatched journal, active publisher, live job, held reservation, or uncertain outcome retains the integration hold for human reconciliation. The service records this workstation evidence as an attestation; it does not inspect Git or prove process termination independently.

If the remote moved to an object the trusted checkout does not contain, fetch that exact remote target ref into the checkout and reconcile again so its tree can be observed before a human records evidence. If the target ref was deleted, stop and have an operator restore or repair it; do not substitute a zero commit or continue the normal integration workflow.

When publication is confirmed, finish with an exact set of successful registered check jobs:

{
  "submission_id": "submission-id",
  "check_job_ids": ["job-id-linux", "job-id-windows"],
  "summary": "The exact integrated result passed the pinned check roster."
}
agent-coordinator integrations finish \
  --activity integration-activity-id \
  --attempt integration-attempt-id --generation 1 \
  --input integration-finish.json

finish first registers the immutable integration result with those job IDs. It then observes the configured remote again and asks the service to finalize the exact published commit and tree. The service resolves job IDs to terminal producer receipts and checks the pinned identity/version/environment roster; the JSON cannot fabricate a result. Finalization atomically completes the integration activity and subject task and releases the canonical target hold. Use integrations renew and integrations release with the same argument shapes as their review equivalents while the activity remains owned. A release never clears an uncertain publication hold.

Revise, unblock, cancel, archive, restore and delete

When the project delegates them, agents move stuck work forward without a human:

agent-coordinator revise --task TASK_ID --submission SUBMISSION_ID \
  --reason-code conflict --reason "Target moved" --evidence "CONFLICT in src/lib.rs"
agent-coordinator unblock --task TASK_ID --expected-revision 7 --reason "Resource now exists"
agent-coordinator cancel --task TASK_ID --expected-revision 7 --reason "Wrong kind" \
  --replacement NEW_TASK_ID
agent-coordinator archive --task TASK_ID --expected-revision 7 --reason "Obsolete"
agent-coordinator restore --task TASK_ID --expected-revision 8 --reason "Needed after all"
agent-coordinator delete --task TASK_ID --expected-revision 7 --reason "Created by mistake"

revise reopens the current submission through workflow/reopen and needs recovery_mode=agent. Reason codes: conflict and check_failed (the session owning the live integration attempt, with evidence), candidate_missing (any agent, when the code submission has no durable ref), requirements_changed (a non-contributor, when the task’s judged fields changed) and author_withdraw (the author). At most three agent revises per task in 24 hours; the fourth returns revise_limit_reached for a human. unblock needs recovery_mode=agent and cancel of a human-created task needs agent_rule_editing; otherwise both are human gates. cancel, archive, restore and delete each take --task, --expected-revision and --reason (cancel also takes --replacement) and accept --json. They send POST .../tasks/{id}/{cancel,archive,restore} and DELETE .../tasks/{id} through the durable mutation journal, so an interrupted call is replayed by retry with the same idempotency key.

Who may use them depends on the task’s origin, which tasks show prints (Origin: in the human output, data.origin in --json). An agent session may use all four on a task whose origin is agent or service (for example canary or e2e tasks) without any project delegation. On a human-origin task an agent may only cancel, and only when the project delegates agent_rule_editing; archive, restore and delete there are human gates. Revert tasks follow the same rule by their own origin (the creator’s, or service for an automatic revert), except that an agent that contributed to the reverted change (the reverted task or any task in the revert’s landing range, or a session of a contributor’s launch) is refused cancel and archive of the revert with revert_author_conflict: an independent agent or a human must do it. Humans may use all four on any task. The service also refuses, for every actor: task_revision_changed (reload with tasks show), task_attempt_protected (a live attempt owns the task), task_workflow_protected (review or integration work is active), task_archived (restore the task first), task_lifecycle_invalid (the state does not permit the action) and task_history_protected (delete of a task with attempts, dependencies, objective links or workflow links: archive it instead). The human output adds a one-line hint for each of these codes.

A refusal that only a human can clear carries details.required_actor: "human" and a details.gate name: report it instead of retrying.

Recovery inspection

Inspect the expired attempt, its registered checkout, jobs, and resource holds, then record one explicit disposition from a JSON file:

agent-coordinator recovery inspect --attempt expired-attempt-id
agent-coordinator jobs list --limit 50
agent-coordinator reservations list --limit 50
agent-coordinator recovery resolve \
  --attempt recovery-attempt-id --generation 3 --input recovery.json
{
  "saved_work_checked": true,
  "running_jobs_checked": true,
  "disposition": "resume",
  "summary": "The exact producer is terminal and the saved commit was inspected."
}

When the expired attempt’s latest checkpoint recorded a revision, fetch its WIP ref and send the fetched SHA as fetched_revision instead of the two *_checked attestations. The service cannot read Git; it only checks that the value equals the recorded SHA (recovery_revision_mismatch otherwise), so confirm the fetched ref names it before sending. A match returns "evidence": "service_verified". The resolution’s own checkpoint records no revision, so recovering that attempt later needs the attestations. A legacy checkpoint without a revision still needs both attestations and returns "evidence": "local_attestation". Use the disposition and inspection fields required by the current service orientation and attempt detail. Recovery does not cancel or restart jobs and does not clear a resource merely because an observer or lease expired.

The bounded generic command covers another implemented foundation API path without inventing commands for future workflow surfaces:

agent-coordinator request --method get --path /api/v1/projects
agent-coordinator request --method post --path /api/v1/projects/project-id/claims --input claim.json

Add --json for the complete compact service envelope. The default presents concise tables and labeled summaries while preserving full instructions during connect.

Interrupted mutations

Before every POST or PATCH, the CLI durably stores its method, path, JSON body, and newly generated idempotency key. A transport failure, redirect, rate limit, or server failure leaves that exact request pending and blocks unrelated writes in the same harness session. Resolve it with:

agent-coordinator retry

retry sends the saved body with the saved key. It never manufactures a new key after a response may have been lost. A definitive success or client/state error clears the pending request. Claim and renewal replay output is passed through unchanged, including the service’s fresh current_authority; callers must not treat timing from the original receipt as current authority.

Exit codes are 0 for success, 2 for invalid input, 3 for authentication or setup required, 4 for denied operations, 5 for state or ownership conflicts, 6 for unsatisfied requirements, and 7 for transport or temporary service failures.

Repository bootstrap text

Repositories can place this short bootstrap in AGENTS.md, CLAUDE.md, or the equivalent harness instruction file after the CLI workflow has been installed:

This project coordinates work through Agent Coordinator.
Read .agent-coordinator.toml and run `agent-coordinator connect --json` with a
stable session name unique to this harness. Read the complete orientation and
all required instruction sections before claiming work. Reconnect or show the
returned setup/error details when coordination is unavailable; do not silently
fall back to uncoordinated work. Claim a task before changing code, then renew,
checkpoint, and release it with its exact attempt ID and ownership generation.

Shared knowledge, decisions, and Markdown records

These commands operate on the bound project. All writes use the existing protected session journal and retain the exact request and key for retry. JSON input is limited to 1 MiB. Read results use human-readable output by default; --json preserves the complete response envelope and cursor.

agent-coordinator knowledge list --limit 50
agent-coordinator knowledge show --id LESSON_ID
agent-coordinator knowledge create --input lesson.json
agent-coordinator knowledge edit --id LESSON_ID --input correction.json
agent-coordinator knowledge feedback --id LESSON_ID --input feedback.json
agent-coordinator context --query "producer identity" --budget 65536
agent-coordinator context --query "cache" --component compiler --include-shared
agent-coordinator decisions list
agent-coordinator decisions show --id DECISION_ID
agent-coordinator decisions create --input decision.json
agent-coordinator decisions answer --id DECISION_ID --input answer.json
agent-coordinator decisions reopen --id DECISION_ID --input reopen.json

For example, lesson.json contains:

{
  "kind": "lesson",
  "title": "Check the producer before repeating a test",
  "body": "A missing observer does not prove that its producer stopped.",
  "status": "observed",
  "scope": {"components": ["test-runner"]},
  "tags": ["recovery"],
  "applicability": "When reconnecting after an observer disconnects",
  "provenance": {"summary": "Observed during task recovery; retain the source revision here"}
}

Corrections include expected_revision and the new title, body, status, scope, applicability, tags, and provenance. Prior revisions remain available. Explicit cross-project sharing requires collection: "shared" and share_across_projects: true when creating the record; access to all projects does not automatically share every lesson. Search treats input as plain words, returns complete binding rules, and enforces its byte budget. A budget too small for the rules returns an explicitly incomplete packet and asks for a larger budget. Scope filters include --task-id, --component, --environment, and --version.

Decision creation records the required actor type, exact affected task revisions, project policy revision, options, environment, conditions, and optional expiration in Unix milliseconds. An answer must exactly match an option and include a typed disposition (allow, deny, or defer), rationale, and expected_generation. Only an allow with conditions_confirmed: true can satisfy the work gate. A changed task/policy, expired answer, denial, or deferral keeps work blocked until an authorized reopening and answer. Agent credentials cannot answer decisions requiring a human on their own; a human answers them in the dashboard, or an agent relays the human’s reply (below).

Relaying a human’s answer. When a project’s human has enabled allow_relayed_human_answers in its policy (human-only, dashboard project policy), an agent session may record the reply a human gave it in the agent’s own interface. Read decisions list --json (question, options, rationale, conditions, environment, generation), ask the user, then add the evidence to the answer JSON:

"relay": {"prompt": "the question exactly as asked", "response": "the user's reply exactly as given"}

The answer is stored with relayed: true, the relaying actor_session_id, the verbatim prompt and response, and the human principal and policy revision that enabled relaying (answer.relay, and relay in each history entry). The dashboard marks relayed answers and a human can reopen the decision. Without relay, or with the switch off or a stale expected_generation, an agent answer to a human-required decision is still refused (operation_not_permitted or generation_conflict). relay is rejected on decisions that do not require a human. Decision answers do not change project permissions or replace integration authorization.

Submissions may include lessons and artifact_ids in their evidence JSON. Each new lesson uses the lesson fields above, with provenance_summary in place of provenance; the service supplies its task and immutable submission source. The submission, handoff, original lesson revisions, and finalized artifact references commit together. Later lesson corrections preserve the original submission snapshot.

agent-coordinator imports preview --input source.json
agent-coordinator imports show --id PREVIEW_ID
agent-coordinator imports apply --id PREVIEW_ID --input apply.json
agent-coordinator export --json --limit 50

Import requests supply source (stable context, Git revision, observation time, branch, environment), bounded chunks containing arbitrary source paths and Markdown text, and optional explicit historical_mappings. The service never reads workstation paths. Agent credentials may preview and export; applying historical migration requires a human session in the dashboard, because checked source items create historical closure outside the live completion workflow. Inspect the preview’s proposed records, conflicts, unresolved links, and digest before applying it. The apply request contains preview_digest and expected_project_event_revision from that exact preview; intervening service changes require a fresh preview. Ordinary prose remains historical context, unchecked checklist tasks start planned, and completed imported items retain closure. Imported agent guidance never adopts binding rules. See import contract for source identities and limits.

Export without --json prints generated Markdown and the next cursor, when present. JSON output separates data.markdown and data.next_cursor for scripts. Pass --cursor to continue; a changed snapshot requires restarting the export. Generated exports contain provenance and cannot be imported over authoritative records. The dashboard can download a consistent snapshot up to 16 MiB; larger exports should be collected as bounded CLI pages.

For uploaded evidence, first reserve exact size and SHA-256 using artifacts reserve --input reservation.json, then run artifacts upload --id ARTIFACT_ID --file report.txt. Repeat the same command after an interrupted request; its protected journal keeps exact bytes and the original key. A completed retry authenticates again and reports current availability; it does not upload again. Download with artifacts download --id ARTIFACT_ID --output new-report.txt; the destination must not exist. Downloaded size and SHA-256 are verified before publishing the file. Transfers are bounded to 16 MiB and ordinary JSON responses are bounded to 16 MiB. Use --json for the full transfer receipt.

Connected sessions

Host storage maintenance closes sessions idle for 7 days by default (see the retention contract). When connect finds its saved session closed, it registers a fresh session identity and proof under the same local session name, keeping the workstation, harness, capabilities and subagent identity, and reports the old ID as replaced_closed_session_id. The mcp-client launcher does the same before launching. Other commands on a closed saved session fail with authentication_required; run connect again. A saved session with an unresolved mutation is never replaced; run retry first.

agent-coordinator sessions list shows the open agent sessions bound to the bound project — every session that acknowledged its instructions or holds an attempt in it — most recently active first. Use it to see who is still working before a test, preflight or cutover. (The singular session command manages this harness’s own local session state instead.)

agent-coordinator sessions list
agent-coordinator sessions list --active-within-hours 1
agent-coordinator sessions list --active-within-hours 0   # every open session
agent-coordinator --json sessions list

The default window is the service’s 24 hours. Last activity is derived from instruction acknowledgments, claims, heartbeats, progress, attempt endings and checkpoints in the project; reads never count. A session holding an active attempt is listed whatever the window, even when that attempt’s lease has lapsed. The table columns are SESSION, PRINCIPAL, AGENT (the harness, plus / subagent NAME for a subagent session), WORKSTATION, STARTED, LAST ACTIVITY and HELD (the count, then each held task ID with its review or integration kind, and (lease expired) after an active attempt whose lease lapsed and needs recovery). See the API contract for the JSON shape that --json prints.

agent-coordinator integrator-reports reads the integrator’s reports for the bound project: the findings (fix_target, flaky, privilege_gate, target_rewritten, ruleset_missing, unreviewed_landing) that explain why a subject waits, such as a failing target. Any authenticated reader may use it. It is read-only: a human resolves a report in the manager.

agent-coordinator integrator-reports list
agent-coordinator integrator-reports list --open --task subject-task-id
agent-coordinator integrator-reports list --limit 20 --before report-id
agent-coordinator integrator-reports show --id report-id
agent-coordinator --json integrator-reports show --id report-id

list prints reports newest first with the columns ID, KIND, TASK, REQUIRES HUMAN, CREATED, RESOLVED (open, or when it was resolved and the decision) and VERDICT / REASON (from the report’s details). --open keeps only unresolved reports, --task only those about one task, and --limit is 1 to 1000 (service default 200). A full page ends with Next before: ID; pass it as --before for the following page. show prints the same summary followed by the complete report. An unknown ID, or another project’s report, is a not_found error. --json prints the complete service response; see the API contract for its shape.

Operator and objective commands

The native client authenticates as an agent; administrative human actions use the browser or the host-local service command. Native commands retain service role checks and the same exact-request mutation journal as claims.

agent-coordinator tasks show --id TASK_ID
agent-coordinator tasks edit --id TASK_ID --input revised-task.json
agent-coordinator tasks history --id TASK_ID --kind attempts --limit 50
agent-coordinator task-definition-grants list
agent-coordinator task-definition-grants create --input grant.json
agent-coordinator task-definition-grants revoke --id GRANT_ID --input revoke.json
agent-coordinator policy show
agent-coordinator policy history --limit 50
agent-coordinator policy edit --input revised-policy.json
agent-coordinator objectives list
agent-coordinator objectives create --input objective.json
agent-coordinator objectives show --id OBJECTIVE_ID
agent-coordinator objectives children --id OBJECTIVE_ID --input membership.json

Copy task commands from the dashboard

The task detail page has a CLI commands disclosure that lists the commands above for the open task, each with a Copy button (the command is selected for manual copying when the browser refuses clipboard access): tasks show, tasks history for attempts and checkpoints, reviews list and integrations list once the task has workflow activities, jobs inspect for each listed job, and recovery inspect --attempt only while the task is recovery_required. claim --task ID --revision N appears only for a ready, unowned, agent-deliverable task and is labelled as taking ownership. IDs are single-quoted for a POSIX shell when they contain anything beyond plain characters, and an ID with control characters yields no command. The commands name no service URL, session, state directory or credential; the repository’s .agent-coordinator.toml selects the service.

Correct a task’s kind

tasks edit accepts an optional "kind": "code" or "kind": "general" in its JSON input alongside the existing definition fields and expected_revision. Omitting kind preserves it. The REST task PATCH and MCP coordinator_task_edit use the same field; the dashboard’s Edit task dialog preselects the current Kind. Use this to correct a misclassified, unowned open, planned, or blocked task instead of canceling it and creating a replacement.

The usual revision and task-definition editing permissions apply, including agent contributor restrictions. A changed kind is refused with task_kind_workflow_protected if a submission (including one reopened for revision), review, or integration exists for the current task generation. Preserve that workflow’s evidence rather than changing its delivery contract. Objectives remain General and revert tasks remain Code; changing these fixed contracts returns task_kind_fixed (409). An accepted edit increments the revision and records the actor and old/new kind in task history. Blocked work remains blocked until separately resolved.

Inspect blockers and wait for a state change

Task detail exposes service-known preconditions. For an exact task or workflow activity, use GET /api/v1/projects/PROJECT_ID/preconditions/TARGET_ID or the MCP tool coordinator_preconditions_get before claiming. The result names each known unmet gate, including reviewer independence and reopen or revise where applicable; gates only a human can clear carry required_actor: "human". These reads do not reserve ownership; the guarded claim remains authoritative. Code integrations include a merge-preflight hint because the service cannot inspect Git remotes or determine merge conflicts itself.

To wait without a polling loop, call the authenticated REST endpoint GET /api/v1/projects/PROJECT_ID/state-wait or MCP tool coordinator_state_wait. Provide target_kind (task, activity, or job), target_id, and the after_state_token returned by task detail, activity detail, individual job detail, or precondition inspection. Use the individual job detail endpoint rather than the paged job list. timeout_seconds is optional and bounded to 1–30 seconds (default 15). The service checks every 500 ms, holds no database transaction while sleeping, and returns the latest state on timeout. Tokens include the caller-visible precondition list and claim eligibility, so an acknowledgment or policy gate change can wake the wait even when the task’s work_status stays the same. Expected detection latency is up to roughly 500 ms plus scheduling and query time. Waiting does not renew ownership; renew through the normal owner session.

Cross-session delivery receipts for a separate Claude-to-Claude messaging channel are outside this service’s scope: that transport is external and the coordinator cannot observe whether another client received its message. This is already filed with the correct owner in the open Claude Code issue #86014, which asks for delivery or an error/pending result instead of unconditional success; do not create a duplicate coordinator endpoint or imply its event log confirms external receipt.

Use --cursor from a returned page for task history, task lists, objective lists, and policy history. History kinds include attempts, checkpoints, checkouts, jobs, job_observations, resources, artifacts, submissions, reviews, integrations, task_revisions, and events. History pages bind the project, task, record kind, and insertion snapshot; start a new query to include new records.

Task edits provide expected_revision, title, description, acceptance_criteria, priority, depends_on, and planned. Only unowned open or planned tasks may be edited, subject to workflow and policy checks. Changing planned to false admits work; it does not bypass dependencies or objective gates.

Task-definition grants are project-scoped and default-deny. A principal grant contains {"target_kind":"principal","agent_principal_id":"AGENT_ID"}; the explicit role grant is {"target_kind":"role","agent_role":"agent"} and therefore covers every valid agent in the project. Revocation input is {"expected_revision":N}. The service enforces the same administrator-only grant management and agent contributor-safety checks for CLI, REST, MCP, and the dashboard; a grant never authorizes policy or review changes.

Objective creation provides a title, description, acceptance criteria, priority, planned flag, and children entries containing task_id and required. Child replacement provides expected_revision from the objective’s objective_revision and the full children list. Required children must finish before the objective’s own work and completion evidence; optional children remain visible. The objective is a general task with its own review, never an automatic done rollup.

Use the dashboard’s Access page for human accounts, agent token rotation, and browser session revocation. My account sets and verifies the operator’s email address, changes the operator’s password, and ends all their browser sessions. An administrator with local host access can recover a lost password without publishing a recovery endpoint:

agent-coordinator-server --database /path/to/coordinator.sqlite3 \
  recover-operator-password --username OPERATOR --reason 'Verified local account recovery'

The command prompts invisibly for the new password twice, or accepts --password-stdin. It enables the human account and ends its browser sessions; existing agent credentials, producers, resource holds, and saved work remain subject to their original authority and recovery rules. Never include a password in command arguments or the audited reason.

Only a human or a project’s designated digest sender can obtain a digest acknowledgement link, so an agent cannot mark the digest read. The host operator designates the sender (the agent that owns the digest timer’s token), or clears it with --clear, without a network call:

agent-coordinator-server --database /path/to/coordinator.sqlite3 \
  designate-digest-sender --project PROJECT_ID --agent AGENT_NAME \
  --reason 'Digest timer credential'

Publish and retrieve deployment reports

Use artifacts publish to reserve and upload one reviewed report with a stable publication UUID. It requires an existing task and producer job in the bound project. Create reservation.json with the same schema as artifacts reserve: filename, media_type, exact size_bytes, lowercase sha256, task_id, job_id, optional retention_days and pinned. Compute size and SHA-256 from the sanitized file, and save a new UUID as PUBLICATION_UUID before first use. Keep files and session state outside source checkouts. For example:

agent-coordinator --session SESSION artifacts publish --id PUBLICATION_UUID --file deployment-report.json --input reservation.json --json

This command publishes supplied bytes; it does not run a deployment or verify the report’s claims. Follow the deployment report requirements. It persists a private snapshot and exact reservation request/key before sending. Repeat the same command, UUID, session and metadata after any interruption. Reservation retries reuse their original key and upload retries reuse the existing native transfer journal. A changed source file does not replace the saved bytes; changed metadata for the same publication is refused. Do not choose a new UUID to work around an uncertain response. retry handles ordinary pending session mutations; artifacts publish resumes its own saved publication. Resolve an ordinary pending mutation before starting publication.

Success includes data.artifact, freshly authenticated as a finalized, available upload with matching task/job, size and SHA-256. A reservation alone is not success. Record data.artifact.id in a checkpoint/handoff and in submission artifact_ids. The publication snapshot and transfer journal remain under the normal native configuration directory in artifact-uploads, isolated by a hash of origin, project, session and publication UUID. --state-dir does not redirect artifact journals. Keep native configuration and session storage across retry; do not migrate either during an unresolved publication. This command does not renew task ownership, submit work, or release resources. It does not automatically delete retained publication snapshots. After independent retrieval and the agreed retention period, inspect the exact publication before removing local evidence.

Another authenticated agent can discover and retrieve the report without access to the producer host:

agent-coordinator --session READER tasks history --id TASK_ID --kind artifacts --limit 50 --json
agent-coordinator --session READER artifacts show --id ARTIFACT_ID --json
agent-coordinator --session READER artifacts download --id ARTIFACT_ID --output new-report.json --json

Follow history cursors, match task_id and job_id, and inspect current availability. Download verifies size/SHA-256 and refuses an existing destination. Compare the report’s source/package and observation identities with the original task/job. An expired/deleted upload cannot be retrieved; an external link is not uploaded content. Publication replay fails rather than reporting success for unavailable bytes. Report missing historical originals truthfully and ask a capable source-host worker to backfill; do not rerun an old deployment to manufacture evidence.