---
status: stable
last_updated: 2026-10-23 (the wave-5 release gate — the core froze
OQ-03-side; track B decomposes against the published core)
---
# Overview: alkgit
## Purpose
alkgit is the git payload service of the alk family (per ADR-010's
pure-protocol framing, corrected for the crate shape by ADR-025):
one repo, a two-crate workspace implementing the git smart protocol
over alkcall channels — the `alk/git` ALPN — with repository storage
behind backend traits. The protocol core provides the smart protocol
as producer/consumer halves and the backend trait seam; the shipped
storage composition lives in the sibling `alkgit-substrate` crate; and
nothing else: no binary, no front doors. The original
framing of this repo (a monorepo with an `alkgitd` binary and its own
http/ssh crates) was an init-agent artifact corrected by OQ-09/ADR-010;
`docs/research/vision.md` is amended accordingly.
**Re-baselined 2026-10-19** (ADR-019..023, after the substrate
recomposition round — all four POCs complete; the evidence ledger is
`docs/research/substrate-recomposition.md`): storage is
substrate-first, `registry-file` and the on-disk odb engine are gone,
`RepoRecord` carries no path, LFS is v1 scope, reactivity is wired by
default.
**Re-split 2026-10-20** (ADR-025, relitigating ADR-010's granularity
sub-decision): one repo, a two-crate workspace — the protocol core
`alkgit` and the shipped backend composition `alkgit-substrate`. The
boundary encodes the real consumption split: door crates and wire-only
embedders consume the protocol core and cannot drag the substrate;
full embedders take both.
## The one-line architecture
**Two crates (one workspace): `alkgit` — producer + consumer + backend
traits, the protocol; `alkgit-substrate` — the shipped alkstore +
alkblobs composition implementing the traits.** Doors (alkhttp,
alkssh, alknet) expose the protocol; assembly belongs to downstream
consumers.
## Crate map
Workspace of two published crates (ADR-025):
| Crate | Contents | POC evidence |
|---|---|---|
| `alkgit` — protocol core | Producer: `GitAdapter` (`alk/git` ALPN via alkcall `ProtocolHandler`; parses the ADR-016 request-line preamble), channels `register_openable` (`channels/git/sub` — open-op params `{repo, service}`, the negotiation + service selector + ACL point; ADR-016). Consumer: `GitSession` typed client (`connect_direct`, `open_via_channels`) — ADR-017: `ls_refs`/`fetch`/`push`; construction simplified per ADR-023 §2 (**validated end-to-end by POC-X**). Wire: duplex session + stateless request/response layer (ADR-005), V2 state machines (ADR-003), receive-pack machine (ADR-013) — POC-1/2/3. Seam: the five ADR-018-pinned traits + seam types + error model; `RepoRecord`/op schemas + `authorize` (ADR-011/015); the `git/repo/*` call ops (ADR-012 §3). **No substrate dependency at any feature level** (ADR-025) | POC-1, POC-2, POC-3, POC-X |
| `alkgit-substrate` — the composition | the ADR-019 composition implementing the seam over alkstore + alkblobs: the reactive halves (publish/notify/enqueue + reconcile + watermark leg), the coherence-contract cached read provider, the family adapter pattern (trait pair + in-memory default adapter), the sqlite/postgres engine twins, the substrate `Find`/odb front + pack pipelines, GC liveness sourcing + maintenance wiring, migrations (ADR-024), the LFS surface (see [lfs.md](lfs.md)) | POC-O, POC-R, POC-L, POC-X |
Feature model (ADR-025's placement table): `alkgit` carries only the
`sha256` passthrough and defaults to no features — the protocol core
is substrate-free by construction, not by remembered flag.
`alkgit-substrate` carries `sqlite` (default-on), `postgres`
(optional), `lfs` (default-on, fail-safe); reactivity and the
engine-generic composition are the crate's unconditional base (there
is no "reactivity" feature — it rides the crate). Engines are
constructor statements at assembly time (alkstore ADR-016), never
alkgit features. Doors
live in the door crates — see [doors.md](doors.md).
## Security invariants (spec-level, carried from vision/principles)
1. **Authenticated by default** — anonymous fetch only on explicitly-
public repos; push always authenticated (the LFS batch composes the
same posture onto the door surface — lfs.md).
2. **Visible-surface = authorized-surface** — alkcall ACL end-to-end;
internal ops never wire-callable; the ownership provider is wired
on every ops-serving surface (alkcall ADR-048's loud default; the
LFS batch binds through the door's own context — lfs.md).
3. **ACL before advertisement** — nothing is emitted before the check
(ADR-007); the channels open-op carrying the repo id is the natural
enforcement point on the native path.
4. **Registry-resolved repo identity** — wire names are ids, never
paths (ADR-008); the record carries **no path at all** (ADR-019 §8),
so the never-a-path rule holds a fortiori.
5. **No secret material on the wire or at rest outside alkvault** —
metadata holds vault references; no env-var credential reads. (In v1
alkgit's metadata holds no credential-shaped material at all, so
nothing is vault-placed — ADR-011 §5.)
6. **No shelling out to `git`** — pure Rust on gix primitives.
7. **Bounded resources** — every session carries `Limits` (ADR-009);
the receive machine's pack-header peek is bounded (ADR-020 §1).
8. **Honest capability advertisement** — advertise exactly what we serve
(ADR-003).
## What is already validated (POC-backed)
- pkt-line over alkcall `BiStream` end-to-end (POC-1 → producer half).
- Pack generation pipeline streaming with O(counts) memory (POC-2 →
the pipeline shape) — now over the substrate `Find` (POC-O).
- Smart-http streaming both ways (POC-3 → the stateless substrate that
alkhttp's future `git` feature maps onto; `docs/research/poc3-findings.md`
§alkhttp fit is the mounting reference).
- The substrate re-baseline's four gates (POC-L/O/R/X, complete):
- **POC-O** — real `git clone`/`git push` against substrate-only
storage; through-store ranged pack serving; row-CAS refs (stale/
atomic/delete/force); GC interop; sqlite co-tenancy clean.
- **POC-R** — the reactive registry composition cross-process; the
coherence contract + reconcile recipe; the maintenance chain
(scheduler → queue → TTL lock → sweep).
- **POC-L** — LFS end-to-end with real `git-lfs` 3.7.0 (both
bindings, three engines).
- **POC-X** — two-node replication converging on real pushes;
`GitSession`'s first working validation; the packless-push and
RST-discipline wire facts.
## Design Decisions
| ADR | Decision | Summary |
|---|---|---|
| [001](decisions/001-crate-decomposition.md) | Crate decomposition | **superseded by ADR-010** |
| [002](decisions/002-front-door-blind-core.md) | Session boundary | (identity, repo, service, stream, limits) — unchanged, load-bearing; service per ADR-016 |
| [003](decisions/003-protocol-v2-first.md) | V2-first protocol | V2-only fetch both doors; push is V0-framed by upstream design (ADR-013); honest advertisement |
| [004](decisions/004-pack-pipeline.md) | Pack pipeline | `data::output` gen / `data::input` ingestion |
| [005](decisions/005-session-substrate-types.md) | Substrate types | duplex + stateless APIs over one state machine |
| [006](decisions/006-http-adapter-composition.md) | HTTP adapter composition | **superseded by ADR-010** (mounting → alkhttp feature) |
| [007](decisions/007-acl-before-advertisement.md) | ACL first | no ref/capability line before ACL passes |
| [008](decisions/008-registry-resolved-repo-identity.md) | Repo identity | wire names are registry IDs (record carries no path — ADR-019 §8) |
| [009](decisions/009-bounded-resources-budget.md) | Budgets | every session carries limits |
| [010](decisions/010-pure-protocol-crate.md) | Pure protocol crate | producer/consumer halves, no doors/binary (granularity + posture superseded: ADR-025) |
| [011](decisions/011-per-repo-authorization.md) | Per-repo authorization | grants in repo records, policy in core, vault-nil (amended: ADR-015) |
| [012](decisions/012-registry-backing-and-ops.md) | Registry + ops | read/write split, CRUD ops, feature split (file default superseded by ADR-019) |
| [013](decisions/013-receive-pack-state-machine.md) | receive-pack | V0-framed push machine, thin-pack acceptance, unpack-first CAS (§3/§6 amended: ADR-020) |
| [014](decisions/014-v2-negotiation-ack-loop.md) | Negotiation | ack loop, `common_haves` seam, no `ready` |
| [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant + op gate | `manage` tier, admin-OR-manage gate, create seeds manage |
| [016](decisions/016-native-session-preamble.md) | Native session preamble | `{repo, service}` open-op params, request-line preamble, service in the tuple |
| [017](decisions/017-consumer-half-git-session.md) | Consumer half | `GitSession` typed client; construction simplified (ADR-023 §2) |
| [018](decisions/018-backend-trait-signatures-and-storage-error-model.md) | Trait signatures + storage errors | signatures held with zero drift through the re-baseline POCs |
| [019](decisions/019-substrate-baseline.md) | Substrate re-baseline | storage on alkstore + alkblobs; `registry-file` scrapped; reactive-by-default |
| [020](decisions/020-receive-pack-duplex-amendments.md) | receive-pack duplex | packless delete pushes; unpack-to-loose + pin bridge |
| [021](decisions/021-feature-graph-and-dependency-posture.md) | Feature graph | **superseded by ADR-025** (graph re-partitioned across the two-crate workspace) |
| [022](decisions/022-lfs.md) | LFS | media under `GitObjectSha256`; alkhttp `lfs` door; wired liveness |
| [023](decisions/023-replication-v1.md) | Replication v1 | protocol-native via `GitSession`; mirror plane = optimization bucket |
| [024](decisions/024-registry-schema-migrations.md) | Schema migrations | construction-run, version-stamped, additive-first |
| [025](decisions/025-two-crate-workspace.md) | Two-crate workspace | protocol core `alkgit` + composition `alkgit-substrate`; the placement rule for every feature |
## Open Questions
Key questions tracked in [open-questions.md](open-questions.md):
- **OQ-03**: publish-time API freeze inventory (the trait family, op
set, and the revised `RepoRecord` schema + substrate composition
types enter it).
- **OQ-05**: sha256 policy (deferred(scope), low).
- **OQ-16**: grant-key identity namespace (deferred(scope); blocks
nothing in v1 — ADR-015 §7).
- **OQ-17**: relational registry schema migrations — resolved as
ADR-024 (construction-run, version-stamped, additive-first).
- **OQ-19**: implementation-phase wire validations (unborn-HEAD
rider; `common_haves` over the substrate odb).
The re-baseline round resolved the recomposition's DQ ledger
(substrate-recomposition.md DQ-1..8 → ADR-019..023); the registry
backing question (OQ-06, resolved by ADR-012) is superseded by
ADR-019. The crate-shape round (2026-10-20, ADR-025) superseded
ADR-010's granularity sub-decision and ADR-021's feature graph —
OQ-03's freeze inventory re-partitions per crate.