Skip to content

Development

Requirements

Tool Version Use
Go 1.25 or later Build and test
OpenBao (bao) 2.7.x tested Tutorials and manual tests
curl, python3 any Tutorials
Docker any Building the documentation site

First build

go.sum is committed; go mod verify checks the downloaded modules against it:

go mod verify
go test ./...
go vet ./...
gofmt -l .

Layout

Path What
cmd/keyholder-mcp The MCP server
cmd/khcall The debugging MCP client
internal/ runner, bao, ref, mask (Architecture)
deploy/ Example OpenBao policy
demo/tutorials/ Executable tutorials: run.sh, out/, expected/
docs/ This site (English), docs/pt-BR/ (Portuguese)
.aurumcode/ Code review rules (Code review)
.github/workflows/ CI, code review, documentation site

Tests

go test ./...

The runner tests use a copy of the test binary itself as the child process (TestMain with KH_TEST_HELPER), so they run the same on Windows, Linux and macOS, without a shell.

Tutorials

for t in quickstart access guardrails masking; do
  bash demo/tutorials/$t/run.sh all && bash demo/tutorials/$t/run.sh --check
done

When a change alters an output on purpose, run the tutorial, review out/, copy it to expected/ and commit both. CI fails when out/ and expected/ disagree.

Documentation site

The site is MkDocs Material in a container pinned by digest (scripts/docs/image.lock):

scripts/docs/build.sh     # builds ./site with --strict
scripts/docs/serve.sh     # http://127.0.0.1:8000 with live reload

Tutorial pages include the files in demo/tutorials/*/expected/ at build time, so the outputs on the site are always the checked ones. Every English page has a Portuguese counterpart under docs/pt-BR/; change both in the same pull request.

CI

Workflow Runs
ci.yml The pipeline: gofmt, go vet, go test, go build on Linux, Windows and macOS; every tutorial and its --check on Linux; then, on a pull request, the AurumCode gate (project rules, gitleaks, Semgrep), which never approves
release.yml When main gets a CHANGELOG version with no release yet (or on a v* tag): tests, builds the binaries for six platforms, publishes them with SHA256SUMS and the CHANGELOG section
docs.yml Builds the site with --strict on every PR; publishes it to GitHub Pages from main
attribution.yml The maintainer's own: strips AI attribution from the maintainer's pull requests, issues and comments. Contributors are not affected

AurumCode gate in your agent

.mcp.json registers aurumcode mcp for Claude Code, so the agent can ask the same gate the CI uses (aurum_gate, aurum_review, aurum_rules, aurum_explain) before it commits. It needs the aurumcode binary on the PATH and your key in the shell that starts Claude Code; the key is never written to the file:

read -s LLM_API_KEY && export LLM_API_KEY     # provider defaults: Anthropic, claude-haiku-5-5
claude                                         # approve the project server "aurum" once

Without a working provider the gate answers inconclusive, never pass.

Branches and releases

Two branches only: dev, where every change lands, and main, what is released. main changes only through a pull request from dev, merged with a merge commit after its checks pass; then dev is fast-forwarded to main. Contributors open pull requests into dev from a fork. Details and the exact steps: CONTRIBUTING.md.

To release, move the ## Unreleased entries under ## X.Y.Z - date in CHANGELOG.md on dev and ship it to main. release.yml sees a version without a release, creates the tag vX.Y.Z on that commit and publishes the binaries.

Contributing

See CONTRIBUTING.md: branch from dev, test, update both languages of the docs and the CHANGELOG, open the pull request into dev.

English is the primary language of the repository: code, comments, messages and commits. Portuguese is the second language of the documentation.