Files
alkgit/AGENTS.md
T
glm-5.3-flash a3cdef909b feat: workspace skeleton + phase 0 research docs
- Cargo workspace with 5 sub-crates: alkgit-core (storage),
  alkgit-transport (smart protocol), alkgit-http, alkgit-ssh, alkgitd
  (binary); sha1 pinned through the gix stack, sha256 passthrough feature
- docs/research/: vision, gitoxide alignment, alk stack fit, server-side
  protocol inventory, license/reference policy, POC plan
- AGENTS.md: conventions mirroring alkcall (no comments, thiserror, tokio,
  no secrets on wire/at rest, visible-surface=authorized-surface,
  gitoxide-only serving path, bounded resources, registry-resolved repos)

Verified: cargo build, clippy -D warnings, fmt, test, check --all-features
2026-09-19 15:36:21 +00:00

9.7 KiB

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: <type>(<scope>): <summary> — 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 <glm-5.3-flash@alk.dev>). Do not change git config, skip hooks, or use git commit -i.

Project Conventions (Rust / git-server workspace)

This is alkgit — a self-hosted git server: repository storage, the git smart protocol served over HTTP and SSH interfaces, and the alkgitd binary that assembles it on the alk stack (alkcall, alkhttp, alktls, alkvault) and gitoxide (gix). The project is a cargo workspace of sub-crates under crates/. The conventions below apply to all work in crates/*/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 workspace 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; any alkgit-specific alkgit↔alkgit framing will get ADRs when it exists), 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: sha256 (hash algorithm passthrough; sha1 is the default and pinned in the workspace manifest) and acme (alktls ACME wiring in the binary). Base crates compile lean. 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. Public API surface is lib.rs re-exports. Workspace members under crates/: alkgit-core (storage), alkgit-transport (smart protocol), alkgit-http (http front door), alkgit-ssh (ssh front door), alkgitd (binary).

Verification Commands

Run these before committing. All must pass.

cargo test                                    # full suite (workspace)
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 0 (exploration) — see docs/sdd_process.md and docs/research/README.md. There is no architecture yet (docs/architecture/ is empty; ADR numbering starts at 001 when phase 1 begins). POCs land under .worktrees/research/ or as scratch dirs; their findings go into docs/research/. Until phase 1 produces ADRs, "the architecture says" has no referent — cite docs/research/ docs instead.

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).