You are an experienced, pragmatic software engineering AI agent. Do not over-engineer a solution when a simple one is possible. Keep edits minimal. If you want an exception to ANY rule, you MUST stop and get permission first.
himitsu (秘密, "secret") is an age-based secret management CLI with transport-agnostic sharing. Secrets are encrypted with age x25519 keys, stored one-file-per-key (.himitsu/secrets/<path>.age) in git-backed stores, and shared via signed envelopes over GitHub PR inboxes or Nostr — never as plaintext.
The project is undergoing a full Rust rewrite from a legacy shell implementation. See docs/IMPLEMENTATION_PLAN.md for the current phase status and open work.
| Area | Detail |
|---|---|
| Language | Rust (CLI binary), TypeScript/Bun (TUI) |
| Crypto | age crate (x25519 encryption), Ed25519 (envelope signing) |
| Storage | Local filesystem (XDG: ~/.local/share/himitsu/, ~/.local/state/himitsu/), SQLite index (rusqlite) |
| Serialization | serde_json, serde_yaml, prost (protobuf for config schema) |
| CLI framework | clap v4 (derive macros) |
| Error handling | thiserror |
| Logging | tracing + tracing-subscriber |
| Dev environment | Nix flake (flake.nix) |
| CI | GitHub Actions (Ubuntu + macOS) |
| Issue tracking | bd (beads) — see Beads Issue Tracker |
Key design invariants:
- Zero plaintext at rest — secrets are always encrypted before hitting the filesystem.
- Transport is untrusted — only envelope signatures and age encryption protect secrets; the transport layer (GitHub, Nostr, etc.) is never trusted.
- One file per secret —
.himitsu/secrets/<path>.agekeeps diffs readable and listing fast without any decryption.
himitsu/
├── rust/src/
│ ├── main.rs # Entrypoint, CLI dispatch
│ ├── error.rs # HimitsuError enum (all error variants)
│ ├── git.rs # git CLI wrapper
│ ├── cli/ # One file per subcommand
│ │ ├── mod.rs # Cli struct + command dispatch
│ │ ├── init.rs, set.rs, get.rs, ls.rs
│ │ ├── encrypt.rs, decrypt.rs, sync.rs, search.rs
│ │ ├── recipient.rs, group.rs, remote.rs, share.rs
│ │ ├── inbox.rs, import.rs, schema.rs, codegen.rs
│ │ └── git.rs
│ ├── config/mod.rs # Mode detection, config loading/validation
│ ├── crypto/ # age encryption/decryption, Ed25519
│ ├── remote/ # Remote resolution, secret file I/O, sync
│ ├── index/mod.rs # SQLite cross-remote search index
│ ├── keyring/ # OS keychain adapters (macOS, etc.)
│ └── proto/mod.rs # Protobuf-generated config schema models
├── tests/integration/
│ └── cli_test.rs # All integration tests (assert_cmd pattern)
├── proto/ # .proto source files (compiled by build.rs)
├── tui/ # Bun/TypeScript terminal UI (@opentui/core)
├── docs/
│ ├── ARCHITECTURE.md # Full system design
│ ├── IMPLEMENTATION_PLAN.md # Phase-by-phase execution plan (update this!)
│ ├── SHARING.md # Envelope / transport protocol spec
│ ├── BACKENDS.md, SERVER_API.md, USE_CASES.md
├── action/entrypoint.sh # GitHub Actions entrypoint
├── build.rs # Proto compilation (prost-build)
├── flake.nix # Nix dev environment + package
└── Cargo.toml # Single-binary workspace
| Module | Responsibility |
|---|---|
cli/ |
Command parsing and UX; one file per subcommand |
config/ |
Project-mode vs user-mode detection; config schema |
crypto/ |
age encrypt/decrypt; Ed25519 envelope signing |
remote/ |
Remote discovery, secret file I/O, sync destinations |
index/ |
SQLite secret index for cross-remote search |
keyring/ |
OS keychain adapters for local age key storage |
proto/ |
Protobuf models (generated from proto/*.proto) |
error.rs |
HimitsuError — all error variants live here |
~/.local/share/himitsu/ # XDG data dir
key # age private key
key.pub # age public key
~/.local/state/himitsu/ # XDG state dir
himitsu.db # Cross-remote search index (SQLite)
stores/<org>/<repo>/ # Store checkouts
.himitsu/
secrets/<path>.age # Encrypted secret files
recipients/<group>/*.pub # Recipient age pubkeys
config.yaml # Store config (recipients_path override, etc.)
himitsu.yaml # Remote policy config
data.json # Group/env metadata
cargo build # Debug build
cargo build --release # Release build
cargo fmt --all # Format code
cargo fmt --all -- --check # Check formatting (CI gate)
cargo clippy --workspace --all-targets -- -D warnings # Lint (CI gate)
cargo test --workspace # All tests
cargo test --lib # Unit tests only
cargo test --test '*' # Integration tests only
cargo test --test cli_test <fn_name> -- --nocapture # Single integration test
cargo insta test # Run snapshot tests
cargo insta review # Review/accept snapshot changescd tui
bun install # Install dependencies
bun run check # Type-check (tsc --noEmit)
bun run dev # Run TUInix develop # Enter dev shell
nix build # Build the package
nix flake check # Verify full Nix package (run after Nix/dep changes)All integration tests live in tests/integration/cli_test.rs and use assert_cmd + tempfile. The env var HIMITSU_HOME (not HOME) isolates the himitsu key store; --store isolates the project secret store. Do not rely on the developer's real home directory.
use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::TempDir;
fn himitsu() -> Command {
Command::cargo_bin("himitsu").unwrap()
}
/// Canonical setup helper — mirrors the one in cli_test.rs
fn setup() -> (TempDir, TempDir) {
let home = TempDir::new().unwrap();
let project = TempDir::new().unwrap();
himitsu()
.env("HIMITSU_HOME", home.path())
.args([
"--store",
&project.path().join(".himitsu").to_string_lossy(),
"init",
])
.assert()
.success();
(home, project)
}
#[test]
fn test_new_feature() {
let (home, project) = setup();
himitsu()
.env("HIMITSU_HOME", home.path())
.args(["--store", &project.path().join(".himitsu").to_string_lossy(), "mycmd", "--flag"])
.assert()
.success()
.stdout(predicate::str::contains("expected output"));
}Add all new error variants to HimitsuError in rust/src/error.rs:
#[derive(Debug, thiserror::Error)]
pub enum HimitsuError {
#[error("config not found: {0}")]
ConfigNotFound(String),
// ...
}Return Result<T, HimitsuError> from all failable functions. Never use anyhow or Box<dyn Error> in library/core code.
- Create
rust/src/cli/<name>.rswith apub struct <Name>Args(clap derive) andpub fn run(args: <Name>Args) -> Result<(), HimitsuError>. - Register it in
rust/src/cli/mod.rsunder theCommandsenum. - Dispatch it in
main.rs. - Add integration tests in
tests/integration/cli_test.rsusing the setup pattern above. - Check off the matching item in
docs/IMPLEMENTATION_PLAN.md.
When completing any planned work:
- Open
docs/IMPLEMENTATION_PLAN.md. - Change
- [ ]→- [x]for the matching item. - If it was the last item in a phase, check the phase header too.
- Do NOT write plaintext secrets to disk.
bulk decryptis intentionally unsupported. Usehimitsu get <path>to read individual values. - Do NOT use
HOMEin tests. UseHIMITSU_HOMEto isolate himitsu's key store in integration tests (see pattern above). - Do NOT use
anyhoworBox<dyn Error>in library code. All errors must be typedHimitsuErrorvariants. - Do NOT manually format code. Let
rustfmthandle it; never add#[rustfmt::skip]without explicit permission. - Do NOT add external dependencies without discussion. Prefer established crates (
serde,clap,thiserror,tracing,rusqlite); keep the dependency surface minimal. - Do NOT add markdown TODO lists. Use
bdfor all task tracking.
- Formatting:
rustfmt(enforced in CI — zero tolerance for format violations). - Naming:
snake_casefunctions/variables/modules,PascalCasetypes/traits/enums,SCREAMING_SNAKE_CASEconstants. - Imports: group
std→ external crates → internal modules, separated by blank lines. - Logging:
tracingmacros for internal diagnostics;println!/eprintln!only for user-facing CLI output.
- Strict types — no
any. Define interfaces for all data shapes. - ES modules only (
"type": "module"inpackage.json). - Favor immutable state updates.
cargo fmt --all -- --check # Must pass
cargo clippy --workspace --all-targets -- -D warnings # Must pass
cargo test --workspace # Must pass
cd tui && bun run check # If TUI was changedCI enforces all three Rust gates on every push to main and every PR.
Use type: short description (≤72 chars), e.g.:
feat: add recipient rm subcommand
fix: handle missing config.yaml gracefully
test: add integration tests for group lifecycle
chore: update clap to 4.5
docs: update implementation plan phase 1 status
Types: feat, fix, test, chore, docs, refactor, perf.
- All CI checks green (fmt, clippy, tests on Ubuntu + macOS).
- Include a brief description of what changed and why.
- Reference the relevant
bdissue ID if one exists (e.g.,closes bd-42). - Update
docs/IMPLEMENTATION_PLAN.mdcheckboxes if the PR completes planned work.
IMPORTANT: This project uses bd (beads) for ALL issue tracking. Do NOT use markdown TODOs, task lists, or other tracking methods.
- Dependency-aware: Track blockers and relationships between issues
- Git-friendly: Dolt-powered version control with native sync
- Agent-optimized: JSON output, ready work detection, discovered-from links
- Prevents duplicate tracking systems and confusion
Check for ready work:
bd ready --jsonCreate new issues:
bd create "Issue title" --description="Detailed context" -t bug|feature|task -p 0-4 --json
bd create "Issue title" --description="What this issue is about" -p 1 --deps discovered-from:bd-123 --jsonClaim and update:
bd update <id> --claim --json
bd update bd-42 --priority 1 --jsonComplete work:
bd close bd-42 --reason "Completed" --jsonbug- Something brokenfeature- New functionalitytask- Work item (tests, docs, refactoring)epic- Large feature with subtaskschore- Maintenance (dependencies, tooling)
0- Critical (security, data loss, broken builds)1- High (major features, important bugs)2- Medium (default, nice-to-have)3- Low (polish, optimization)4- Backlog (future ideas)
- Check ready work:
bd readyshows unblocked issues - Claim your task atomically:
bd update <id> --claim - Work on it: Implement, test, document
- Discover new work? Create linked issue:
bd create "Found bug" --description="Details about what was found" -p 1 --deps discovered-from:<parent-id>
- Complete:
bd close <id> --reason "Done"
- Use
--acceptanceand--designfields when creating issues - Use
--validateto check description completeness
bd defer <id>/bd supersede <id>for issue managementbd stale/bd orphans/bd lintfor hygienebd human <id>to flag for human decisionsbd formula list/bd mol pour <name>for structured workflows
bd stores issue history in Dolt:
- Each write auto-commits to Dolt history
- Use
bd dolt push/bd dolt pullfor remote sync - Do not treat
.beads/issues.jsonlas the sync protocol
Architecture in one line: issues live in a local Dolt DB; sync uses refs/dolt/data on your git remote; .beads/issues.jsonl is a passive export. See https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md for details and anti-patterns.
- ✅ Use bd for ALL task tracking
- ✅ Always use
--jsonflag for programmatic use - ✅ Link discovered work with
discovered-fromdependencies - ✅ Check
bd readybefore asking "what should I work on?" - ❌ Do NOT create markdown TODO lists
- ❌ Do NOT use external issue trackers
- ❌ Do NOT duplicate tracking systems
For more details, see README.md and docs/QUICKSTART.md.
The managed Beads block is task-tracking guidance, not permission to override repository, user, or orchestrator instructions.
- Conservative (default): Use
bdfor task tracking. Do not run git commits, git pushes, or Dolt remote sync unless explicitly asked. At handoff, report changed files, validation, and suggested next commands. - Minimal: Keep tool instruction files as pointers to
bd prime; use the same conservative git policy unless active instructions say otherwise. - Team-maintainer: Only when the repository explicitly opts in, agents may close beads, run quality gates, commit, and push as part of session close. A current "do not commit" or "do not push" instruction still wins.
This protocol applies when ending a Beads implementation workflow. It is subordinate to explicit user, repository, and orchestrator instructions.
- File issues for remaining work - Create beads for anything that needs follow-up
- Run quality gates (if code changed) - Tests, linters, builds
- Update issue status - Close finished work, update in-progress items
- Handle git/sync by active profile:
# Conservative/minimal/default: report status and proposed commands; wait for approval. git status # Team-maintainer opt-in only, unless current instructions forbid it: git pull --rebase bd dolt push git push git status
- Hand off - Summarize changes, validation, issue status, and any blocked sync/commit/push step
Critical rules:
- Explicit user or orchestrator instructions override this Beads block.
- Do not commit or push without clear authority from the active profile or the current user request.
- If a required sync or push is blocked, stop and report the exact command and error.
This project uses beads_rust (br) for issue tracking and beads_viewer (bv) for graph-aware triage. Issues are stored in .beads/ and tracked in git.
bv is a graph-aware triage engine for Beads projects (.beads/beads.jsonl). Instead of parsing JSONL or hallucinating graph traversal, use robot flags for deterministic, dependency-aware outputs with precomputed metrics (PageRank, betweenness, critical path, cycles, HITS, eigenvector, k-core).
Scope boundary: bv handles what to work on (triage, priority, planning). br handles creating, modifying, and closing beads.
CRITICAL: Use ONLY --robot- flags. Bare bv launches an interactive TUI that blocks your session.*
bv --robot-triage is your single entry point. It returns everything you need in one call:
quick_ref: at-a-glance counts + top 3 picksrecommendations: ranked actionable items with scores, reasons, unblock infoquick_wins: low-effort high-impact itemsblockers_to_clear: items that unblock the most downstream workproject_health: status/type/priority distributions, graph metricscommands: copy-paste shell commands for next steps
bv --robot-triage # THE MEGA-COMMAND: start here
bv --robot-next # Minimal: just the single top pick + claim command
# Token-optimized output (TOON) for lower LLM context usage:
bv --robot-triage --format toon| Command | Returns |
|---|---|
--robot-plan |
Parallel execution tracks with unblocks lists |
--robot-priority |
Priority misalignment detection with confidence |
--robot-insights |
Full metrics: PageRank, betweenness, HITS, eigenvector, critical path, cycles, k-core |
--robot-alerts |
Stale issues, blocking cascades, priority mismatches |
--robot-suggest |
Hygiene: duplicates, missing deps, label suggestions, cycle breaks |
--robot-diff --diff-since <ref> |
Changes since ref: new/closed/modified issues |
--robot-graph [--graph-format=json|dot|mermaid] |
Dependency graph export |
bv --robot-plan --label backend # Scope to label's subgraph
bv --robot-insights --as-of HEAD~30 # Historical point-in-time
bv --recipe actionable --robot-plan # Pre-filter: ready to work (no blockers)
bv --recipe high-impact --robot-triage # Pre-filter: top PageRank scoresbr ready # Show issues ready to work (no blockers)
br list --status=open # All open issues
br show <id> # Full issue details with dependencies
br create --title="..." --type=task --priority=2
br update <id> --status=in_progress
br close <id> --reason="Completed"
br close <id1> <id2> # Close multiple issues at once
br sync --flush-only # Export DB to JSONL- Triage: Run
bv --robot-triageto find the highest-impact actionable work - Claim: Use
br update <id> --status=in_progress - Work: Implement the task
- Complete: Use
br close <id> - Sync: Always run
br sync --flush-onlyat session end
- Dependencies: Issues can block other issues.
br readyshows only unblocked work. - Priority: P0=critical, P1=high, P2=medium, P3=low, P4=backlog (use numbers 0-4, not words)
- Types: task, bug, feature, epic, chore, docs, question
- Blocking:
br dep add <issue> <depends-on>to add dependencies
git status # Check what changed
git add <files> # Stage code changes
br sync --flush-only # Export beads changes to JSONL
git commit -m "..." # Commit everything
git push # Push to remoteUse Beads (bd) for durable task tracking in repositories that include it. Use the beads skill at .agents/skills/beads/SKILL.md (project install) or ~/.agents/skills/beads/SKILL.md (global install) for Beads workflow guidance, then use the bd CLI for issue operations.
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --claim # Claim work
bd close <id> # Complete work
bd prime # Refresh Beads context- Use
bdfor all task tracking; do not create markdown TODO lists. - Run
bd primewhen Beads context is missing or stale. Codex 0.129.0+ can load Beads context automatically through native hooks; use/hooksto inspect or toggle them. - Keep persistent project memory in Beads via
bd remember; do not create ad hoc memory files.
Architecture in one line: issues live in a local Dolt DB; sync uses refs/dolt/data on your git remote; .beads/issues.jsonl is a passive export. See https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md for details and anti-patterns.