diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..28bb1f0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,126 @@ +# 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." + +The workflow: + +1. Make the change +2. Verify: `cargo test --all-features`, `cargo clippy --all-features + --all-targets`, `cargo doc --no-deps --all-features` 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 matching the repo style (see `git log + --oneline -10`). 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 + (this repo is on crates.io; `EncryptedData` is frozen per ADR-018) +- 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.2 `). Do not +change `git config`, skip hooks, or use `git commit -i`. + +## Project Conventions (Rust / cryptographic library) + +This is a cryptographic vault crate. 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., "fresh per call — IV reuse under the same key is + catastrophic"). + +2. **Error handling** — `thiserror` for library error types, `anyhow` for + application code (this crate is a library; use `thiserror`). 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. **Cryptographic nonces use `OsRng`** — AES-GCM IVs and any other + cryptographic nonces must use `SysRng`/`OsRng` (or equivalent CSPRNG), + never `rand::random()`. IV reuse under the same key is catastrophic + for GCM (authenticity breaks, two-time-pad on plaintext). See + `docs/architecture/encryption.md` §Security Constraints. + +4. **Secret material is zeroized on drop** — any type holding derived + keys, decrypted credentials, or other secret material must derive + `Zeroize` and `ZeroizeOnDrop`. Secrets must not linger in freed heap + memory. See `EncryptionKey` and `Seed` for the pattern. + +5. **Feature flags** — `secp256k1` is a feature gate for the Ethereum + BIP-0032 derivation path. The base crate compiles lean (no networking, + no `tokio`, no `secp256k1` unless the feature is on). Verify both + `cargo test` (default) and `cargo test --all-features` pass. + +6. **No `async`** — this crate is synchronous (`std::sync::RwLock`, + direct method calls). No `tokio` dependency (ADR-025). Do not + introduce `async`/`.await` or async-sync primitives. + +7. **Naming** — Rust standard: `snake_case` for functions/variables/ + modules, `PascalCase` for types/traits, `SCREAMING_SNAKE_CASE` for + constants. + +8. **Module structure** — one module per file under `src/`, re-exported + from `src/lib.rs`. Public API surface is `lib.rs` re-exports. + +9. **Wire format is frozen** — `EncryptedData` is a stable wire format + shared with `alknet-storage` and the TypeScript `@alkdev/storage` + consumer by type-level agreement (ADR-018). Fields, encoding, and + semantics are locked. No field may be removed or renamed; new fields + must be optional (default on deserialization) and must not change the + meaning of existing fields. The `salt` field is unused in v2 key + derivation (ADR-020) but retained for wire-format compatibility — do + not remove it. + +## Verification Commands + +Run these before committing. All must pass. + +```bash +cargo test --all-features # full suite (~108 tests) +cargo test # default features (~101 tests) +cargo clippy --all-features --all-targets +cargo doc --no-deps --all-features # if docs changed +cargo publish --dry-run --all-features --allow-dirty # before a release +``` + +## Architecture Context + +- `docs/architecture/` — the authoritative spec. Read it before + non-trivial changes. ADRs are numbered; OQs (open questions) track + resolved/deferred decisions. +- ADR-018 — vault standalone, `EncryptedData` wire format lock +- ADR-020 — HD derivation for encryption keys, salt unused in v2 +- ADR-021 — key rotation via version-indexed derivation paths +- ADR-025 — local-only dispatch, no `async`/`tokio`/irpc +- If a TODO references a "Phase B" or a design direction that an ADR + has since decided against, the TODO is stale — remove it and align + the comments with the ADR. Do not implement the rejected design. \ No newline at end of file