AGENTS.md — zuka
Read ../AGENTS.md first; conventions cascade. This file records the
exceptions and the rules that only apply here.
Before working on a topic, read the doc that owns it: SPEC.md for
architecture, API, security and data model; ROADMAP.md for sequencing,
risk and open decisions; README.md for what the product is and is not.
Exception: the runtime is Rust, not Deno
product/AGENTS.md states "Runtime is Deno. TypeScript throughout." zuka is
Rust, and this is a stated override rather than a silent one.
Why: the workload is git object manipulation, subprocess supervision and long-lived
byte streams, and it ships as a single self-hostable binary a stranger can drop on a
VM. A Deno service would need a runtime installed and would still shell out for every
git operation. The two existing Rust services in yangu/ (atlas, kazi) set the
in-house precedent this follows.
Deno still applies to tests — the live suite in test/live/ is TypeScript,
spawning the compiled binary and driving it with a real git CLI and real fetch.
The service now has one UI: the read-only browser viewer in src/web/ (SPEC §4.9).
It is server-rendered from the binary with no bundler and no CDN, because zuka ships
as a single self-hostable file — so Motheo tokens and Worklyn Sans, which arrive
through @ori/motheo and a font pipeline, do not apply to it. It uses a system
font stack and its own small stylesheet. The marketing page in yangu/website/
follows the design system there, where a build step is available.
If that ever stops being true — if the viewer grows enough to justify a build — this exception is the thing to revisit first.
Rust conventions
Follow yangu/atlas and yangu/kazi, whose patterns are already load-bearing in
production:
hyper1.x +tokio, no web framework.anyhowinternally, one typedErrorat the HTTP boundary (SPEC §8.3).serdeon the wire.edition = "2021", standalone crate, committedCargo.lock,.gitignore=target/,[profile.release] opt-level = 3,lto = "thin".- Config is
std::env::varwith defaults gathered intoConfig::from_env() -> Result<Config>that fails boot loudly on an invalid value. PrefixZUKA_. - Tests are inline
#[cfg(test)] mod testswith sentence-named cases (rejects_ref_write_without_if_match), nottest_-prefixed. - CI gates on
cargo test→cargo clippy --all-targets -- -D warnings→cargo build --release, followingyangu/.github/workflows/build-kazi.yml.
The live suite must run in CI. It self-skips without ZUKA_LIVE_TEST, and a
proof that never executes is not a proof — SPEC calls the live tests the place the
wire protocol and REST contract are actually proven, so the CI job sets the flag and
installs git.
Deviation: nested src/, not flat modules
yangu/atlas and yangu/kazi keep everything in one main.rs (1,158 and 3,050
lines). zuka nests by concern (SPEC §8) because it carries four protocol surfaces
against atlas's one. This is a judgment call, recorded as such — do not restate it as
a measured failure of the flat pattern.
Rules specific to this service
-
git::exec::Gitis the only way to invoke git. NotCommand::new("git"). It clears the environment and setsGIT_CONFIG_NOSYSTEM, so host configuration cannot change what our git calls do. Five wrappers with three different policies existed before it, and/etc/gitconfigapplied to the ref rule and the quota accounting but not to the wire. -
Exit 1 is an answer; anything higher is a fault.
Git::queryencodes this. Collapsing every non-zero exit into404once meant a corrupt repository reported as empty and nothing paged anyone. -
Git work never runs on a runtime worker. Use
git::exec::blocking. A fork+exec on a tokio worker stalls unrelated requests including/healthz, and the pool is only as wide as the core count. -
Shared operations live in
core/. REST and MCP each had their own repository create and delete once; the copies drifted in four ways before anyone noticed. If a facade needs a rule, the rule goes incore/orgit/and the facade calls it. -
AppState::open_repois how a repository is resolved. It carries the access check, the ready check and — forAccess::Write— the disk reserve and the storage quota, so no write path can forget them. -
Validation in SPEC §2.5 is normative. Ref names, repo names, tree paths and file modes are security controls, not input hygiene. A ref name reaching the filesystem unvalidated is remote code execution. Never hand-roll ref validation; use
gix-validate. -
Every ref mutation goes through a
gix-reftransaction with the precondition enforced inside it (SPEC §1.3). Check-then-write is a race againstreceive-pack. -
One rule, one implementation. The
updatehook and the REST ref endpoint call the same core function. If a rule appears in both a hook and a handler, it is in the wrong layer. -
git is the only writer. No endpoint and no MCP tool modifies a repository's contents or moves a ref; that is
git push. Adding a write path means a second home for the fast-forward rule, a concurrency model and a merge story, all of which git already has (SPEC §1.3). If a task seems to need one, the answer is almost certainly that the caller should run git. -
Facades translate; they do not decide.
api/andmcp/may fill defaults and reshape payloads. They may not carry authorization logic — that lives onIdentity, so REST, MCP and SSH cannot drift. A facade must never call into another facade. -
The git paths are not REST.
/{account}/{repo}.git/*has its own error contract:WWW-Authenticateon401,application/x-git-*content types, neverproblem+json(SPEC §4.7). -
Scheduled work lives in
jobs/and its own systemd unit, never the web entrypoint. -
CI isolation claims must name a mechanism. "No network" means a network namespace; "isolated" means a uid, a cgroup and a scrubbed environment. An intention is not a control (SPEC §6.3).
The gate
Run all four before pushing; CI runs the same set and gates on every one.
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test
deno task test:live
Status
Standalone is complete: M0–M5 and M7. M6 (multi-tenant control plane) is deferred and
unbuilt — see ROADMAP.md D9.
SPEC.md describes how the service works; ROADMAP.md says what exists and why. When
they disagree about what is built, the roadmap is right.