Concise reference for agents and contributors. Command-first. No prose.
Non-negotiable rule: always test before committing. Never commit to fix a problem you haven't verified is actually fixed.
git status # must show: nothing to commit, working tree clean
git branch # must be on: main
git log --oneline -5 # confirm all feature work is committedIf the tree is dirty, commit or stash all changes first. Never start a release from a dirty tree.
Handles bump → lock rebuild → version verify → commit → tag → push in one command.
# Dry run first (no push, no publish)
pwsh ./release.ps1 -Version X.Y.Z
# Full release: bump, tag, push main + tag, rebuild portable, update PATH
pwsh ./release.ps1 -Version X.Y.Z -AddToPath -Push
# Full release + crates.io publish (only after CI is green)
pwsh ./release.ps1 -Version X.Y.Z -AddToPath -Push -PublishCratesUse -Bump patch|minor|major instead of -Version to auto-calculate the next version.
# Step 1 — bump version (updates Cargo.toml, README, CLAUDE.md, installer)
powershell -ExecutionPolicy Bypass -File bump-version.ps1 -Version X.Y.Z
# Step 2 — rebuild to regenerate Cargo.lock
cargo build
# Step 3 — verify all version surfaces are in sync
powershell -ExecutionPolicy Bypass -File scripts/verify-version-sync.ps1 -Version X.Y.Z -RequireCargoLock
# Step 4 — commit exactly these five files (never git add .)
git add Cargo.toml Cargo.lock README.md CLAUDE.md installer/hematite.iss
git commit -m "chore: bump version to X.Y.Z"
# Step 5 — tag and push (triggers CI)
git tag -a vX.Y.Z -m "Release vX.Y.Z"
git push origin main
git push origin vX.Y.Z
# Step 6 — wait for CI green on BOTH workflows (see CI section below)
# Step 7 — only publish to crates.io after CI is green on all platforms
cargo publish -p hematite-cliBoth must go green before publishing to crates.io:
windows-release— builds--releaseon Windows, packages portable zip + installerunix-release— builds--releaseon Linux/macOS, packages portable tarballs
Check status: gh run list --workflow windows-release.yml and gh run list --workflow unix-release.yml
If either fails: push a patch fix commit to main, then re-tag (delete old tag: git tag -d vX.Y.Z && git push origin :refs/tags/vX.Y.Z, then re-tag). Never publish crates from a red CI state.
When to bump:
PATCH— bug fixes, doc updates, routing fixes, test additionsMINOR— new user-visible features, new inspect_host topics, new TUI commandsMAJOR— breaking config/API changes or first stable release
Do not bump to test whether a fix works. Build the local portable first, verify live, then bump.
Run before every release. All must pass before bumping.
cargo fmt
cargo check --tests
cargo test --test diagnostics
cargo test --test routing_precision
cargo deny check
powershell -ExecutionPolicy Bypass -File scripts/verify-doc-sync.ps1If doc-sync fails: the topic count in README.md, CAPABILITIES.md, or CLAUDE.md is out of sync with src/tools/host_inspect.rs. Update the failing doc to match the actual count, then re-run.
For a targeted single test:
cargo test --test diagnostics test_name_here -- --exact
cargo test --lib tools::verify_build::tests # unit tests for verify_build autodetectBuild the actual portable binary and update PATH before live-testing. Do this before bumping a version.
powershell -ExecutionPolicy Bypass -File scripts/package-windows.ps1 -AddToPathRestart the terminal after running. The hematite command on PATH now points to the new build. Live-test the behavior before committing or bumping anything.
Requires a local OpenAI-compatible runtime running with three models loaded. The verified path is LM Studio with Qwen3.5 9B (main), nomic-embed-text-v2 (search), and Bonsai 8B Q1_0 (privacy summarizer).
$i1 = '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
$i2 = '{"jsonrpc":"2.0","id":2,"method":"initialized","params":{}}'
$c = '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"inspect_host","arguments":{"topic":"summary"}}}'
"$i1`n$i2`n$c" | hematite --mcp-server --semantic-redact --semantic-model bonsai-8b 2>$nullWhat to verify in the output:
- Response 1:
"redactMode":"semantic+regex"and"privacyNote"present - Response 2:
"isError":false - Response 2:
[edge-redact: semantic+regex — local model summary appliedheader present - Response 2: no raw
$env:USERNAMEor$env:COMPUTERNAMEvalues in the text — replaced with[USER]/[HOST]
Without Bonsai loaded (single-model or edge-redact-only test):
"$i1`n$i2`n$c" | hematite --mcp-server --edge-redact 2>$nullVerify: "redactMode":"regex" and [edge-redact: header with substitution count.
Use when a query routes to shell instead of inspect_host, or routes to the wrong topic.
- Check
preferred_host_inspection_topic()insrc/agent/routing.rs— if the topic has no matchingasks_*variable,host_inspection_modeis never injected and the model free-forms. - Add the missing
asks_*variable with natural-language phrases covering the query shape. - Add it to the dispatch chain (
if asks_X { Some("topic") }). Order matters — more specific topics before generic ones (e.g.asks_portsbeforeasks_processes). - Add the same phrase to the matching detector in
all_host_inspection_topics()(multi-topic pre-run table — separate from single-topic routing). - Update the HOST INSPECTION MODE bullet list in
src/agent/conversation.rsso the model knows to use the topic. - Add a
test_routing_detects_*test intests/diagnostics.rscovering 2–3 representative phrases. - Run
cargo test --test diagnostics, build portable, verify the live query. Commit only after live test passes.
Key distinction: preferred_host_inspection_topic() controls single-topic routing. all_host_inspection_topics() controls the multi-topic harness pre-run (fires when 2+ topics detected). A topic can be in one and not the other — always check both.
When adding a new topic to src/tools/host_inspect.rs:
- Implement the inspector function and wire it into the
matchblock. - Add routing phrases to
preferred_host_inspection_topic()insrc/agent/routing.rs. - Add a detector to
all_host_inspection_topics()insrc/agent/routing.rs. - Add a bullet to the HOST INSPECTION MODE list in
src/agent/conversation.rs. - Add a bullet to the capability list in
src/agent/prompt.rs. - Update
CAPABILITIES.mdtopic count and add a row to the matrix. - Update the topic count reference in
README.mdandCLAUDE.md. - Run
powershell -ExecutionPolicy Bypass -File scripts/verify-doc-sync.ps1— must report SUCCESS. - Add tests in
tests/diagnostics.rs: at minimum a header test and a routing detection test. - Build portable, verify live, then commit.
Cross-platform rule: if a parameter is Windows-only, silence it on Unix with let _ = param; — not #[cfg] removal, which causes missed warnings on the other platform.
The verify-doc-sync.ps1 script checks that topic counts are consistent across all docs.
powershell -ExecutionPolicy Bypass -File scripts/verify-doc-sync.ps1Expected output:
SUCCESS: All documentation is synchronized and grounded.
If it fails, the topic count in one of README.md, CAPABILITIES.md, or CLAUDE.md is out of sync with the actual count in src/tools/host_inspect.rs. Update the failing doc to match.
- Publish
hematite-kokorosonly whenlibs/kokoros/source changed. - Publish
hematite-clion every tagged release after CI is green on all platforms. - Never publish from a state where CI is red on any platform — not even one.
- Publish order:
hematite-kokorosfirst (if needed), thenhematite-cli.
# Voice crate (only if libs/kokoros/ changed)
cargo publish -p hematite-kokoros
# Main crate (every release, after CI green)
cargo publish -p hematite-cliLowercase conventional commits only. No co-author lines.
feat: add X
fix: correct Y
refactor: restructure Z
chore: bump version to X.Y.Z
docs: update README
ci: fix cache key in windows workflow
powershell -ExecutionPolicy Bypass -File clean.ps1 # ghost, scratch, memories, sandbox, reports, logs
powershell -ExecutionPolicy Bypass -File clean.ps1 -Deep # + target/, onnx_lib/, vein.db
powershell -ExecutionPolicy Bypass -File clean.ps1 -Deep -PruneDist # + old dist/ artifacts (keeps current version)
powershell -ExecutionPolicy Bypass -File clean.ps1 -Reset # + PLAN.md, TASK.md (full blank-slate)