zuka
zuka/AGENTS.md

worklyn / zukapublic

Agent-first git hosting. One Rust binary: git over HTTP and SSH, a REST API, MCP, CI, and multi-tenant isolation.

Get a copy: git clone https://zuka.worklyn.com/worklyn/zuka.git
zuka/AGENTS.md
MDAGENTS.md6.1 KBFormattedDownload
1# AGENTS.md — zuka
2
3Read [`../AGENTS.md`](../AGENTS.md) first; conventions cascade. This file records the
4exceptions and the rules that only apply here.
5
6Before working on a topic, read the doc that owns it: [`SPEC.md`](SPEC.md) for
7architecture, API, security and data model; [`ROADMAP.md`](ROADMAP.md) for sequencing,
8risk and open decisions; [`README.md`](README.md) for what the product is and is not.
9
10## Exception: the runtime is Rust, not Deno
11
12`product/AGENTS.md` states "Runtime is Deno. TypeScript throughout." **zuka is
13Rust**, and this is a stated override rather than a silent one.
14
15Why: the workload is git object manipulation, subprocess supervision and long-lived
16byte streams, and it ships as a single self-hostable binary a stranger can drop on a
17VM. A Deno service would need a runtime installed and would still shell out for every
18git operation. The two existing Rust services in `yangu/` (`atlas`, `kazi`) set the
19in-house precedent this follows.
20
21Deno still applies to **tests** — the live suite in `test/live/` is TypeScript,
22spawning the compiled binary and driving it with a real `git` CLI and real `fetch`.
23
24The Motheo design-system and Worklyn Sans rules do not apply: this service has no UI.
25Its marketing page lives in `yangu/website/` and follows them there.
26
27## Rust conventions
28
29Follow `yangu/atlas` and `yangu/kazi`, whose patterns are already load-bearing in
30production:
31
32- `hyper` 1.x + `tokio`, no web framework. `anyhow` internally, one typed `Error` at
33 the HTTP boundary (SPEC §8.3). `serde` on the wire.
34- `edition = "2021"`, standalone crate, committed `Cargo.lock`, `.gitignore` = `target/`,
35 `[profile.release] opt-level = 3`, `lto = "thin"`.
36- Config is `std::env::var` with defaults gathered into `Config::from_env() ->
37 Result<Config>` that fails boot loudly on an invalid value. Prefix `ZUKA_`.
38- Tests are inline `#[cfg(test)] mod tests` with sentence-named cases
39 (`rejects_ref_write_without_if_match`), not `test_`-prefixed.
40- CI gates on `cargo test` → `cargo clippy --all-targets -- -D warnings` →
41 `cargo build --release`, following `yangu/.github/workflows/build-kazi.yml`.
42
43**The live suite must run in CI.** It self-skips without `ZUKA_LIVE_TEST`, and a
44proof that never executes is not a proof — SPEC calls the live tests the place the
45wire protocol and REST contract are actually proven, so the CI job sets the flag and
46installs `git`.
47
48### Deviation: nested `src/`, not flat modules
49
50`yangu/atlas` and `yangu/kazi` keep everything in one `main.rs` (1,158 and 3,050
51lines). zuka nests by concern (SPEC §8) because it carries four protocol surfaces
52against atlas's one. This is a judgment call, recorded as such — do not restate it as
53a measured failure of the flat pattern.
54
55## Rules specific to this service
56
57- **`git::exec::Git` is the only way to invoke git.** Not `Command::new("git")`. It
58 clears the environment and sets `GIT_CONFIG_NOSYSTEM`, so host configuration cannot
59 change what our git calls do. Five wrappers with three different policies existed
60 before it, and `/etc/gitconfig` applied to the ref rule and the quota accounting but
61 not to the wire.
62- **Exit 1 is an answer; anything higher is a fault.** `Git::query` encodes this.
63 Collapsing every non-zero exit into `404` once meant a corrupt repository reported
64 as empty and nothing paged anyone.
65- **Git work never runs on a runtime worker.** Use `git::exec::blocking`. A fork+exec
66 on a tokio worker stalls unrelated requests including `/healthz`, and the pool is
67 only as wide as the core count.
68- **Shared operations live in `core/`.** REST and MCP each had their own repository
69 create and delete once; the copies drifted in four ways before anyone noticed. If a
70 facade needs a rule, the rule goes in `core/` or `git/` and the facade calls it.
71- **`AppState::open_repo` is how a repository is resolved.** It carries the access
72 check, the ready check and — for `Access::Write` — the disk reserve and the storage
73 quota, so no write path can forget them.
74
75- **Validation in SPEC §2.5 is normative.** Ref names, repo names, tree paths and file
76 modes are security controls, not input hygiene. A ref name reaching the filesystem
77 unvalidated is remote code execution. Never hand-roll ref validation; use
78 `gix-validate`.
79- **Every ref mutation goes through a `gix-ref` transaction** with the precondition
80 enforced *inside* it (SPEC §1.3). Check-then-write is a race against `receive-pack`.
81- **One rule, one implementation.** The `update` hook and the REST ref endpoint call
82 the same core function. If a rule appears in both a hook and a handler, it is in the
83 wrong layer.
84- **git is the only writer.** No endpoint and no MCP tool modifies a repository's
85 contents or moves a ref; that is `git push`. Adding a write path means a second
86 home for the fast-forward rule, a concurrency model and a merge story, all of
87 which git already has (SPEC §1.3). If a task seems to need one, the answer is
88 almost certainly that the caller should run git.
89- **Facades translate; they do not decide.** `api/` and `mcp/` may fill defaults and
90 reshape payloads. They may not carry authorization logic — that lives on
91 `Identity`, so REST, MCP and SSH cannot drift. A facade must never call into
92 another facade.
93- **The git paths are not REST.** `/{account}/{repo}.git/*` has its own error contract:
94 `WWW-Authenticate` on `401`, `application/x-git-*` content types, never
95 `problem+json` (SPEC §4.7).
96- **Scheduled work lives in `jobs/`** and its own systemd unit, never the web
97 entrypoint.
98- **CI isolation claims must name a mechanism.** "No network" means a network
99 namespace; "isolated" means a uid, a cgroup and a scrubbed environment. An intention
100 is not a control (SPEC §6.3).
101
102## The gate
103
104Run all four before pushing; CI runs the same set and gates on every one.
105
106```sh
107cargo fmt --check
108cargo clippy --all-targets -- -D warnings
109cargo test
110deno task test:live
111```
112
113## Status
114
115Standalone is complete: M0–M5 and M7. M6 (multi-tenant control plane) is deferred and
116unbuilt — see `ROADMAP.md` D9.
117
118`SPEC.md` describes how the service works; `ROADMAP.md` says what exists and why. When
119they disagree about what is built, the roadmap is right.