# Hematite Maintainer Workflows
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.**
---
## 1. Release Workflow
### Prerequisites — check before starting
```powershell
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 committed
```
If the tree is dirty, commit or stash all changes first. Never start a release from a dirty tree.
### Option A — release.ps1 wrapper (recommended)
Handles bump → lock rebuild → version verify → commit → tag → push in one command.
```powershell
# 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 -PublishCrates
```
Use `-Bump patch|minor|major` instead of `-Version` to auto-calculate the next version.
### Option B — manual steps
```powershell
# 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-cli
```
### CI workflows to monitor after pushing the tag
Both must go green before publishing to crates.io:
- **`windows-release`** — builds `--release` on Windows, packages portable zip + installer
- **`unix-release`** — builds `--release` on 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 additions
- `MINOR` — new user-visible features, new inspect_host topics, new TUI commands
- `MAJOR` — 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.
---
## 2. Pre-Release Verification Loop
Run before every release. All must pass before bumping.
```powershell
cargo fmt
cargo check --tests
cargo test --test diagnostics
cargo test --test routing_precision
powershell -ExecutionPolicy Bypass -File scripts/verify-doc-sync.ps1
```
If 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:
```powershell
cargo test --test diagnostics test_name_here -- --exact
cargo test --lib tools::verify_build::tests # unit tests for verify_build autodetect
```
---
## 3. Local Portable Build (Smoke Test)
Build the actual portable binary and update PATH before live-testing. Do this before bumping a version.
```powershell
powershell -ExecutionPolicy Bypass -File scripts/package-windows.ps1 -AddToPath
```
Restart the terminal after running. The `hematite` command on PATH now points to the new build. Live-test the behavior before committing or bumping anything.
### MCP Semantic Redact Smoke Test
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).
```powershell
$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"}}}'
**What 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 applied` header present
- Response 2: no raw `$env:USERNAME` or `$env:COMPUTERNAME` values in the text — replaced with `[USER]` / `[HOST]`
Without Bonsai loaded (single-model or edge-redact-only test):
```powershell
Verify: `"redactMode":"regex"` and `[edge-redact:` header with substitution count.
---
## 4. Routing Fix Workflow
Use when a query routes to `shell` instead of `inspect_host`, or routes to the wrong topic.
1. Check `preferred_host_inspection_topic()` in `src/agent/routing.rs` — if the topic has no matching `asks_*` variable, `host_inspection_mode` is never injected and the model free-forms.
2. Add the missing `asks_*` variable with natural-language phrases covering the query shape.
3. Add it to the dispatch chain (`if asks_X { Some("topic") }`). Order matters — more specific topics before generic ones (e.g. `asks_ports` before `asks_processes`).
4. Add the same phrase to the matching detector in `all_host_inspection_topics()` (multi-topic pre-run table — separate from single-topic routing).
5. Update the HOST INSPECTION MODE bullet list in `src/agent/conversation.rs` so the model knows to use the topic.
6. Add a `test_routing_detects_*` test in `tests/diagnostics.rs` covering 2–3 representative phrases.
7. 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.
---
## 5. Adding a New inspect_host Topic
When adding a new `topic` to `src/tools/host_inspect.rs`:
1. Implement the inspector function and wire it into the `match` block.
2. Add routing phrases to `preferred_host_inspection_topic()` in `src/agent/routing.rs`.
3. Add a detector to `all_host_inspection_topics()` in `src/agent/routing.rs`.
4. Add a bullet to the HOST INSPECTION MODE list in `src/agent/conversation.rs`.
5. Add a bullet to the capability list in `src/agent/prompt.rs`.
6. Update `CAPABILITIES.md` topic count and add a row to the matrix.
7. Update the topic count reference in `README.md` and `CLAUDE.md`.
8. Run `powershell -ExecutionPolicy Bypass -File scripts/verify-doc-sync.ps1` — must report SUCCESS.
9. Add tests in `tests/diagnostics.rs`: at minimum a header test and a routing detection test.
10. 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.
---
## 6. Doc Sync Verification
The `verify-doc-sync.ps1` script checks that topic counts are consistent across all docs.
```powershell
powershell -ExecutionPolicy Bypass -File scripts/verify-doc-sync.ps1
```
Expected 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.
---
## 7. Crates.io Publish Rules
- Publish `hematite-kokoros` **only** when `libs/kokoros/` source changed.
- Publish `hematite-cli` on 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-kokoros` first (if needed), then `hematite-cli`.
```powershell
# Voice crate (only if libs/kokoros/ changed)
cargo publish -p hematite-kokoros
# Main crate (every release, after CI green)
cargo publish -p hematite-cli
```
---
## 8. Commit Style
Lowercase 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
```
---
## 9. Cleanup
```powershell
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)
```