- new ADR-017: GitSession is a real typed client in v1 (ls_refs/fetch/ push), grounded in the two deployment use cases — the p2p replicator is the named downstream and needs the client protocol layer; the thin-wrapper reading is superseded - fetch client reuses gix-protocol (async-client) over a custom alkcall gix_transport::client::Transport impl (handshake writes the ADR-016 request line on the direct path; the channels open-op params carry it otherwise); push hand-rolled to ADR-013's shapes (gitoxide has no send-pack client) - storage-agnostic: packs stream both ways to caller-owned consumers; no in-session credentials (alkcall transport authenticates); client sessions carry ADR-009 Limits (client is also internet-facing) - manifest: gix-protocol/gix-transport gain async-client features (verified against published tree, MSRV 1.88) - amend ADR-010 (consumer-half bullet) and ADR-012 §4 (the deferred gix-protocol call — resolved; rider superseded); backend/transport/ overview/doors wording; review 001 A-5 marked resolved verification: cargo check (default, --all-features, --no-default-features, --features sha256), cargo +1.88 check, cargo test, clippy -D warnings, fmt --check — clean across the matrix
7.3 KiB
status, last_updated
| status | last_updated |
|---|---|
| draft | 2026-09-25 |
Overview: alkgit
Purpose
alkgit is the git payload service of the alk family: a pure protocol crate
(per ADR-010, following the alktty/alktunnels template) implementing the
git smart protocol over alkcall channels — the alk/git ALPN. It provides
repository storage as backend traits (with a feature-gated gitoxide
implementation), the git smart protocol as producer/consumer halves, 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.
The one-line architecture
One protocol crate: producer + consumer + backend traits, gix behind a feature. Doors (alkhttp, alkssh, alknet) expose it; assembly belongs to downstream consumers.
Crate map
Single crate alkgit:
| Half | Contents | POC evidence |
|---|---|---|
| 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) |
POC-1 verbatim |
| Consumer | GitSession typed client (connect_direct, open_via_channels) — ADR-017: ls_refs/fetch/push; fetch via gitoxide client machinery over a custom alkcall Transport, push hand-rolled to ADR-013's shapes; the replication/mirroring primitive for alknet |
new, specified (grammar capture-grounded: ADR-013/014 + captures) |
| Substrate | duplex session + stateless request/response layer (ADR-005); wire framing, V2 state machines (ADR-003) | POC-1, POC-3 |
| Backends | GitRegistry (+ write supertrait), GitRefs, GitPackGen, GitPackIngest traits; impls behind the default-on gix (engine) and registry-file (records) features |
POC-2 (gix impl) |
| Management ops | git/repo/* call ops over GitRegistryStore (ADR-012 §3) — the JSON half alongside the alk/git open op (first dual-kind payload; ADR-012 §5) |
thin over the store trait |
Feature model: gix (engine impls) and registry-file (record store +
ops) are independent default-on seams (ADR-012 §4);
default-features = false gives the wire/protocol layer without either
(wasm-clean as a side effect, not a goal); the sha256
passthrough and (eventually, in alkhttp) the git door feature ride the
same pattern. Doors live in the door crates — see doors.md.
Security invariants (spec-level, carried from vision/principles)
- Authenticated by default — anonymous fetch only on explicitly- public repos; push always authenticated.
- Visible-surface = authorized-surface — alkcall ACL end-to-end; internal ops never wire-callable.
- 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.
- Registry-resolved repo identity — wire names are ids, never paths (ADR-008).
- 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.)
- No shelling out to
git— pure Rust on gix primitives. - Bounded resources — every session carries
Limits(ADR-009). - Honest capability advertisement — advertise exactly what we serve (ADR-003).
What is already validated (POC-backed)
- pkt-line over alkcall
BiStreamend-to-end (POC-1 → producer half). - Pack generation pipeline streaming with O(counts) memory (POC-2 → gix backend impl).
- Smart-http streaming both ways (POC-3 → the stateless substrate that
alkhttp's future
gitfeature maps onto;docs/research/poc3-findings.md§alkhttp fit is the mounting reference). The full V2 fetch path against real git 2.43 is proven; receive-pack and multi-round negotiation are design-complete against real-client captures (ADR-013, ADR-014 —push-captures.md,negotiation-captures.md).
Design Decisions
| ADR | Decision | Summary |
|---|---|---|
| 001 | Crate decomposition | superseded by ADR-010 |
| 002 | Session boundary | (identity, repo, service, stream, limits) — unchanged, load-bearing; service per ADR-016 |
| 003 | V2-first protocol | V2-only fetch both doors; push is V0-framed by upstream design (ADR-013); honest advertisement |
| 004 | Pack pipeline | data::output gen / data::input ingestion |
| 005 | Substrate types | duplex + stateless APIs over one state machine |
| 006 | HTTP adapter composition | superseded by ADR-010 (mounting → alkhttp feature) |
| 007 | ACL first | no ref/capability line before ACL passes |
| 008 | Repo identity | wire names are registry IDs |
| 009 | Budgets | every session carries limits |
| 010 | Pure protocol crate | single crate, producer/consumer halves, no doors/binary |
| 011 | Per-repo authorization | grants in repo records, policy in core, vault-nil (amended: ADR-015) |
| 012 | Registry + ops | read/write split, file default, CRUD ops, feature split |
| 013 | receive-pack | V0-framed push machine, thin-pack acceptance, unpack-first CAS |
| 014 | Negotiation | ack loop, common_haves seam, no ready |
| 015 | Manage grant + op gate | manage tier, admin-OR-manage gate, create seeds manage |
| 016 | Native session preamble | {repo, service} open-op params, request-line preamble, service in the tuple |
| 017 | Consumer half | GitSession typed client, custom alkcall Transport + gix-protocol fetch, hand-rolled push |
Open Questions
Key questions tracked in open-questions.md:
- OQ-03: publish-time API freeze inventory (the
git/repo/*op set and the trait family enter it; ADR-012, ADR-013/014's trait additions; the ADR-015 three-action grant shape must land in it; the ADR-016 native preamble wire shapes —{repo, service}params schema and the request-line grammar — entered it; ADR-017'sGitSessionpublic API enters it). - OQ-05: sha256 policy (deferred(scope), low).
- OQ-16: grant-key identity namespace (deferred(scope); blocks nothing in v1 — ADR-015 §7).
Resolved this cycle: OQ-04 (ADR-013 — receive-pack state machine,
capture-grounded), OQ-02 (ADR-014 — negotiation ack loop). Earlier:
OQ-08 (ADR-011 — per-repo authorization, grants in records, vault-nil),
OQ-06 (ADR-012 — registry-file default, persistence adapters
additive), OQ-07 (ADR-012 — CRUD ops shipped External with scope+grant
ACL, gate amended by ADR-015), OQ-09/OQ-01 (ADR-010 — pure protocol
crate).