alkvault 0.1.0

Local key vault: BIP39 mnemonic generation, SLIP-0010 Ed25519 HD key derivation, AES-256-GCM encryption for securing provider keys, credentials, and identity material
Documentation
# 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 <glm-5.2@alk.dev>`). 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.