Skip to content

Help topics

The concept pages of the terminal, word for word: ag help TOPIC prints the same text. They are short on purpose; the guides they point to have the detail.

workflow

Workflow: from an edit to a landed change

A change goes through four independent checks. None implies another:

    Mergeable   is there one unambiguous result?        ag preview PROPOSAL
    Validated   did trusted checks pass on THAT tree?   ag validate run PROPOSAL ...
    Approved    did enough eligible people approve?     ag proposal review PROPOSAL --approve
    Integrated  was the stream updated atomically?      ag integrate PROPOSAL

The everyday loop

    ag init --namespace me/project     once: creates .ag/ and the stream "main"
    ag snapshot -m "message"           record the working directory (private until proposed)
    ag propose -t "title"              publish the snapshot and open a proposal
    ag integrate PROPOSAL              move the stream; policy decides whether it may

Any unique prefix (6 or more characters) of a proposal id works: `ag integrate prop_8f3a1c`.

When integrate says "Blocked" (exit code 3)

The stream was not changed. The message lists what is missing; provide it and run the SAME command again, it
resumes the same operation:

    missing validation   ag validate run PROPOSAL --check NAME --key ISSUER -- COMMAND
    missing approval     ag proposal review PROPOSAL --approve          (by someone eligible)
    missing provenance   ag provenance attach @WORKSPACE --agent NAME
    lease token          ag integrate PROPOSAL --fencing-token N

When it says "Conflict" or "Denied" (exit code 4)

The stream was not changed and waiting will not help:

    conflict   ag sync, resolve the marked files, ag snapshot, ag proposal update PROPOSAL
    denied     the policy forbids it for this actor or change; see `ag help policy`

Working in parallel

    ag workspace create NAME --dir ../NAME     an isolated directory that starts at the stream head
    ag snapshot -m MSG --workspace NAME
    ag propose @NAME -t TITLE
    ag sync --workspace NAME                   bring the stream's new head into the workspace

Where am I? `ag status` shows the workspace, your proposals, your leases, your task and the remote.
Is everything healthy? `ag doctor`. What exactly happened? `ag trace`, `ag op show OPERATION`.

More: docs/getting-started.md and docs/tutorials/first-agent-safe-repo.md

policy

Policy: what must be true before a change lands

A policy is a JSON document per stream. It is versioned and append-only: `ag policy set FILE` stores a new
version, `ag policy history` lists them, `ag policy show` prints the one in force. Unknown fields and
policies that can never be satisfied are rejected when you set them.

    ag policy example > policy.json     a document to start from
    ag policy set policy.json           needs an admin of the current version
    ag policy show

You do not have to write the first one: four presets are built in (solo, team, agents, strict).

    ag policy preset list               who each is for
    ag policy preset apply agents       store one (or `ag init --preset team`); `--ci-key ci` also requires a signed check
    ag policy explain                   the policy in force in plain language, read from the document itself

The fields

    integrators / admins / allowed_authors   who may integrate, change policy, author proposals
    trusted_issuers                          identities AND public keys whose attestations count
    required_validations                     checks that must have passed on the exact candidate tree
    approvals                                min, min_for_agents, approvers, forbid_self_approval
    protected_paths                          globs that need extra approvals (min_approvals, approvers)
    agent_autonomy                           auto_integrate, allowed_paths, max_files: the envelope
    require_provenance_for_agents            agent changes need a valid signed provenance record
    max_changed_files                        deny integrations that touch more files

With no policy stored: any non-agent may integrate; agents cannot integrate on their own and need one human
approval.

What the verdicts mean

    Blocked (exit 3)   something you can provide is missing: validation, approval, provenance, lease token
    Denied  (exit 4)   the policy forbids it: actor not allowed, a trusted FAIL on this tree, too many files

Validation is bound to the tree: an attestation counts only if it is signed by a trusted issuer, names this
exact candidate tree, and was made under this policy version. Changing the policy, or the stream moving,
means validating again. Approvals are bound to the proposal head: pushing a new head resets them.

`--json` output of `ag integrate` carries stable blocker codes: missing_validation, insufficient_approvals,
changes_requested, missing_provenance, lease, failed_validation, actor_not_allowed, author_not_allowed,
too_many_changed_files.

`ag explain [PROPOSAL]` puts every reason in words and lists the commands that fix it.

Command help: `ag policy --help`. More: docs/guides/policy.md and docs/tutorials/policy-cookbook.md

leases

Leases: claiming a part of the tree

A lease claims a path scope (a glob such as `src/auth/**`) for an identity, for a limited time.

    ag lease acquire 'src/auth/**' --ttl 30m                soft: a signal, never blocks anyone
    ag lease acquire 'src/auth/**' --ttl 30m --exclusive    enforced at integration; prints a fencing token
    ag lease extend LEASE --ttl 30m                         the token stays the same
    ag lease release LEASE
    ag lease list [--all]

Soft leases are advisory. Acquiring one over someone else's reports the overlap as a warning.

Exclusive leases are refused while another principal holds an overlapping exclusive lease, and they are
enforced when a change lands: while the lease is active, a change that touches its scope can only be
integrated if its author is the holder AND the integration presents the lease's current fencing token:

    ag integrate PROPOSAL --fencing-token 7

Fencing tokens come from one strictly increasing counter. If a holder stalls, its lease expires and someone
else acquires the scope with a higher token; when the stalled holder wakes up, its old token no longer passes.
Expiry never deletes changes that were already proposed: it only stops a stale holder from landing them into
a scope that is now someone else's.

`ag integrate` reports a lease problem as a blocker (exit 3): "exclusive lease on 'src/**' held by ...
(held_by_other / stale_or_missing_token)". Look with `ag lease list`, wait or ask the holder, then pass the
current token.

Finishing an agent run (`ag agent finish RUN`) releases that run's leases; `ag agent reap` abandons runs with
no recent heartbeat and releases theirs.

`ag predict` shows overlapping work before it collides; `ag preview PROPOSAL` gives the definitive merge answer.

More: docs/guides/agents.md

identities

Identities: who is acting

An identity is `kind:name`. The kind is `user`, `agent`, `service` or `system`:

    user:alice            a person
    agent:refactor-bot    a registered agent (see `ag agent register`)
    agent:refactor-bot#run_7f3a...   one run of that agent (`ag agent start` prints it)
    service:ci            a trusted validation service

Rules that compare people (self-approval, lease ownership) compare the principal, the part before `#`, so an
agent cannot approve its own work by starting a new run.

Which identity `ag` uses, first match wins

    1. --as IDENTITY
    2. the AG_IDENTITY environment variable
    3. the `identity` setting:  ag config set identity user:alice
    4. user:$USER

`ag config get identity` shows the result and where it came from; `ag status` and `ag doctor` show it too.

In local mode an identity is a label, not authentication: anyone who can run `ag` in the repository can claim
any identity. Against clients you do not control, use `ag-server`, which authenticates every request and
enforces policy there (docs/architecture/security.md).

Agents: `ag agent register NAME`, then `ag agent start NAME` prints the identity to use for the run:

    export AG_IDENTITY='agent:NAME#run_...'

More: docs/concepts.md and docs/guides/agents.md

revisions

Revisions: naming a point in history

Wherever a command takes a revision you can use:

    @                  the head of the default workspace
    @NAME              the head of workspace NAME
    main               a stream name (its current head)
    prop_8f3a1c        a proposal id (its proposed head); a unique prefix of 6+ characters is enough
    e55836a9d643       a changeset id, or a unique prefix of 6+ hex characters

optionally followed by `~N` (the N-th first-parent ancestor) and `^N` (the N-th parent):

    main~2             two changesets before the head of main
    prop_8f3a1c^2      the second parent of the proposed head (for a merge)

`REV:PATH` names a file at a revision:

    ag cat main:src/lib.rs
    ag cat @:README.md             the workspace head
    ag blame main:src/lib.rs

Without a revision, most commands use the head of the default workspace, or the default stream when the
workspace has no snapshots yet.

If a name cannot be resolved, `ag stream list`, `ag proposal list` and `ag log` show what exists.

More: docs/concepts.md

exit-codes

Exit codes: what a script or an agent can rely on

    0   success
    1   error: bad input, a missing object, I/O; the message is on stderr (with --json, as one JSON line)
    2   usage error: unknown command or option, a missing argument (printed by the argument parser)
    3   blocked: something you can provide is missing (an approval, a validation, a lease token);
        provide it and run the same command again. The stream was not changed.
    4   refused: a conflict, a policy denial, or an invalid request. Waiting will not help;
        the stream was not changed.

Which commands use 3 and 4

    ag integrate, ag op resume, ag remote integrate   0 integrated, 3 blocked, 4 conflict / denied / invalid
    ag remote prepare                                 0 nothing blocks it, 3 blocked, 4 conflict or problem
    ag preview                                        0 clean, 4 conflict or problem
    ag sync, ag pull                                  0 up to date, 4 the merge left conflict markers
    ag validate run                                   0 the check passed, 4 it failed (the failure is recorded)
    ag queue run                                      0 everything integrated, 3 something is blocked or failed
    ag predict                                        0 no overlapping work, 3 overlaps found

Commands that find a problem with the repository itself exit 1: ag verify, ag audit, ag recover (errors),
ag backup (unhealthy copy), ag doctor (a check failed).

Code 4 is the verdict on a change, not a general "conflict" or "not found" status: asking for something that does
not exist ("not found: proposal 'x'", "no stream 'x'") or creating something that already exists ("already
exists: stream 'main'") is an ordinary error and exits 1. A script that must tell those apart reads
`error.message` of the JSON error; the exit code stays 1 so that scripts written against it keep working.

Branch on the code, not on message text. With --json, `ag integrate` also returns `outcome.status`
and stable `blockers[].code` values (see `ag help policy`).

Output goes to stdout; errors, hints and diagnostics go to stderr. `--quiet` removes confirmations and hints,
never errors.

More: docs/reference/cli.md

json

Machine-readable output: --json

Every command that reports something accepts the global `--json` flag (before or after the command):

    ag --json log
    ag integrate PROPOSAL --json

Standard output then holds exactly one JSON document and nothing else; text, hints and diagnostics go to
standard error. Errors become one JSON line on standard error:

    {"error":{"message":"not found: proposal 'x'","hint":"list proposals with `ag proposal list` ...","exit_code":1}}

Commands that print file contents or a template are the exceptions, because their output is the data: `ag cat`,
`ag remote cat`, `ag policy example`, `ag completions`, `ag man`. `ag help` prints text.

A command that never ends is the other exception to "one document": `ag remote events --follow --json` prints one
compact JSON object per line (NDJSON), so that a script can read it line by line.

Stability: the shapes are version 1 (`ag version --json` prints `json_schema`). Within a version, keys are only
ever added, never removed, renamed or retyped, so ignore keys you do not know. The shapes are checked by golden
tests; the list of commands and their shapes is docs/reference/cli-json.md.

Typical use in a script:

    id=$(ag --json propose -t "Fix typo" | jq -r .id)
    ag integrate "$id" --json; rc=$?       # branch on the exit code, see `ag help exit-codes`

config

Configuration: files and environment

`ag config list` shows every effective setting and where it came from.

Files

    .ag/config.json          the repository: namespace, default stream, storage backends (set by `ag init`)
    .ag/remotes.json         remotes (managed with `ag remote add|list|remove`); never holds a secret
    .ag/credentials/NAME     a remote's token stored with --token-stdin (mode 0600)
    .ag/keys/                agent and issuer private keys (mode 0600)
    .agignore                files the working directory scan skips (one glob per line)
    user file                personal defaults: `ag config path` prints where; keys: identity, color

    ag config set identity user:alice      store your default identity
    ag config set color never
    ag config unset color

Precedence, highest first

    identity    --as, AG_IDENTITY, the user file, user:$USER
    colour      --color WHEN, the user file (when not auto), NO_COLOR, CLICOLOR_FORCE, TERM=dumb /
                CLICOLOR=0, then whether the output is a terminal
    repository  -C DIR / --repo DIR, else the nearest parent directory that contains .ag/
    credential  the variable named by the remote's token_env, the remote's token file,
                AG_TOKEN_<REMOTE>, AG_TOKEN, then the login saved by `ag login` (credentials.json beside the user file)

Environment variables

    AG_IDENTITY      the acting identity
    AG_CONFIG        path of the user file
    AG_KEY_DIR       where private keys live instead of .ag/keys
    AG_RUN           the agent run a server credential acts for
    AG_TOKEN         credential for remotes; AG_TOKEN_<REMOTE> for one remote (upper-case, non-letters as _)
    NO_COLOR, CLICOLOR, CLICOLOR_FORCE, TERM    colour (https://no-color.org)

Storage backends are configured in `ag init --storage FILE` (PostgreSQL URL and S3 credentials are read from
the environment variables that file names; see docs/operations/postgres-and-s3.md).

More: docs/reference/configuration.md