Working with a server: clone, fetch, pull, push — and offline¶
A local AgentGit repository is a complete, embedded repository: every command in the CLI
reference works without a network. ag talks to an ag-server
over gRPC when you ask it to. The model is deliberately small:
- your local default stream mirrors the server's stream.
pullonly ever fast-forwards it; you never move the server's head yourself; - changes travel to the server as proposals (
push), and land there throughintegrateunder the server's policy, approvals and validations — exactly like a proposal opened on the server.
Connecting¶
export AG_TOKEN=agt_… # a credential minted on the server
ag clone https://git.example.com:8443/acme/web web # http:// works for a local or TLS-terminated server
cd web
ag remote whoami # who the server thinks you are, and your roles
A remote is <server>/<owner>/<name>; ag clone records it as origin in .ag/remotes.json (no secrets in it).
Where the credential comes from, in order: the variable named by --token-env, a file you stored with
--token-stdin (.ag/credentials/<remote>, mode 0600 — ag refuses a credential file other users can
read), AG_TOKEN_<REMOTE>, then AG_TOKEN. For TLS with a private CA add --ca-file ca.pem. To act as an agent
run, export AG_RUN=<run id> (the credential must belong to that agent).
echo "$TOKEN" | ag clone --token-stdin https://… web # store it instead of keeping it in the environment
ag remote add upstream https://other.example.com/acme/web --token-env UPSTREAM_TOKEN
ag remote list
The loop¶
ag pull # fetch, fast-forward the local stream, bring the workspace up to date
# ... edit files ...
ag snapshot -m "Rename the config loader"
ag push -t "Rename the config loader" # upload what the server lacks, open a proposal
ag remote prepare prop_… # what would integrating do? what is missing? (exit 3 = blocked, 4 = conflict)
ag remote review prop_… --approve # a reviewer, from anywhere
ag remote integrate prop_… # an integrator
ag pull # the merged result comes back
ag fetchdownloads new changesets and blobs (only what you lack: the server computeswant/have, you get them parents first), verifies every object by its content hash, and publishes them locally.ag pull=fetch+ fast-forward of the local stream + a workspace sync. If the workspace has changes the merge cannot combine, you get the same conflict markers asag sync, and exit code 4.ag pushuploads only objects the server reports missing, then creates the proposal with an idempotency key derived from the head, so repeating a push that timed out cannot create a second proposal. It refuses while the working directory has uncommitted changes (ag snapshotfirst).- Everything else about a proposal is
ag remote …:proposals,proposal,prepare,review,integrate,close,streams,events [--follow],policy,log,cat,blame,whoami. They mirror the local commands of the same names but act on the server;--jsonworks everywhere. Listings are complete:proposalsandeventsread every page the server has, andlog -n Nasks for as many pages asNneeds.events --follow --jsonprints one compact JSON object per line (NDJSON), so a script can read it line by line;remote catwrites the file's raw bytes.remote blame --max-commits Nbounds how far back blame looks (the server's own limit applies by default, and the output says when blame stopped there). - Every call to a server has a deadline: 120 seconds, or
AG_TIMEOUTseconds (a whole number greater than zero; anything else is refused, not ignored). A push sends its objects in batches of at most 32 MiB, each call with the full deadline, so the deadline bounds a batch and not the whole transfer over a slow link. A download that stops in the middle ends at the same deadline instead of waiting for ever. ag remote remove NAMEdeletes the stored credential first; if it cannot, the remote is kept and the error names the file.
Offline¶
Nothing about a local repository needs the server:
ag snapshot -m "work on the train" # local changesets, local history
ag log; ag diff; ag blame src/lib.rs # all local
# ... later, with a connection:
ag pull # first catch up: the merge happens in your workspace
ag push -t "Work on the train" # then publish
If the server's stream moved while you were away, push still works — the server merges the proposal at
integration time like any other, and reports a conflict then if the edits overlap. Pulling first lets you
resolve conflicts locally, with markers, before anyone is waiting.
Do not run ag integrate on the mirrored stream of a clone. It would advance your local main past the
server's, and ag pull will then refuse to fast-forward ("it has local history the server lacks"). Land
changes on the server; use ag integrate only in a repository that is itself the source of truth.
Limits (today)¶
- One stream per command (
--stream, default: the repository's default stream); no shallow or partial clones, no submodules. - The CLI speaks gRPC only. The HTTP/JSON API and the SDKs cover the same operations for other tools.
- A crash in the middle of
fetchleaves already-downloaded objects in the local store (harmless; the next fetch skips them) but does not move the tracking reference, so it is simply retried. - The Rust client crate
ag-clientis whataguses; it retries only errors the server marks retryable, honouringretry_after_ms.