# AGENTS.md Operating instructions for opencode agents working in this repo. opencode auto-loads this file as instructions, overriding the built-in defaults for this project. Custom agents in `.opencode/agents/` inherit these rules unless their own prompts say otherwise. ## Git Workflow **Commit and push when reasonable.** When a change is complete and verified (build + lint + tests pass), commit and push to `origin/main` without asking. This overrides the built-in default of "only commit when explicitly asked." Commit in small, focused units — one commit per unit of work (a fix, a feature, a doc change), not one large commit covering many topics. Push regularly so work is never stranded locally. The workflow: 1. Make the change 2. Verify: `cargo test`, `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`, `cargo doc --no-deps` if docs changed 3. Inspect `git status` and `git diff` before staging — stage only the intended files, never secrets 4. Write a concise commit message in **conventional commits** style: `(): ` — types are `feat`, `fix`, `docs`, `chore`, `refactor`, `test`, `perf`, `build`, `ci`; the scope is optional. For multi-point changes, use a summary line plus a body with bullet points and a verification block. 5. `git push origin main` 6. Report the commit hash and the verification summary Exceptions — **do not** commit or push without asking: - The change is exploratory / speculative (you're not sure the user wants it kept) - The user is actively reviewing the diff and may ask for changes - The change touches published wire formats or semver-relevant public API (crates will be published to crates.io once architecture lands; see the ADRs in `docs/architecture/decisions/` for the stable-contract list once it exists) - You'd be force-pushing, amending a published commit, creating an empty commit, or skipping hooks Never commit secrets, keys, or credentials. If a commit fails or hooks reject it, fix the issue and create a new commit — do not amend the failed one. Git identity is preconfigured (`glm-5.3-flash `). Do not change `git config`, skip hooks, or use `git commit -i`. ## Project Conventions (Rust / protocol crate) This is alkgit — a pure protocol crate (ADR-010, the alktty/alktunnels template): the git smart protocol as producer/consumer halves on alkcall channels (the `alk/git` ALPN), backend traits with a feature-gated gitoxide (gix) implementation, no binary, no front doors (doors — alkhttp `git` feature, alkssh — are family infrastructure; see `docs/architecture/doors.md`). Single crate at the repo root (`src/`, `tests/`). The conventions below apply to all work in `src/` and `tests/`. They mirror `.opencode/agents/implementation-specialist.md` §Project Conventions and are repeated here so they apply to every session, not just spawned implementation agents. 1. **No comments in code** unless the user explicitly asks. This is a project-wide convention. Doc comments (`///`, `//!`) are fine and expected on public API. Inline `//` comments only when the user asks or when a non-obvious safety/correctness constraint would otherwise be missed (e.g., "ACL must run before the first advertised ref line — ref names leak repository existence"). 2. **Error handling** — `thiserror` for library error types. No panics in library code. No `unwrap()` or `expect()` outside tests. If you reach for `unwrap`, the error path wasn't specified — stop and decide what should actually happen. For poisoned `RwLock`/`Mutex`, use `unwrap_or_else(|e| e.into_inner())` so a panic in one operation does not cascade to other operations. 3. **`tokio` is the async runtime** — all I/O is async. Git protocol sessions are long-lived streaming conversations; do not introduce blocking I/O on the async path. Use `tokio::sync` primitives (`oneshot`, `mpsc`) for correlation; `parking_lot` for short-held internal locks. 4. **No secret material on the wire or in plaintext at rest** — the git protocol, the call protocol payloads, and the metadata store carry no private keys, API keys, tokens, or decrypted credentials. Stored credential material lives in alkvault; metadata holds vault references. Outbound credentials flow through `Capabilities` injected at the assembly layer → `OperationContext.capabilities` → handler. See the no-env-vars invariant below and the alkcall ADRs (ADR-010, ADR-017). 5. **No-env-vars invariant** — no handler reads outbound credentials from any source other than `OperationContext.capabilities`. The credential injection path is vault → assembly layer → `Capabilities` → handler. This is a spec-level invariant, not a runtime convention. 6. **Visible-surface = authorized-surface** — the reason this project exists (a self-hosted gitea got pwned via an internal API reachable over the internet). Every operation exposed on the wire is gated by alkcall's `AccessControl::check(peer_identity)`; ops with `Visibility::Internal` are never wire-callable; no endpoint exists that a caller cannot see themselves authorized for. There is no unauthenticated endpoint unless a repo is explicitly public, and push is always authenticated. This is a spec-level invariant. 7. **gitoxide for git primitives, no shelling out** — storage and pkt-line come from the gix crates (pinned in the crate manifest). The serving path never spawns the `git` binary (no GPL dependency, no process-injection surface). The server half of the smart protocol is ours; see `docs/research/git-protocol.md` for the inventory. 8. **License hygiene** — this project is MIT OR Apache-2.0. Never copy or derive code from MPL-2.0-licensed reference projects; reading gitoxide (MIT OR Apache-2.0) is fine. The policy and the rationale live in `docs/research/reference-policy.md` — do not name the incompatible-licensed project in docs, README, or commit messages. 9. **Wire formats are stable one-way doors** — once a wire surface is published (the git smart protocol is defined upstream and not ours to change; the one existing piece of alkgit-specific framing — the native session preamble, ADR-016 — is pinned and in the OQ-03 freeze inventory), its shape must not change. Protocol capability advertisement is honest: never advertise what we don't serve. 10. **Feature flags** — optional surface is feature-gated: `gix` (default-on; the backend implementations) and `sha256` (hash algorithm passthrough; `sha1` is the default and pinned in the crate manifest). The wire layer compiles without gix (`default-features = false`). Verify both `cargo test` (default) and `cargo test --all-features` pass if features are added. 11. **Bounded resources** — every protocol session carries wall-clock, size, and round limits (max negotiation rounds, max receive-pack size, session timeout). Git servers are internet-facing; unbounded loops and unbounded buffers are bugs. 12. **Repo identity is registry-resolved** — repo names arriving on the wire are IDs resolved against a server-side registry to configured storage roots. Wire-supplied names are never used as filesystem paths directly (path traversal is a protocol-level input, not a config value). 13. **Naming** — Rust standard: `snake_case` for functions/variables/ modules, `PascalCase` for types/traits, `SCREAMING_SNAKE_CASE` for constants. 14. **Module structure** — one module per file under `src/`, re-exported from `src/lib.rs` (the alktty crate-root pattern). Public API surface is `lib.rs` re-exports. Single crate at the repo root (ADR-010); the gix backend implementation lives under the default-on `gix` feature; `default-features = false` gives the wire/protocol layer only. 15. **Composability boundary ("ALPN as a service")** — alkgit is front-door-blind: it consumes (identity, repo id, duplex stream, limits) and depends on alkcall types only, never on alkhttp/alkssh, and carries no http/channel-specific types below the stream. Doors (alkhttp `git` feature, alkssh) are family infrastructure; a downstream app embeds alkgit and brings its own doors. v1 is the reduction to wire layer + backend traits + one gix implementation. ## Verification Commands Run these before committing. All must pass. ```bash cargo test # full suite cargo clippy --all-targets -- -D warnings cargo fmt --check cargo doc --no-deps # if docs changed cargo publish --dry-run --allow-dirty # before a release (per crate) ``` If feature flags are added, also run `cargo test --all-features` and `cargo clippy --all-features --all-targets -- -D warnings`. ## Lifecycle Status The project is in **SDD phase 1** (architecture committed, implementation not yet begun). Phase 0 research is in `docs/research/`; the committed architecture is `docs/architecture/` (ADR-010 is the structural decision: pure protocol crate, `alk/git` ALPN, backend traits, no binary/doors). POC code never merges to main — two modes: branch mode (POC builds on repo code; git branch, findings merged into research docs, branch dropped) or standalone mode (POC independent of repo code; scratch project at `/workspace/`). POCs have relaxed constraints (comments/unwrap acceptable) — they are exploration tools, not production code. Open architecture questions live in `docs/architecture/open-questions.md` (the active set: OQ-03 — partially resolved, the publish freeze inventory — and OQ-05 — sha256 policy, deferred on ecosystem need; OQ-16 — grant-key identity namespace, deferred on the distributed phase. OQ-04 receive-pack, OQ-06 registry backing, and OQ-08 identity model are resolved: ADR-013, ADR-012, ADR-011). Both gate reviews (001 pre-decomposition, 002 post-remediation) are complete and all their findings are resolved (resolutions: ADR-015/016/017/018); the specs are in `reviewed` status and decomposition into implementation tasks may begin. ## Architecture Context - `docs/research/` — phase 0 research (current source of truth for design direction): - `vision.md` — vision, guiding principles, non-goals - `gitoxide.md` — gix capability/version alignment (sha1 feature pinning is mandatory; `default-features = false` without a hash feature does not compile) - `alk-stack.md` — alkcall/alkhttp/alktls/alkvault integration surface - `git-protocol.md` — server-side smart-protocol inventory (what we own: advertisement, ls-refs, fetch negotiation, receive-pack) - `reference-policy.md` — license/reuse policy (MPL-2.0 prior art: facts only, never code) - `pocs.md` — POC-1..3 plan gating phase 0 completion - Sibling crates (published, MIT OR Apache-2.0): `alkcall 0.8` (call + channels RPC with ACL; `BiStream` is the git-session substrate), `alkhttp 0.5` (HTTP serving + call adapters), `alktls 0.1` (rustls + ACME), `alkvault 0.1` (secret encryption). Their architecture docs live in their own repos; alkcall ADRs referenced above are at `/workspace/@alkdev/alkcall/docs/architecture/decisions/`. - gitoxide reference clone: `/workspace/gitoxide` (matches published 0.87.1 plus a few unreleased commits — pin crates.io versions; treat the clone as a reading aid only, never a path dependency).