- Tests now use a read-only dir inside the bound workspace as HOME, so the red-proofs don't depend on where the temp dir or repo lives. - USER_GUIDE idle check passes --rig (needed outside a managed seat). - SEAT-WRITE-SCOPES maps the omni command-pod seats to their rows, generated from fleet.yaml omni.core_pod. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VjcGdhFQxjHWWV9xxvurqs
38 KiB
Heretek-Rigs Operator & User Guide
Welcome to the operator manual for heretek-rigs — the 51-agent, 8-rig software engineering fleet built on OpenRig v0.7.5 (rig), Pi Coding Agent v1.4.0 (pi), @gotgenes/[email protected], and OpenCode Go (opencode-go/muse-spark-1.3-contributor:high).
This guide walks you through installing prerequisites, provisioning zero-leak secrets, seeding isolated seat directories, launching and operating domain rigs, dynamically scaling the heretek-omni-fleet command center, running Docker sidecars safely, customizing the fleet catalog, and troubleshooting common issues.
1. Prerequisites & Toolchain Installation
System Requirements
| Component | Required Version | Purpose |
|---|---|---|
| Operating System | Linux or macOS (WSL2 on Windows) | Host environment for OpenRig daemon, tmux sessions, and Docker sidecars. |
| Node.js & npm | Node.js 22.x or 24.x (>=22.19.0) |
Required by @openrig/[email protected] (better-sqlite3 ABI) and @earendil-works/[email protected]. (Node 20 is unsupported.) |
| tmux | 3.2+ |
Terminal multiplexer backing all OpenRig agent seats. |
| Python 3 | 3.10+ with pyyaml and jsonschema (or uv) |
Runs generate-rigs.py, render-seat.py, seed-rig.py, verify-rigs.sh, and audit_loop.py. All scripts automatically fall back to uv run --with pyyaml --with jsonschema if uv is installed. |
| Docker & Compose | Docker Engine + docker compose v2 |
Optional for core rig launch; required when starting supporting sidecar profiles (docker-compose.sidecars.yml) or the terraform MCP container. |
Step 1: Install OpenRig CLI (rig) and Pi Coding Agent (pi)
Install the exact pinned versions of the OpenRig CLI (@openrig/[email protected]) and Pi Coding Agent (@earendil-works/[email protected]) globally:
⚠ Existing operators — snapshot before upgrading: 0.7.5 applies one-way daemon DB migration 126 (
escalation_target_refs). Before installing, snapshot existing daemon state (rig down <rig> --snapshot) and confirm you can restore it — never run 0.7.5 against the pre-upgrade snapshot without a restore path. Rollback procedure:docs/sprints/CLI-0.7.5-BUMP.md§6 Rollback.
npm install -g @openrig/[email protected] @earendil-works/[email protected]
rig --version # Expect: 0.7.5 (b57c4da3)
pi --version # Expect: 1.4.0
Note
: Always invoke the OpenRig CLI using
rig(oropenrig-tuifor the standalone dashboard binary), neveropenrig.
Step 2: Install Pi Permission & AST/LSP Packages into $HERETEK_TOOLS
By default, scripts/render-seat.py looks for Pi extension packages and local npm MCP binaries under $HERETEK_TOOLS (which defaults to ~/.local/share/heretek-rigs/tools). Install the mandatory permission harness (@gotgenes/[email protected]) and optional builder AST/LSP extensions ([email protected], [email protected]):
export HERETEK_TOOLS="${HERETEK_TOOLS:-$HOME/.local/share/heretek-rigs/tools}"
mkdir -p "$HERETEK_TOOLS/pi-packages" "$HERETEK_TOOLS/mcp" "$HERETEK_TOOLS/bin" "$HERETEK_TOOLS/src"
# 1. Install Pi permission and AST/LSP packages
npm --prefix "$HERETEK_TOOLS/pi-packages" install \
@gotgenes/[email protected] \
[email protected] \
[email protected]
# 2. Install stdio npm MCP servers used by fleet seats
npm --prefix "$HERETEK_TOOLS/mcp" install \
[email protected] \
@upstash/[email protected] \
@modelcontextprotocol/[email protected] \
@playwright/[email protected] \
[email protected] \
@mobilenext/[email protected] \
[email protected] \
[email protected]
If you plan to run the binary/firmware reverse engineering seats (binary-reverse-eng, firmware-sec-analyst), build the pinned read-only [email protected] binary into $HERETEK_TOOLS/bin/r2mcp:
git clone --depth 1 --branch 1.9.0 https://github.com/radareorg/radare2-mcp "$HERETEK_TOOLS/src/radare2-mcp"
make -C "$HERETEK_TOOLS/src/radare2-mcp"
install -m 755 "$HERETEK_TOOLS/src/radare2-mcp/src/r2mcp" "$HERETEK_TOOLS/bin/r2mcp"
2. Environment Variables & Zero-Leak Secret Provisioning
Key Environment Variables
| Variable | Default Value | Description |
|---|---|---|
OPENRIG_HOME |
~/.openrig |
Root directory for OpenRig daemon state, SQLite database, and per-seat Pi directories ($OPENRIG_HOME/state/pi/<pod>-<member>@<rig>/agent/). |
HERETEK_TOOLS |
~/.local/share/heretek-rigs/tools |
Base directory containing pi-packages/node_modules, mcp/node_modules, and bin/r2mcp. |
HERETEK_SECRETS |
~/.config/heretek-rigs/secrets |
Mode 0700 directory holding mode 0600 secret files referenced via !cat in auth.json and mcp.json. |
HERETEK_WORKSPACE |
Current working directory (.) |
Target project repository path passed to rig up rig.yaml --cwd "$HERETEK_WORKSPACE". |
SIDECAR_PROFILES |
Empty ("") |
Space- or comma-separated list of Docker Compose profiles for make sidecars-up (e.g., "web-research", "qa-testing"). |
Provisioning $HERETEK_SECRETS (0700 Directory, 0600 Files)
OpenRig strips OPENCODE_API_KEY from runtime: pi child processes by design. Instead, heretek-rigs uses Pi's command-backed credential syntax ("!cat /abs/path/to/secret"), where Pi executes the command only when connecting to the inference endpoint or MCP server.
scripts/render-seat.py enforces strict security invariants on $HERETEK_SECRETS:
- Every secret file must be a regular file (symlinks are rejected before
stat()and viaO_NOFOLLOW). - Every secret file must be owned by your current effective UID (
st_uid == os.geteuid()). - Every secret file must have mode
0600(any group or world permission bit causesrender-seat.pyto abort with exit code2).
Create your secrets directory and provision your OpenCode Go API key (opencode-go.key):
export HERETEK_SECRETS="${HERETEK_SECRETS:-$HOME/.config/heretek-rigs/secrets}"
mkdir -p -m 700 "$HERETEK_SECRETS"
# Required for all 51 seats (OpenCode Go API key for Muse Spark 1.3 Contributor)
printf '%s' "your-opencode-go-api-key" > "$HERETEK_SECRETS/opencode-go.key"
chmod 600 "$HERETEK_SECRETS/opencode-go.key"
Optional Role-Specific MCP Secret Files
Depending on which rigs and MCP servers you use, create the corresponding 0600 files in $HERETEK_SECRETS:
Secret File ($HERETEK_SECRETS/<file>) |
Bound MCP Server | Roles Requiring This Secret | Format / Example Content |
|---|---|---|---|
opencode-go.key |
Primary LLM (auth.json) |
All 51 roles | Bare OpenCode Go API key string |
github.pat |
github |
exec-director, product-director, tpm-scrum-lead, ux-research-analyst, release-qa-officer, threat-modeler, compliance-auditor |
Bare GitHub Personal Access Token (expanded via !echo Bearer $(cat @SECRETS@/github.pat)) |
context7.key |
context7 (optional) |
system-architect, ts-node-fullstack, python-backend-spec, go-backend-eng, rust-systems-spec, ai-red-teamer |
Bare Context7 API key (if omitted, CONTEXT7_API_KEY env is cleanly stripped) |
aws.profile, aws.region, aws.config, aws.credentials |
aws |
cloud-platform-eng, cloud-sec-auditor |
AWS profile name, region (e.g., us-east-1), config file, and credentials file |
kubeconfig |
kubernetes |
k8s-orchestrator |
Standard Kubernetes client config file (read-only cluster access) |
prometheus.url |
prometheus |
sre-incident-eng, observability-eng |
Prometheus base URL (e.g., http://127.0.0.1:9090) |
postgres-readonly.uri |
postgres |
dba-specialist |
Read-only PostgreSQL URI (postgresql://ro_user:pass@host:5432/dbname) |
redis-readonly.url |
redis |
cache-streaming-eng |
Read-only Redis URI (redis://ro_user:pass@host:6379/0) |
clickhouse.host, clickhouse.user, clickhouse.password |
clickhouse |
analytics-metrics-eng |
ClickHouse hostname, read-only username, and password |
Tip — Degraded Seeding (
--allow-missing-secrets): If you only haveopencode-go.key(or want to test seat rendering before provisioning every cloud/database credential), pass--allow-missing-secretstoseed-rig.pyorbootstrap-pi-seats.sh. Any MCP server whose required secret file is missing will be written with"enabled": false, and a missingopencode-go.keyrendersauth.jsonwith no provider entry (pi 1.4.0 ignoresenabled); both are logged as warnings tostderrrather than aborting.
3. Quickstart: Verify, Seed, Validate, and Launch a Rig
Follow these five steps from the root of the heretek-rigs repository to verify your checkout, seed your seats, and launch a rig.
Step 1: Run the Self-Testing Verification Gate
Verify that all 51 AgentSpecs, 8 RigBundles, JSON schemas, cryptographic digests, and unit tests are intact:
make verify
You should see SUMMARY: 39 checks passed, 0 failed.
Step 2: Seed the Pi Seats for Your Target Rig
Crucial Rule: Always seed a rig's seats before running rig up, rig expand, or rig add. Seeding populates $OPENRIG_HOME/state/pi/<pod>-<member>@<rig>/agent/ with auth.json, models.json, settings.json, mcp.json, extensions/pi-permission-system/config.json, and AGENTS.md (all mode 0600).
To seed a single rig (for example, executive-and-architecture):
# Strict mode (requires opencode-go.key + github.pat in $HERETEK_SECRETS):
python3 ./scripts/seed-rig.py rigs/executive-and-architecture/rig.yaml
# Or degraded mode (disables MCP servers whose secret files are not yet provisioned):
make seed RIG=executive-and-architecture
Or provision all 54 default boot seats across all 8 rigs at once:
# Strict mode (all required secrets must exist):
make bootstrap-seats
# Degraded mode (missing MCP secrets render "enabled": false; a missing provider key renders an empty auth.json):
bash ./scripts/bootstrap-pi-seats.sh --all --allow-missing-secrets
Step 3: Validate the Bundle and Start the OpenRig Daemon
Run offline bundle and spec checks first, then start the OpenRig daemon and run preflight checks:
# 1. Offline bundle integrity check (returns [] when 0 findings exist)
rig bundle check rigs/executive-and-architecture --json
# 2. Offline RigSpec v0.2 structural validation
(cd rigs/executive-and-architecture && rig spec validate rig.yaml --json)
# 3. Start the local OpenRig daemon (if not already running)
rig daemon start --no-kernel
# 4. Run live daemon preflight and AgentSpec validation
(cd rigs/executive-and-architecture && rig spec preflight rig.yaml --json)
(cd rigs/executive-and-architecture && rig agent validate agents/exec-director --json)
Step 4: Launch the Rig Against Your Target Workspace
Set HERETEK_WORKSPACE to the git repository you want the rig to work on, and launch the rig from inside rigs/<rig-id>/ so local agents/<role> references resolve cleanly:
export HERETEK_WORKSPACE="/path/to/your/project-repo"
(cd rigs/executive-and-architecture && rig up rig.yaml --cwd "$HERETEK_WORKSPACE" --yes)
Step 5: Inspect Running Seats and Open the Dashboard
# Check seat status and readiness
rig ps --nodes --rig executive-and-architecture
# Open the OpenRig Terminal UI dashboard
rig tui
4. Day-to-Day Fleet Operations
Addressing Seats
Every running seat in OpenRig has a canonical address of the form:
<pod>-<member>@<rig>
For example:
exec-exec-director@executive-and-architecture(Director / CEO-Delegate in theexecpod)delivery-tpm-scrum-lead@executive-and-architecture(TPM / Scrum Lead in thedeliverypod)build-ts-node-fullstack@fullstack-and-web-studio(TypeScript / Node Fullstack Lead in thebuildpod)qa-release-qa-officer@qa-and-verification-gauntlet(Release QA Officer in theqapod)blue-threat-modeler@defensive-sec-and-red-team(Threat Modeler in thebluepod)
Assigning Missions & Managing Work Queues
In heretek-rigs, work moves in small, verifiable slices through OpenRig queues (mission-slice-sop and queue-handoff). Send your high-level objective to a pod lead or director seat, and track progress through rig queue:
# 1. Send a mission to the pod lead
rig send exec-exec-director@executive-and-architecture \
"Draft an ADR and sprint breakdown for migrating our auth service to passkeys. Coordinate with system-architect and tpm-scrum-lead."
# 2. Inspect the seat's queue items (always --json when an ID will be reused)
rig queue list --destination exec-exec-director@executive-and-architecture --limit 100 --json
# Copy qitem IDs verbatim from --json output -- never retype or reconstruct them.
# Bare queue output (no flags) mixes JSON with a human trailer and MUST NOT be parsed — always pass --json.
# 3. Capture recent terminal output or full conversation transcript from a seat
rig capture exec-exec-director@executive-and-architecture
rig transcript exec-exec-director@executive-and-architecture
Operator relays must be authenticated (issue #9).
rig sendissued from outside a managed seat arrives with no sender identity, so seats hold it as UNVERIFIED. Never relay a human decision with rawrig send— usescripts/send-authenticated.sh, which files the relay as a signed queue item (rig queue create --json --verify --destination <session> --body-file <file>) self-identified as operator-relayed with its human-ref grounding, UTC timestamp, and verbatim-relay statement. It never claims seat origin. Bare create output is a human advisory, not proof of persistence — the wrapper parses the JSON receipt fail-closed. See--helpfor the full contract.
How Seats Handle Permission Denials & Escalations
Every seat is governed by the Heretek Fleet Culture (CULTURE.md) and @gotgenes/[email protected]:
- Evidence Over Assertion: Every seat must include the exact verification command and its output before marking a queue slice complete.
- Permission Denials Are Hand-Offs: If a seat attempts to write outside its
path_writeglobs (for example,appsec-engineerattempting to editsrc/auth.tsdirectly when its writable path isdocs/security/advisories/*),@gotgenes/pi-permission-systemimmediately returns:[pi-permission-system] Denied by policy: 'path_write' for tool 'write' for path 'src/auth.ts' (rule '*') - Instead of working around the restriction, the seat writes its advisory to
docs/security/advisories/and escalates or hands off the code fix to its designated escalation target (rig send <reports_to> "<message>") as documented in its<agentDir>/AGENTS.md## Seatblock.
Where Mission Files Must Live
Seats can only write under their own path_write globs, relative to the
workspace they were launched in, and every seat denies paths outside that
workspace. Check SEAT-WRITE-SCOPES.md (generated from
fleet/fleet.yaml) before placing a mission, and put each slice under the
globs of the seat that owns it. A scratch directory or a new top-level folder
is writable by no seat (#78).
Refreshing or Re-homing One Seat
rig launch <rig> <node> does not relaunch a running node (#11). Use the
single-seat verbs instead; they touch only the named seat, and its queue rows,
address and identity are kept.
# Permission-only change: hot reload, no relaunch (#96)
python3 scripts/seed-rig.py rigs/<rig>/rig.yaml --refresh-policy-only
# Charter, model, MCP or skill change: re-seed, then relaunch only the
# affected seat. Check it is idle first (rig ps --nodes --json --rig <rig>); a fresh
# launch starts a blank conversation.
python3 scripts/seed-rig.py rigs/<rig>/rig.yaml # or members/<role>.yaml --rig <rig> --pod <pod>
rig seat launch <seat> --fresh --stop --reason "refresh: <change>"
# Give one seat a mission workspace (path_write globs then apply there)
rig seat set-cwd <seat> --cwd /abs/path/to/mission-workspace --reason "<mission>"
rig seat launch <seat> --fresh --stop --reason "<mission>: adopt workspace"
Preview any launch with --plan. After a whole-fleet restart, resumed seats
can fail their first model call (encrypted_content was not issued to this caller); the same rig seat launch <seat> --fresh --stop clears it.
Snapshotting, Restoring, and Stopping a Rig
# Stop a rig while capturing a full state snapshot for later resumption
rig down executive-and-architecture --snapshot
# Restore a snapshotted rig
rig up executive-and-architecture
# Stop and tear down a rig cleanly
rig down executive-and-architecture
5. Choosing the Right Rig for Your Mission
| Scenario / Engineering Goal | Recommended Rig | Lead Seat to Contact First | Key Writable Outputs |
|---|---|---|---|
| Product roadmap, OKRs, architecture decision records (MADRs), sprint planning, or repo documentation | executive-and-architecture (6 seats, all builtin:locked) |
exec-exec-director@executive-and-architecture or delivery-tpm-scrum-lead@executive-and-architecture |
docs/executive/*, docs/product/*, docs/adr/*, docs/architecture/*, docs/sprints/*, docs/ops/*, docs/* |
| Building web apps, REST/gRPC backends (TS/Node, Python, Go, Java/Kotlin), design systems, a11y, or UX research | fullstack-and-web-studio (11 seats) |
build-ts-node-fullstack@fullstack-and-web-studio or design-ui-ux-designer@fullstack-and-web-studio |
src/*, app/*, cmd/*, internal/*, pkg/*, packages/ui/*, tokens/*, tests/a11y/*, docs/research/* |
| Low-level Rust crates, C++20/23 libraries with ASan/UBSan/libFuzzer, or native Android/iOS mobile apps | systems-and-mobile-foundry (4 seats) |
systems-rust-systems-spec@systems-and-mobile-foundry or mobile-android-mobile-spec@systems-and-mobile-foundry |
crates/*, src/*, include/*, app/src/*, ios/*, Sources/*, Tests/* |
| ECS game engines, deterministic physics, HLSL/WGSL/GLSL shaders, gameplay AI, or glTF asset pipelines | game-dev-and-sim-rig (6 seats) |
engine-engine-systems-eng@game-dev-and-sim-rig or gameplay-game-systems-dev@game-dev-and-sim-rig |
src/engine/*, src/shaders/*, src/rendering/*, src/game/*, assets/*, tools/asset-pipeline/* |
| OpenTofu/Terraform IaC, Kubernetes/Helm, CVE patching, SRE postmortems, DB migrations, dbt/ClickHouse, or RAG | cloud-sre-and-data-platform (11 seats) |
platform-cloud-platform-eng@cloud-sre-and-data-platform or data-dba-specialist@cloud-sre-and-data-platform |
terraform/*, infra/*, deploy/*, k8s/*, migrations/*, dbt/*, pipelines/*, src/rag/* |
| Pre-release verification, Playwright E2E tests, OpenAPI contract checks, k6 load tests, mutation testing, or Semgrep | qa-and-verification-gauntlet (6 seats) |
qa-release-qa-officer@qa-and-verification-gauntlet |
docs/releases/*, tests/e2e/*, tests/api/*, tests/load/*, tests/chaos/*, rules/* |
| Zero-trust security audit: STRIDE threat modeling, OWASP triage, IAM audit, SBOMs, LLM red-teaming, or binary RE | defensive-sec-and-red-team (7 seats, all builtin:locked) |
blue-threat-modeler@defensive-sec-and-red-team or red-ai-red-teamer@defensive-sec-and-red-team |
docs/security/threat-models/*, docs/security/advisories/*, docs/security/cloud/*, sbom/*, docs/security/ai-redteam/*, docs/protocols/*, docs/forensics/*, docs/security/firmware/* |
| Cross-domain mission starting small (3 seats) and scaling pods/specialists on demand | heretek-omni-fleet (3 default seats, scales to 51) |
command-exec-director@heretek-omni-fleet |
Starts with docs/executive/*, docs/sprints/*, docs/adr/*; scales dynamically as pods/members are attached |
6. Dynamic Scaling with heretek-omni-fleet
Instead of booting all 51 agents at once, rigs/heretek-omni-fleet/ provides a Hybrid Omni-Fleet workflow:
Mode A: Boot the 3-Seat Command Pod and Scale on Demand (Recommended)
- Seed and launch the 3-seat command center (
exec-director,tpm-scrum-lead,system-architect):python3 ./scripts/seed-rig.py rigs/heretek-omni-fleet/rig.yaml --allow-missing-secrets (cd rigs/heretek-omni-fleet && rig up rig.yaml --cwd "$HERETEK_WORKSPACE" --yes) - Dynamically attach any of the 15 domain pods (
rig expand): Available pod fragments inrigs/heretek-omni-fleet/pods/are:exec,delivery,build,design,systems,mobile,engine,gameplay,platform,sre,data,ml,qa,blue, andred. Always seed the pod fragment first, then runrig expand:# Example: Attach the 'blue' security pod to the running heretek-omni-fleet rig python3 ./scripts/seed-rig.py rigs/heretek-omni-fleet/pods/blue.yaml \ --rig heretek-omni-fleet --allow-missing-secrets RIG_ID=$(rig ps --json | jq -r '.[] | select(.name=="heretek-omni-fleet") | .rigId') (cd rigs/heretek-omni-fleet && rig expand "$RIG_ID" pods/blue.yaml --rig-root "$PWD" --json) - Dynamically attach a single specialist seat to an existing pod (
rig add): All 51 specialist roles have member fragments inrigs/heretek-omni-fleet/members/<role>.yaml. Always seed the member fragment for the target rig and pod first, then runrig add:# Example: Add 'rust-systems-spec' into the 'command' pod (or 'systems' pod) python3 ./scripts/seed-rig.py rigs/heretek-omni-fleet/members/rust-systems-spec.yaml \ --rig heretek-omni-fleet --pod command --allow-missing-secrets (cd rigs/heretek-omni-fleet && rig add heretek-omni-fleet command members/rust-systems-spec.yaml --rig-root "$PWD" --json)
Mode B: Boot the Full 51-Seat Static Omni Profile (rig.all-51.yaml)
If you have sufficient host memory and want all 15 pods and 51 seats running inside heretek-omni-fleet simultaneously:
# 1. Seed all 51 seats under @heretek-omni-fleet
bash ./scripts/bootstrap-pi-seats.sh --profile all-51 --allow-missing-secrets
# 2. Launch rig.all-51.yaml
(cd rigs/heretek-omni-fleet && rig up rig.all-51.yaml --cwd "$HERETEK_WORKSPACE" --yes)
Consulting the Fleet Roster (rosters/heretek-omni-fleet.json)
Agents and operators can query rosters/heretek-omni-fleet.json to find which specialist seat owns a capability:
jq '.members[] | select(.capabilities[] | contains("semgrep"))' rosters/heretek-omni-fleet.json
7. Managing Docker Sidecar Services
Supporting services (docker-compose.sidecars.yml) are opt-in by profile and bind exclusively to 127.0.0.1.
Sidecar Environment Variables (.env)
Before starting web-research or ai-gateway sidecars, set the required secret variables in your shell or .env file (the Compose specification uses ${VAR:?...} fail-closed guards):
| Variable | Required By Profile / Service | Purpose |
|---|---|---|
SEARXNG_SECRET |
web-research (searxng) |
Secret key for the local SearXNG metasearch instance (127.0.0.1:8888). |
BROWSERLESS_TOKEN |
web-research (browserless) |
Authentication token for headless Chrome on 127.0.0.1:3000. |
QDRANT_API_KEY |
ai-gateway (qdrant) |
API key for the Qdrant vector database container on 127.0.0.1:6333. |
Starting and Stopping Sidecars Safely
Never invoke docker compose -f docker-compose.sidecars.yml directly, as raw Compose bypasses the mobile/devsec isolation guard. Always use make sidecars-up or ./scripts/compose-sidecars.sh:
# Start web-research sidecars (searxng, browserless, firecrawl, firecrawl-redis)
make sidecars-up SIDECAR_PROFILES="web-research"
# Start devsec sidecars (ghidra on :1337, radare2 on :9090, sonarqube on :9000)
# Note: Place binaries to analyze in ./workspaces/binaries (mounted :ro at /samples)
mkdir -p ./workspaces/binaries
make sidecars-up SIDECAR_PROFILES="devsec"
# Start qa-testing sidecar (GET-only docker-socket-proxy) and ai-gateway (qdrant)
make sidecars-up SIDECAR_PROFILES="qa-testing ai-gateway"
# Start isolated Android emulator sidecar (6080) ALONE
make sidecars-up SIDECAR_PROFILES="mobile"
# Stop all running sidecar containers while preserving named volumes
make sidecars-down
Isolation Rule:
make guard-profilesand./scripts/compose-sidecars.shwill refuse to start--profile mobilealongsidedevsecorweb-research(exit 1) so the Android emulator remains strictly isolated on the internalheretek-mobilebridge network.
8. Customizing the Fleet, Regenerating Artifacts & Running Security Gates
Editing fleet/fleet.yaml or fleet/mcp-servers.yaml
Never hand-edit files under specs/, rigs/, rosters/, or registry/. Because rigs/*/bundle.yaml and registry/status.json embed SHA-256 digests over every generated file, any manual edit to a generated file will immediately break make verify (Stage V3/V5).
To modify a role's permissions, skills, thinking level, or MCP bindings:
- Edit
fleet/fleet.yamlorfleet/mcp-servers.yaml. - Ensure your git working tree is clean (or set
HERETEK_RIGS_ALLOW_DIRTY=1during local development soresolve_heretek_commit()allows provenance baking on a dirty worktree). - Ensure the pinned upstream checkouts exist in
.scratch/vendor/(obra_superpowers@bb92a77,trailofbits_skills@5c99c03,getsentry_skills@f57ada2,anthropics_skills@dbd4588,vercel-labs_agent-skills@063bee9, plusHeretek-Crew@5ffb1fcand@openrig/[email protected]). - Run the deterministic generator and idempotency gate:
HERETEK_RIGS_ALLOW_DIRTY=1 python3 ./scripts/generate-rigs.py HERETEK_RIGS_ALLOW_DIRTY=1 python3 ./scripts/generate-rigs.py --check-idempotent make verify
Live Role Permission Gate Testing (make gate)
To test a role's rendered @gotgenes/[email protected] configuration against a local mock OpenAI server (scripts/mock-openai.mjs) and real pi --no-approve --mode json execution across 40+ hostile probes (unauthorized writes, AGENTS.md overwrites, .. traversal, curl, ; / | / & / $() / backtick / newline command chaining, --output write escapes (=, space, and tab forms), --output-junit/--output-log file-writer flags, git log -p / --patch / --full-diff / --textconv read-deny bypasses, .env / *.pem / *.url / *.user / .pi/ / .agents/ / fleet/* / scripts/* reads, and code_rewrite / lsp_rename / lsp_code_actions mutations) plus a ctest --output-on-failure allow probe on ctest-holding roles:
make gate ROLE=appsec-engineer
make gate ROLE=exec-director
make gate ROLE=go-backend-eng
Fleet Wiring & Topography (make topology)
To verify every cross-reference in the catalog and render the whole hierarchy:
make topology OUT=/tmp/heretek-topology
scripts/topology.py fail-closed checks that every reports_to.address resolves to
a real seat, every collaborators[] / skill / MCP / package reference exists on
disk and in the lockfiles, every rig.yaml member matches fleet.yaml (and vice
versa), all 51 member fragments are present, and every pod edge endpoint exists with no
self-edges. It then renders graph.json, an org-chart SVG
(15 pods + command), per-rig agent SVGs, per-rig seat×resource bipartite SVGs, and a
51-row matrix.md. Orphan skills/servers and omni-divergent reports_to addresses
are reported as advisory warnings only. The .github/workflows/topology.yml CI job
runs this on push to main limited to the listed paths, on pull requests limited
to the listed paths, and on manual workflow_dispatch, and uploads the SVGs +
graph.json + matrix.md as artifacts (30-day retention).
Live Seat Audit (make audit-sessions)
To scan running seats for misattributed permission denials (assistant claims a
tool-wide ban while the review log shows a unit-scoped deny and the config allows
the capability) and false delivery claims (DISPATCHED with no qitem- id):
make audit-sessions WORKSPACE=/path/to/seat-workspace
Findings are leads for operator review (exit 1 when any exist), not verdicts:
assistant-text matching is heuristic, and delivery flags do not cross-check live
queue state. Scans every seat under OPENRIG_HOME/state/pi, including archived rigs.
9. Complete Command Reference (Makefile & Scripts)
Makefile Targets
| Command | Description |
|---|---|
make help |
List all documented Makefile targets and descriptions. |
make generate |
Run python3 ./scripts/generate-rigs.py to regenerate all 51 AgentSpecs, 8 RigBundles, Roster, and Registry views. |
make idempotent |
Run python3 ./scripts/generate-rigs.py --check-idempotent (regenerates twice and fails if any byte differs). |
make verify |
Run bash ./scripts/verify-rigs.sh (all 6 verification stages V1–V6 + unit tests). |
make test |
Run python3 -m unittest tests/test_render_seat.py -v (7 offline unit tests for seat rendering and permissions). |
make bootstrap-seats |
Run bash ./scripts/bootstrap-pi-seats.sh --all (strict secret checking; provisions all 54 default boot seats). |
make seed RIG=<rig-id> |
Seed one rig in degraded-allowed mode: python3 ./scripts/seed-rig.py rigs/$(RIG)/rig.yaml --allow-missing-secrets. |
make gate ROLE=<role-id> |
Live-test one role's permission config against mock-openai.mjs and pi: bash ./scripts/gate-role.sh $(ROLE). |
make topology OUT=<dir> |
Referential wiring gates + rendered topography (graph.json, org/rig/bipartite SVGs, 51-row matrix). |
make audit-sessions |
Detect misattributed denials + false delivery claims in live seats (OPENRIG_HOME/state/pi + workspace docs). |
make guard-profiles |
Fail-closed check refusing SIDECAR_PROFILES that combine mobile with devsec or web-research. |
make sidecars-up SIDECAR_PROFILES="..." |
Run guard-profiles then start the specified profiles in docker-compose.sidecars.yml (up -d). |
make sidecars-down |
Stop sidecar containers while preserving named volumes (docker compose -f docker-compose.sidecars.yml down). |
make bundle-check |
Run verify and then invoke rig bundle check <rig> --json across all 8 rigs if rig is on PATH. |
make audit-loop |
Run python3 ./scripts/audit_loop.py (automated OpenCode triad adversarial audit & remediation loop). |
Direct Script CLI Reference
| Script | CLI Syntax & Options | Purpose |
|---|---|---|
scripts/render-seat.py |
python3 ./scripts/render-seat.py --role <role-id> --rig <rig-id> --pod <pod-id> [--member <id>] [--fleet fleet/fleet.yaml] [--mcp fleet/mcp-servers.yaml] [--charter <file>] [--out <dir>] [--model-provider opencode-go] [--model-id muse-spark-1.3-contributor] [--allow-missing-secrets] [--dry-run] |
Renders a single seat's 6 runtime files (auth.json, models.json, mcp.json, settings.json, extensions/pi-permission-system/config.json, AGENTS.md) with mode 0600. |
scripts/seed-rig.py |
python3 ./scripts/seed-rig.py <rig.yaml | pod-fragment.yaml | member-fragment.yaml> [--rig <rig-id>] [--pod <pod-id>] [--dry-run] [--allow-missing-secrets] |
Invokes render-seat.py for every seat in a rig.yaml, pod fragment (--rig required), or member fragment (--rig and --pod required). |
scripts/bootstrap-pi-seats.sh |
bash ./scripts/bootstrap-pi-seats.sh [--rig <rig-slug> | --all] [--profile all-51] [--dry-run] [--strict-secrets | --allow-missing-secrets] |
Batch wrapper around seed-rig.py to provision one rig, all 8 default rigs (54 seats), or the 51-seat omni static profile (--profile all-51). |
scripts/verify-rigs.sh |
bash ./scripts/verify-rigs.sh [--check-only | --dry-run | --help] |
Runs the 22-check offline verification suite (V1–V6) and unit tests. |
scripts/compose-sidecars.sh |
SIDECAR_PROFILES="..." ./scripts/compose-sidecars.sh up -d or ./scripts/compose-sidecars.sh --profile <p> up -d |
Fail-closed wrapper around docker compose -f docker-compose.sidecars.yml enforcing the mobile isolation guard. |
scripts/audit_loop.py |
python3 ./scripts/audit_loop.py [--repo-root .] [--required-passes 3] [--max-iterations 15] [--model opencode-go/muse-spark-1.3-contributor] [--run-implementation-first] [--self-test | --dry-run] |
Runs the automated adversarial triad audit (Alpha/Beta/Gamma) and remediation loop until 3 consecutive STATUS: NO_FINDINGS passes. |
10. Troubleshooting Guide
| Symptom / Error Message | Root Cause | Resolution |
|---|---|---|
error: missing /.../.config/heretek-rigs/secrets/opencode-go.key (chmod 600) |
You ran render-seat.py, seed-rig.py, or bootstrap-pi-seats.sh in default strict mode without provisioning opencode-go.key (or a role's required MCP secret). |
Provision the secret file in $HERETEK_SECRETS with chmod 600, or pass --allow-missing-secrets to render the missing MCP server with "enabled": false (a missing provider key leaves auth.json empty). |
error: /.../secrets/opencode-go.key is mode 644; run: chmod 600 ... |
The secret file has group or world permission bits (mode & 0o077 != 0). |
Run chmod 600 "$HERETEK_SECRETS"/* and chmod 700 "$HERETEK_SECRETS". |
error: /.../secrets/<file> must not be a symlink or must be owned by uid <uid> |
A file in $HERETEK_SECRETS is a symbolic link or owned by a different user account. |
Replace the symlink with a regular file owned by your current user (chown $(id -u):$(id -g)) and set chmod 600. |
error: unknown pod '<pod>' for rig <rig> (valid pods: [...]) |
render-seat.py or seed-rig.py was passed a --pod ID that does not belong to --rig in fleet/fleet.yaml. |
Check the valid pod IDs for the target rig (or use heretek-omni-fleet when seeding pod/member fragments across all 15 pods). |
error: refusing to co-schedule --profile mobile with devsec/web-research |
SIDECAR_PROFILES or --profile flags included both mobile and devsec or web-research. |
Run mobile in its own isolated sidecar session; stop devsec/web-research with make sidecars-down before starting mobile. |
error: refusing to bake provenance on a dirty checkout |
scripts/generate-rigs.py detected uncommitted changes via git status --porcelain. |
Commit or stash your changes before running make generate, or set HERETEK_RIGS_ALLOW_DIRTY=1 during local development iterations. |
Declared file is missing, unreadable or outside the bundle folder during rig up or rig bundle check |
rig up was run from outside the rigs/<rig>/ directory without --rig-root, or a symlink was introduced into rigs/<rig>/. |
Always run (cd rigs/<rig> && rig up rig.yaml --cwd "$HERETEK_WORKSPACE" --yes) and ensure zero symlinks exist (make verify checks this in V3). |
rig spec preflight fails with daemon connection error |
The local OpenRig daemon is not running (rig spec validate and rig bundle check run offline, but preflight and agent validate require the daemon). |
Start the daemon first with rig daemon start --no-kernel (or rig daemon start). |
11. Run in Docker (GHCR Fleet Image)
Public multi-arch images (linux/amd64, linux/arm64) are published by
.github/workflows/docker-release.yml to ghcr.io/heretek-ai/heretek-rigs:
| Tag | Contents | Approx. size |
|---|---|---|
:latest (slim) |
rig 0.7.5, pi 1.4.0, permission system + AST/LSP packages, 8 npm MCP servers, uvx PyPI MCP servers |
~3.5 GB (dominated by the upstream codebase-memory-mcp 330 MB Go binary, tree-sitter WASM grammars, and the Node 22 toolchain) |
:full |
slim + Playwright Chromium (+CHROME_PATH for chrome-devtools-mcp), source-built radare2 6.2.4, compiled r2mcp -R |
~4.7 GB |
:sha-<commit> / :sha-<commit>-full |
Pinned releases (provenance + SBOM attestations) | — |
Run contract (all required)
- UID: the image runs as
heretek(uid/gid 1000). Always pass--user 1000:1000so$HOME=/home/heretekstays writable; any other UID fails loudly at entrypoint with a clear message. - Secrets: mount your host secrets dir read-only at
/run/heretek-secrets. The entrypoint dereferences every file into$HERETEK_SECRETSas a fresh0600regular file owned by uid 1000 (satisfyingrender-seat.py's symlink/uid/mode triple check), covering hostile cases:0644files, symlinks, and foreign-uid files are all normalized. On SELinux hosts (Fedora/RHEL) append:zso the mount is relabeled and visible in-container:-v "$HOME/.config/heretek-rigs/secrets:/run/heretek-secrets:ro,z. - Terminal: pass
-e TERM=xterm-256colorforrig tuirendering. - No
rig ui openin-container (no browser). Userig tui,rig terminal open <rig> --window, or plaintmux attach. - Sidecars stay siblings: join the deterministic
hereteknetwork (--network heretek) to reach sidecars by service name and container port. Host clients use127.0.0.1and the published host port.
# Interactive shell, auto-seed + auto-launch executive rig against ./my-project
docker run --rm -it --user 1000:1000 \
-v "$PWD/my-project:/workspace" \
-v "$HOME/.config/heretek-rigs/secrets:/run/heretek-secrets:ro" \
-e TERM=xterm-256color \
-e HERETEK_RIG="executive-and-architecture" \
-e HERETEK_AUTO_UP="1" \
ghcr.io/heretek-ai/heretek-rigs:latest \
rig tui
Pairing with sidecars (docker-compose.yml)
HERETEK_IMAGE=ghcr.io/heretek-ai/heretek-rigs:latest \
HERETEK_RIG=executive-and-architecture \
HERETEK_WORKSPACE=/path/to/project \
docker compose up -d fleet
docker compose exec fleet rig tui
The fleet service joins the external heretek network (named deterministically via
name: heretek in docker-compose.sidecars.yml). Host clients use
127.0.0.1:<published-port>; clients inside fleet use
<service-name>:<container-port> for sidecars on the shared network. Configure
each client's endpoint accordingly; joining the network does not rewrite MCP
bindings. The current catalog has no SearXNG MCP binding, and its Qdrant MCP uses
QDRANT_LOCAL_PATH for local storage. Start sidecars first with
make sidecars-up SIDECAR_PROFILES="..." on the host (or a second compose file).
Which MCP servers work in-container
:latest: all exceptplaywright,chrome-devtools(no browser) andradare2(no binary). Seats binding them render degraded ("enabled": false) unless the tools exist — validated fail-closed by the in-container smoke gates.:full: adds Chromium (CHROME_PATHpre-set for chrome-devtools-mcp),radare2+r2mcp -R. TheterraformMCP still shells to a hostdockerbinary — mount/var/run/docker.sockexplicitly if you need it (understand the privilege implications first).