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
This commit is contained in:
glm-5.3-flash committed 2026-09-19 15:36:21 +00:00
1 parent a633dddd6b
commit a3cdef909b
20 files changed
+965

No files matched your search

+199
View File
@@ -0,0 +1,199 @@
# 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.
```bash
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).