Architecture overview¶
AgentGit is an agent-native source control system with its own version-control core. Git is an external adapter (Git bridge), never the engine or the source of truth. The design is recorded in ADR-0001 (in Russian) and amended by ADR-0002; traceability maps every ADR promise to what exists today.
The guiding decision: correctness of storage and versioning is guaranteed by a deterministic core; everything intelligent about agents is a replaceable layer on top. Nothing in storage, merge or recovery needs a language model.
Layers¶
flowchart TB
subgraph clients["Clients"]
CLI["ag CLI"]
SDK["Rust API (ag-integrate)"]
GIT["Git bridge (ag-git)"]
NET["Network: ag-server (AGWP) ← ag-client, SDKs, Web UI, ag-mcp, orchestrator"]
end
subgraph engine["Engine — ag-integrate"]
PUB["publish<br/>prepare · upload · verify · ready"]
INT["integrate<br/>candidate · policy · CAS"]
WS["workspaces · queue · recover · GC · fsck · backup"]
end
subgraph platform["Policy and agent coordination"]
POL["ag-policy<br/>pure evaluation, signed attestations"]
AGT["ag-agent<br/>identities · tasks · leases · provenance · prediction"]
end
subgraph core["Deterministic core"]
CHG["ag-changeset · ag-object<br/>canonical formats, content IDs"]
TREE["ag-tree · ag-dag"]
MRG["ag-merge · ag-diff"]
end
subgraph store["Storage — ag-storage"]
OBJ[("Object store (files or S3)<br/>immutable, verified on read")]
META[("Metadata (SQLite WAL or PostgreSQL)<br/>index · streams · reflog · intents<br/>outbox · audit · policy")]
end
CLI --> engine
SDK --> engine
GIT --> engine
NET --> engine
engine --> platform
engine --> core
engine --> store
platform --> store
core -.reads.-> store
| Crate | Responsibility |
|---|---|
ag-types |
validated value types: IDs, RepoPath, Identity, Namespace, StreamName, limits; no I/O |
ag-crypto |
Ed25519 with domain separation, key files (0600), randomness |
ag-object |
content addressing, object envelope, strict canonical binary encoding |
ag-changeset |
ChangesetV1: canonical encode/decode/validate; ChangesetSource trait |
ag-tree |
trees (derived state), applying operations, diff, tree resolution |
ag-dag |
ancestors, merge bases, reachability over any Graph |
ag-diff |
deterministic Myers line diff and unified output |
ag-merge |
deterministic three-way merge of text and trees with typed conflicts |
ag-storage |
ObjectStore (fs / memory / S3-compatible) and Meta (SQLite / PostgreSQL) with all transactional operations; the server's control database (storage, PostgreSQL and S3) |
ag-policy |
policy document, attestation signing/verification, pure evaluation |
ag-agent |
agent registry and runs, tasks, leases and fencing, provenance, conflict prediction |
ag-integrate |
the engine: publication, integration, workspaces, queue, GC, fsck, backup, recovery |
ag-sandbox |
isolated execution of untrusted commands: rootless namespaces, OCI containers, a limits-only fallback (sandbox) |
ag-worker |
the execution-plane worker: claims validation jobs, runs them in ag-sandbox, signs attestations (guide) |
ag-git |
Git import/export via git plumbing |
ag-protocol |
the AGWP v1 messages and operation list shared by server and clients (protocol) |
ag-server |
the network server: AGWP over gRPC and HTTP/JSON + SSE, roles, credentials, quotas, metrics (deployment) |
ag-ui-assets |
embeds the built Web UI into ag-server (Web UI) |
ag-client |
the Rust client for ag-server (used by ag clone/push/pull, remote) |
ag-mcp |
the MCP server for agent hosts (guide) |
ag-cli |
the ag binary |
Outside the Cargo workspace: the TypeScript and Python SDKs (sdk/, guide), the Vue Web UI
(apps/web) and the Go agent orchestrator (services/agent-orchestrator, guide).
Canonical model: a changeset DAG¶
History is a DAG of immutable changesets. Each carries a delta against its first parent; the tree
(full state) is derived: tree(c) = apply(tree(first_parent(c)), c.ops). This resolves the classic
snapshot-vs-delta tension: deltas are canonical, trees are verifiable projections that can be dropped and
rebuilt (ag reindex). Agent provenance lives in separate signed records so code history is not mixed
with mutable orchestration state. See Object formats.
Two stores, one ordering rule¶
The object store (files) and the metadata store (SQLite) cannot share a transaction. The engine therefore obeys one rule everywhere:
Objects first, durably and verified; metadata second, in one transaction.
An object is written (temp file → fsync → atomic rename → directory fsync) and re-read before the
transaction that makes it reachable. A crash in between leaves harmless unreferenced objects (collected by
GC); it can never leave a reference to a missing object. Backups invert the order for the same reason
(database snapshot first, then objects). See Publication & integration
and Storage.
Concurrency model¶
There is no repository-wide lock. Contention is limited to the stream being updated:
- candidates (fast-forward or merge) are computed outside any lock against a snapshot of the stream state;
- a short
BEGIN IMMEDIATEtransaction re-checks(head, version), evaluates policy against facts read in that same transaction, and commits the head move together with reflog, proposal state, audit and outbox rows; - if the stream moved, nothing is written and the candidate is recomputed — never reused;
- objects are content-addressed and immutable, so writers never conflict with each other.
SQLite serializes writers across threads and processes, so several ag processes (several agents on
one machine) are safe against one repository. This is tested with parallel workers
(concurrent_integrations_never_lose_an_update).
What is deliberately not here (yet)¶
The roadmap items that are not built are in ROADMAP; what each ADR promise maps to today, and which promises are still open, is in traceability. The engine is a library; the server exposes the same operations over the network (protocol mapping). What is verified, and what is explicitly not, is stated per area: deployment, sandbox, workers.