// repository workflow
Development Guide
Hovel is a Bazel monorepo operated through Aspect CLI. The checked-in
.aspect/ commands compose pinned toolchains and declared targets so
contributors and CI use the same build graph.
Everyday commands
| Command | Purpose |
|---|---|
aspect hovel-check | Run the complete non-publishing gate for repository policy, core, SDKs, example modules, modules, docs, and agent integrations. |
aspect hovel-check <scope> | Check one of repo, core, sdk, module-examples, modules, docs, or agent. |
aspect hovel-format | Format the wired Go, Python, Rust, and Squatter sources and refresh Gazelle metadata. |
aspect hovel-report | Run report-producing tests and materialize the evidence-backed static site. |
aspect hovel-release <kind> | Build, without publishing, hovel, sdk, modules, picblobs, picblobs-cli, or agent artifacts. |
aspect hovel <mode> -- … | Run the development CLI, daemon, MCP adapter, status, initialization, throw, or session workflow. |
aspect build|test|run … | Address a declared Bazel target through the repository's selected configuration. |
Repository slices
| Path | Owns | Focused gate |
|---|---|---|
core/ | Daemon, front ends, domain, application services, storage, and core build tooling. | aspect hovel-check core |
sdk/ | Public Go, Python, and Rust module authoring contracts. | aspect hovel-check sdk |
modules/examples/ | Cross-language compatibility examples. | aspect hovel-check module-examples |
modules/ | Integrated modules, including Squatter and Picblobs. | aspect hovel-check modules |
docs/ | Book content, module manuals, generated API references, demos, and the static site. | aspect hovel-check docs |
agent/ | Canonical Agent Skills and Claude, Codex, and OpenCode distribution packaging. | aspect hovel-check agent |
These are ownership boundaries, not permission to bypass the root build graph. Cross-slice dependencies should use narrow public labels and public SDK or wire contracts rather than importing core internals.
Hermetic tool ownership
Bazel owns build, lint, test, documentation, and demo tools whenever practical: pinned archives, Python wheels, and Go, Rust, C, and cross-compilation toolchains. Host services are reserved for real system boundaries such as Docker, Wine, tmux, ttyd, or ffmpeg. Repository tooling that materializes generated output is a declared Bazel-run program with explicit data dependencies.
BuildBuddy and CI
Select buildbuddy in the ignored .hovel-bazel-config
file to use the organization's remote cache, execution service, and build event
UI. Both workspaces declare the same digest-pinned Ubuntu worker image with
action networking disabled. Language runtimes, compilers, and compiler support
libraries are inputs in the Bazel graph; the worker image supplies the OS.
Keep the API key in ~/.config/hovel/buildbuddy.bazelrc with mode
0600. Its only setting is
build:buildbuddy --remote_header=x-buildbuddy-api-key=YOUR_KEY.
Import that file by its absolute path from both ignored
.bazelrc.user and core/.bazelrc.user using
try-import /absolute/path/to/buildbuddy.bazelrc.
Credentials never belong in tracked rc files or command-line arguments.
CI dependency caches are isolated by check scope and release family, with
toolchain definitions included in their keys. Job summaries show complete
Aspect task times, including host executables; nested task times overlap.
To inspect a completed run, use
aspect run //repo-tools/tasks:ci_audit -- --run-id=RUN_ID --credential-file=/path/to/private/buildbuddy.bazelrc --output=/path/to/audit.json.
The audit uses GitHub authentication from the environment or GitHub CLI and
records only selected timings and cache counters. Logical and transferred
bytes include repeated worker reads, not just downloads to the CI runner.
Aspect adds invocation metadata following the BuildBuddy metadata guide: repository, checked-out commit, branch, and worktree state. GitHub runs also carry the actor, CI role, workflow, job or matrix scope, run attempt, event, and logical Aspect step. BuildBuddy links lead back to the exact GitHub Actions attempt, source commit, and pull request. The commit describes the actual checkout, including GitHub's PR merge commit, rather than assuming that the event SHA is the source built by a manually selected release. These are invocation fields; changing them does not stamp or invalidate compiled artifacts. Indexed tags are limited to project, worktree state, and a bounded job name so long command lines cannot exceed BuildBuddy's tag storage limit.
Set the GitHub Actions secret BUILDBUDDY_API_KEY to enable remote
execution in CI and release jobs. The shared setup action invokes
aspect hovel-ci setup, writes a mode-0600 credential rc under
RUNNER_TEMP, and exports its path. Without the secret, fork PRs and
Dependabot builds use local execution while retaining the same Aspect gates.
CI metadata configuration alone does not enable a remote service.
The setup action disables setup-aspect's additional disk and repository caches:
BuildBuddy owns action caching, and the shared GitHub cache stores only dependency
downloads. The Aspect launcher and CLI are pinned together.
Each job finishes with a table of BuildBuddy invocations and their results, including incomplete invocations from failed builds, then removes its credential file. Summaries read only allowlisted fields from local build events; raw event files and rc files are never uploaded as artifacts. Results retain BuildBuddy's authenticated visibility and default environment redaction. GitHub job checks aggregate the Aspect workflow; per-invocation BuildBuddy commit statuses are disabled to avoid a competing set of checks. Aspect's automatic GitHub comments, check runs, and artifact uploads are also disabled; the explicit workflow steps own those surfaces without an Aspect API token or extra CI write permissions.
CI uses a matrix for the repository, core, SDK, example, module, and agent
scopes, with separate evidence-backed docs and Wine jobs. The scopes keep their
stable check names, continue independently on failure, and have explicit timeouts.
Build artifacts are retained for 14 days and failed test logs for seven days.
Wine and Docker are host-service boundaries; aspect hovel-ci wine
keeps Wine tests on the runner while compilation uses remote workers. The report
workflow downloads remote test outputs for the assembled evidence-backed site.
Pages promotes the exact artifact from a successful main push; only a manual
Pages dispatch rebuilds it. OIDC and write permissions belong to publishing jobs.
Runner bootstrap and summary programs use only the host Python standard library
through aspect hovel-ci: they must work before Bazel authentication
exists and after a build fails. Their regression tests and the pinned Actionlint
binary run through aspect hovel-check repo.
Definition of done
- Run the focused scope while iterating.
- Run
aspect hovel-formatafter source or import changes. - Run
aspect hovel-checkbefore considering a full-repository change complete. - For public SDK or module protocol changes, run
aspect hovel-reportand inspect the compatibility and branch-coverage evidence. - For docs-only changes, at minimum run
aspect hovel-check docs; use the report command when the materialized site must contain current evidence.
Design boundaries
Core follows inward dependencies: adapters and infrastructure call application services, which call the pure domain. Front ends do not reach around application services, and modules depend on public descriptors rather than internal packages. Preserve defensive copies and constructor validation at boundaries. Changes to throw planning, confirmation, dangerous-module checks, or audit events must retain the safety rules in Safety and Guardrails.
Release procedure
Hovel releases are driven by an annotated v* tag whose version matches
the committed VERSION. The release workflow accepts the tag only when its
commit is contained in main, runs the complete non-publishing gate, builds
every artifact through Aspect, publishes Python distributions with trusted
publishing, and creates the GitHub Release last.
aspect run //core/tools/release:upver -- 0.4.0
aspect hovel-format
aspect hovel-check
# After merge and a successful build-only workflow dispatch on main:
git tag -a v0.4.0 -m "Hovel v0.4.0"
git push origin v0.4.0
Do not manually create the GitHub Release first. Rerun the same tag workflow after a
transient failure; publication verifies existing PyPI filenames and hashes rather
than replacing immutable files. Hovel and hovel-sdk share the Hovel
version. Picblobs and picblobs-cli retain their own synchronized version
and are published change-aware as part of the release train.
PyPI trusted publishers must name release.yml. Hovel projects use the
pypi environment; Picblobs projects use
pypi-picblobs and pypi-picblobs-cli. Only publishing jobs
receive OIDC permission, and only the terminal GitHub Release job receives repository
write permission.