Files
alkgit/AGENTS.md
T
glm-5.3-flash 4fe5dec0c4 docs: record the live-pg harness env convention in AGENTS.md
The six ALKGIT_SUBSTRATE_PG_* variables, the ALKBLOBS_PG_* fallback,
and the harness defaults are now stated in the operating instructions
so agents run the postgres-feature tests without reconstructing the
convention from task notes (the wave-8 session's request).
2026-10-23 22:43:58 +00:00

15 KiB
Raw Permalink Blame History

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 / 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 the shipped substrate composition (alkstore + alkblobs — ADR-019/021), no binary, no front doors (doors — alkhttp git/lfs features, alkssh — are family infrastructure; see docs/architecture/doors.md). Since ADR-025 (2026-10-20) the repo is a two-member workspace: the protocol core alkgit (root member, src/, tests/ — substrate-free by construction) and the composition alkgit-substrate (substrate/). 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, placed per ADR-025's placement table: sha256 (optional, on alkgit — hash algorithm passthrough; sha1 is the default and pinned in the crate manifest), sqlite (default-on) + postgres + lfs (default-on) on alkgit-substrate (the shipped alkstore/alkblobs composition — substrate.md). The protocol core alkgit carries no substrate dependency at any feature level (structural, ADR-025). Verify cargo test (default), cargo test --all-features, and cargo test -p alkgit 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. Wire-supplied names are never used as filesystem paths directly (path traversal is a protocol-level input, not a config value); after ADR-019 the record carries no path at all — storage is keyed on the resolved id.

  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 its crate's src/, re-exported from the crate root (the alktty crate-root pattern). Public API surface is lib.rs re-exports. ADR-025 made the repo a two-member workspace: the protocol core alkgit (root member) and the composition alkgit-substrate — the backend traits live in the core, the shipped implementation in the substrate crate; the seam is the inter-crate contract.

  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 at the wire layer, never on alkhttp/alkssh, and carries no http/channel-specific types below the stream. Doors (alkhttp git/lfs features, alkssh) are family infrastructure; a downstream app embeds alkgit and brings its own doors. v1 is the reduction to wire layer + backend traits + the substrate composition (ADR-019/021).

Verification Commands

Run these before committing. All must pass.

cargo test                                    # full suite
cargo clippy --all-targets -- -D warnings
cargo fmt --check
cargo doc --no-deps                           # if docs changed
cargo test --manifest-path fuzz/shared/Cargo.toml   # the fuzz corpus gate (stable) — campaigns run only via fuzz/run-detached.sh
cargo publish --dry-run --allow-dirty         # before a release (per crate)

The fuzz corpus gate replays the committed fuzz/corpus/ seeds through every fuzz target's invariant battery (the stable fuzz/shared crate — fuzz/README.md); the fuzzing campaigns themselves run at wave gates and before publish (fuzz/run-detached.sh per target, bounded runtime).

If feature flags are added, also run cargo test --all-features and cargo clippy --all-features --all-targets -- -D warnings.

Live postgres tests (env-gated)

The postgres-feature tests (and any e2e that rides the pg assembly) skip with a clear message unless the harness container is up. With it running (localhost:15432), export:

export ALKGIT_SUBSTRATE_PG_HOST=localhost
export ALKGIT_SUBSTRATE_PG_PORT=15432
export ALKGIT_SUBSTRATE_PG_USER=postgres
export ALKGIT_SUBSTRATE_PG_PASSWORD=poc
export ALKGIT_SUBSTRATE_PG_DB=blobs

then cargo test -p alkgit-substrate --features postgres (live pg green, 0 skips). Each variable also falls back to the same-named ALKBLOBS_PG_* variable (one family container), then to the harness defaults (15432/postgres/poc/blobs); the host variable's absence is the clean-skip signal. Live tests work in unique process-keyed schemas and drop them after.

Task files (taskgraph)

Any file under tasks/ is a taskgraph task. Frontmatter is required (id, name) and its enum fields are closed sets (taskgraph 0.1.3): status: pending|in-progress|completed|failed|blocked (never done or finished), scope: single|narrow|moderate|broad|system, risk: trivial|low|medium|high|critical, impact: isolated|component|phase|project, level: planning|decomposition|implementation|review|research. A file without frontmatter is silently dropped from the graph (validate does not flag it) — prose-only trackers belong under docs/. Run taskgraph validate after writing or editing anything under tasks/; full field semantics live in docs/sdd_process.md §"Task File Format" / §"Categorical Estimates".

Lifecycle Status

The project is in SDD phase 1 (architecture committed, implementation not yet begun; re-baselined 2026-10-19 by the substrate round, ADR-019..023 — the storage is alkstore+alkblobs-based per docs/architecture/substrate.md, and the recomposition POC evidence is docs/research/substrate-recomposition.md

  • the four findings docs). 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; crate granularity + dependency posture superseded by ADR-025, 2026-10-20 — a two-member workspace: protocol core alkgit + composition alkgit-substrate, whose feature placement table is the live feature model). 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/<poc-name>). 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; OQ-05 — sha256 policy, deferred on ecosystem need; OQ-16 — grant-key identity namespace, deferred on the distributed phase; OQ-19 — the implementation-phase wire validations, deferred(scope) on the booked wave item; OQ-20 — LFS row pruning, deferred on row-volume need; OQ-21 — the LFS lock-server build deferred on client need + the composition-validation POC owed pre-publish. OQ-04 receive-pack, OQ-08 identity model are resolved: ADR-013, ADR-011; OQ-06 registry backing is superseded by ADR-019; OQ-17 migrations resolved as ADR-024). Both gate reviews (001 pre-decomposition, 002 post-remediation) are complete and all their findings are resolved (resolutions: ADR-015/016/017/018; OQ-06 registry backing is superseded by ADR-019), and the substrate re-baseline review (review-003, 2026-10-20) settled the re-baseline cycle — all findings fixed same-day, OQ-19 reclassified deferred(scope), and the specs are in reviewed status. Implementation decomposes wave-based per docs/plans/implementation.md (the alkblobs/ADR-025 rhythm: decompose the next wave after the previous wave's review gate; waves 1–5 are the protocol-core track, waves 6–10 the substrate track gated on the core's publish; task files under tasks/implementation/, decomposed one wave at a time).

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.10 (call + channels RPC with ACL; BiStream is the git-session substrate; the gateway ownership-provider threading + loud default, ADR-048), alkhttp 0.8 (HTTP serving + call adapters; door-surface Basic tolerance ADR-073, ownership wiring ADR-072), 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).