
Bstack
- 37 installs
- 1 repo stars
- Updated July 30, 2026
- broomva/bstack
bstack is a Claude skill and portable agent harness that composes 20 governance primitives and 30 curated skills into a self-operating workspace with bootstrap, doctor, repair, and validate commands.
About
bstack, the Broomva Stack, is a portable harness that composes 20 governance primitives and 30 curated skills into a self-operating agent workspace. Developers install it to bootstrap a new agent-driven project, verify primitive compliance, repair missing hooks or policy, and manage installed skills. Each primitive closes a specific failure mode such as session amnesia, destructive operations, or context rot. It installs via npx skills add and drives a canonical autonomous operating mode on top of the substrate.
- Bootstraps an agent workspace with 20 primitives plus 30 curated skills
- Enforces a primitive contract via bstack doctor, repair, status, and validate commands
- Ships a canonical autonomous operating mode plus governance, hooks, and a policy file
Bstack by the numbers
- 37 all-time installs (skills.sh)
- Ranked #8,545 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 31, 2026 (Skillselion catalog sync)
bstack capabilities & compatibility
- Capabilities
- workspace bootstrap · primitive compliance check · governance repair · skill status · frontmatter validation
- Works with
- github
- Use cases
- orchestration · project management
- Pricing
- Free
What bstack says it does
Twenty irreducible primitives (P1-P20) plus 30 curated skills that turn an agent-driven workspace into a self-operating system.
bstack is a *portable harness metalayer* — it composes existing skills into a binding primitive contract that the agent enforces by reasoning
/bstack bootstrap → install 30 skills + scaffold governance + wire hooks + run doctor
npx skills add https://github.com/broomva/bstack --skill bstackAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 37 |
|---|---|
| repo stars | ★ 1 |
| Last updated | July 30, 2026 |
| Repository | broomva/bstack ↗ |
What it does
Bootstrap and govern an agent-driven workspace with a fixed set of primitives, skills, hooks, and a policy contract.
Who is it for?
Developers standing up a governed, autonomous agent-driven workspace and enforcing primitive compliance.
Skip if: Simple one-off tasks that do not need a governed multi-skill agent harness.
When should I use this skill?
Bootstrapping a new agent workspace, running bstack doctor for compliance, or repairing missing governance, hooks, or policy.
What you get
A bootstrapped, self-operating workspace with primitives, skills, governance, hooks, and a policy contract in place.
- 30 installed skills
- scaffolded governance and hooks
- .control/policy.yaml
By the numbers
- 20 irreducible primitives (P1-P20)
- 30 curated skills
- 6 core commands (bootstrap, doctor, repair, status, validate, revamp)
Files
/bstack-upgrade
Upgrade bstack to the latest version and show what's new.
Inline upgrade flow
This section is referenced by the bstack SKILL.md preamble when it detects UPGRADE_AVAILABLE.
Step 1: Ask the user (or auto-upgrade)
First, check if auto-upgrade is enabled:
_BSTACK_ROOT="${BSTACK_DIR:-$HOME/.claude/skills/bstack}"
[ ! -x "$_BSTACK_ROOT/bin/bstack-config" ] && _BSTACK_ROOT="$HOME/.agents/skills/bstack"
_AUTO=""
[ "${BSTACK_AUTO_UPGRADE:-}" = "1" ] && _AUTO="true"
[ -z "$_AUTO" ] && _AUTO=$("$_BSTACK_ROOT/bin/bstack-config" get auto_upgrade 2>/dev/null || true)
echo "AUTO_UPGRADE=$_AUTO"If `AUTO_UPGRADE=true` or `AUTO_UPGRADE=1`: Skip AskUserQuestion. Log "Auto-upgrading bstack v{old} → v{new}..." and proceed directly to Step 2.
Otherwise, use AskUserQuestion:
- Question: "bstack v{new} is available (you're on v{old}). Upgrade now?"
- Options: ["Yes, upgrade now", "Always keep me up to date", "Not now", "Never ask again"]
If "Yes, upgrade now": Proceed to Step 2.
If "Always keep me up to date":
"$_BSTACK_ROOT/bin/bstack-config" set auto_upgrade trueTell user: "Auto-upgrade enabled. Future updates will install automatically." Then proceed to Step 2.
If "Not now": Write snooze state with escalating backoff (first snooze = 24h, second = 48h, third+ = 1 week), then continue with the current skill.
_SNOOZE_FILE=~/.bstack/update-snoozed
_REMOTE_VER="{new}"
_CUR_LEVEL=0
if [ -f "$_SNOOZE_FILE" ]; then
_SNOOZED_VER=$(awk '{print $1}' "$_SNOOZE_FILE")
if [ "$_SNOOZED_VER" = "$_REMOTE_VER" ]; then
_CUR_LEVEL=$(awk '{print $2}' "$_SNOOZE_FILE")
case "$_CUR_LEVEL" in *[!0-9]*) _CUR_LEVEL=0 ;; esac
fi
fi
_NEW_LEVEL=$((_CUR_LEVEL + 1))
[ "$_NEW_LEVEL" -gt 3 ] && _NEW_LEVEL=3
echo "$_REMOTE_VER $_NEW_LEVEL $(date +%s)" > "$_SNOOZE_FILE"Note: {new} is the remote version from the UPGRADE_AVAILABLE output — substitute it from the update check result.
Tell user the snooze duration: "Next reminder in 24h" (or 48h or 1 week, depending on level).
If "Never ask again":
"$_BSTACK_ROOT/bin/bstack-config" set update_check falseTell user: "Update checks disabled. Run bstack-config set update_check true to re-enable." Continue with the current skill.
Step 2: Detect install type
_BSTACK_ROOT=""
if [ -d "$HOME/.claude/skills/bstack/.git" ]; then
INSTALL_TYPE="global-git"
_BSTACK_ROOT="$HOME/.claude/skills/bstack"
elif [ -d "$HOME/.agents/skills/bstack/.git" ]; then
INSTALL_TYPE="agents-git"
_BSTACK_ROOT="$HOME/.agents/skills/bstack"
elif [ -d ".claude/skills/bstack/.git" ]; then
INSTALL_TYPE="local-git"
_BSTACK_ROOT=".claude/skills/bstack"
elif [ -d "$HOME/.claude/skills/bstack" ]; then
INSTALL_TYPE="vendored-global"
_BSTACK_ROOT="$HOME/.claude/skills/bstack"
elif [ -d "$HOME/.agents/skills/bstack" ]; then
INSTALL_TYPE="vendored-agents"
_BSTACK_ROOT="$HOME/.agents/skills/bstack"
else
echo "ERROR: bstack not found"
exit 1
fi
echo "Install type: $INSTALL_TYPE at $_BSTACK_ROOT"Step 3: Save old version
OLD_VERSION=$(cat "$_BSTACK_ROOT/VERSION" 2>/dev/null || echo "unknown")Step 4: Upgrade
For git installs (global-git, agents-git, local-git):
cd "$_BSTACK_ROOT"
STASH_OUTPUT=$(git stash 2>&1)
git fetch origin
git reset --hard origin/main
chmod +x bin/* scripts/* 2>/dev/null || trueIf $STASH_OUTPUT contains "Saved working directory", warn the user.
For vendored installs:
PARENT=$(dirname "$_BSTACK_ROOT")
TMP_DIR=$(mktemp -d)
git clone --depth 1 https://github.com/broomva/bstack.git "$TMP_DIR/bstack"
mv "$_BSTACK_ROOT" "$_BSTACK_ROOT.bak"
mv "$TMP_DIR/bstack" "$_BSTACK_ROOT"
chmod +x "$_BSTACK_ROOT/bin/"* "$_BSTACK_ROOT/scripts/"* 2>/dev/null || true
rm -rf "$_BSTACK_ROOT.bak" "$TMP_DIR"Step 5: Write marker + clear cache
mkdir -p ~/.bstack
echo "$OLD_VERSION" > ~/.bstack/just-upgraded-from
rm -f ~/.bstack/last-update-check
rm -f ~/.bstack/update-snoozedStep 6: Show What's New
Read $_BSTACK_ROOT/CHANGELOG.md if it exists. Otherwise check git log --oneline $OLD_VERSION..HEAD for changes. Summarize as 3-5 bullets. Format:
bstack v{new} — upgraded from v{old}!
What's new:
- [bullet 1]
- [bullet 2]
- ...Step 7: Continue
After showing What's New, continue with whatever skill the user originally invoked.
---
Standalone usage
When invoked directly as /bstack-upgrade (not from a preamble):
1. Force a fresh update check:
~/.claude/skills/bstack/bin/bstack-update-check --force 2>/dev/null || ~/.agents/skills/bstack/bin/bstack-update-check --force 2>/dev/null || true2. If UPGRADE_AVAILABLE <old> <new>: follow Steps 2-6 above. 3. If no output: tell the user "You're already on the latest version."
name: CI
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
lint:
name: Lint shell + JSON templates
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: ShellCheck (scripts + bin)
run: |
# Only lint files that have a shebang we recognize.
set -euo pipefail
mapfile -t targets < <(
find scripts bin -type f \( -name "*.sh" -o ! -name "*.*" \) 2>/dev/null \
| xargs -I {} sh -c 'head -n1 "{}" | grep -q "^#!.*sh" && echo "{}"' \
| sort -u
)
if [ "${#targets[@]}" -eq 0 ]; then
echo "No shell scripts found to lint."
exit 0
fi
printf ' • %s\n' "${targets[@]}"
# Excluded checks (bstack's defensive shell style accepts these):
# SC1091 — don't follow sourced files.
# SC2155 — declare-and-assign masks return code (intentional).
# SC2034 — unused variable. Several scripts intentionally name
# variables that are only used in conditional branches
# shellcheck can't see. Suppressed at the lint gate;
# per-file SC2034 audit is a follow-up.
shellcheck --severity=warning \
--exclude=SC1091,SC2155,SC2034 \
"${targets[@]}"
- name: Validate JSON templates
run: |
set -euo pipefail
shopt -s nullglob
fail=0
for f in assets/templates/*.snippet; do
if ! jq -e . "$f" >/dev/null 2>&1; then
echo "::error file=$f::invalid JSON shape"
fail=1
else
echo " • $f — valid JSON"
fi
done
exit "$fail"
doctor:
name: bstack doctor (primitive-contract lint)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run doctor against templates
run: |
set -euo pipefail
mkdir -p .control
cp assets/templates/CLAUDE.md.template ./CLAUDE.md 2>/dev/null || true
cp assets/templates/AGENTS.md.template ./AGENTS.md 2>/dev/null || true
cp assets/templates/policy.yaml.template .control/policy.yaml 2>/dev/null || true
bash scripts/doctor.sh --quiet
tests:
name: tests/*.test.sh
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install python deps for tests
# PyYAML is the primary parser path for validate-skill-frontmatter.py
# (the dependency-free hand-parser is a best-effort fallback). The
# frontmatter test exercises both paths via SKILL_FM_NO_YAML.
run: python3 -m pip install --quiet PyYAML
- name: Run all tests/*.test.sh
# As of v0.8.0 (Phase 5 of substrate completion) the pre-existing
# tests/template_lockstep.test.sh and tests/onboard.test.sh are
# fixed (case-insensitive lockstep assertion + BSTACK_SKIP_SKILLS=1
# env override for the bootstrap skill-install loop). The full
# `tests/*.test.sh` suite now runs on every PR — no more vetted
# allowlist.
run: |
set -euo pipefail
shopt -s nullglob
fail=0
for t in tests/*.test.sh; do
echo ""
echo "=== $t ==="
if ! bash "$t"; then
echo "::error file=$t::test failed"
fail=1
fi
done
exit "$fail"
canary:
name: bstack canary suite (substrate invariants)
runs-on: ubuntu-latest
needs: [lint, doctor]
steps:
- uses: actions/checkout@v4
- name: Install jq + python deps for canary
run: |
set -euo pipefail
sudo apt-get update -qq && sudo apt-get install -y jq
python3 -m pip install --quiet jsonschema PyYAML
- name: Run canary suite (substrate invariants on fresh install)
# The canary suite verifies that the substrate's load-bearing
# contracts hold on a fresh install (no companion skills, no
# workspace state). Each canary covers one phase's deliverables:
# 01 — fresh bootstrap (Plant Contract)
# 02 — metrics pipeline (Phase 1 v0.4.0)
# 03 — status surface (Phase 2 v0.5.0)
# 04 — schemas validate (Phase 3 v0.6.0)
# 05 — crystallize detector (Phase 7 v0.9.5)
run: |
set -euo pipefail
shopt -s nullglob
fail=0
for t in tests/canary/*.test.sh; do
echo ""
echo "=== $t ==="
if ! bash "$t"; then
echo "::error file=$t::canary failed"
fail=1
fi
done
exit "$fail"
name: Release on merge
# Auto-tag + auto-publish GitHub Release whenever VERSION changes on main.
# Composes with validate-release.yml (PR gate) so this workflow trusts that
# the merged VERSION is semver, monotonic, and matched by a CHANGELOG section.
#
# Idempotent: if `vX.Y.Z` already exists (e.g. tagged manually before this
# workflow shipped) the run skips silently — no overwrite, no duplicate.
on:
push:
branches: [main]
paths:
- VERSION
permissions:
contents: write # tag push + gh release create
concurrency:
group: release-on-merge
cancel-in-progress: false
jobs:
release:
name: Tag + GitHub Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history so we can check existing tags
- name: Read VERSION
id: version
run: |
set -euo pipefail
v="$(tr -d '[:space:]' < VERSION)"
if ! printf '%s' "$v" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error file=VERSION::not semver X.Y.Z: '$v'"
exit 1
fi
echo " version=$v"
echo "version=$v" >> "$GITHUB_OUTPUT"
echo "tag=v$v" >> "$GITHUB_OUTPUT"
- name: Check existing tag
id: tag_check
run: |
set -euo pipefail
tag="${{ steps.version.outputs.tag }}"
if git rev-parse "$tag" >/dev/null 2>&1; then
echo " $tag already exists — skipping release."
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo " $tag is new — will create."
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
- name: Extract release notes from CHANGELOG
if: steps.tag_check.outputs.exists == 'false'
id: notes
run: |
set -euo pipefail
v="${{ steps.version.outputs.version }}"
awk -v ver="$v" '
$0 ~ "^## " ver "( |$)" { flag=1; next }
flag && /^## / { exit }
flag { print }
' CHANGELOG.md > /tmp/release-notes.md
if [ ! -s /tmp/release-notes.md ]; then
echo "::error file=CHANGELOG.md::no '## $v' section found"
exit 1
fi
# Title = first `### ` heading inside the section, else fall back to vX.Y.Z.
title=$(awk '/^### / { sub(/^### /, ""); print; exit }' /tmp/release-notes.md)
[ -z "$title" ] && title="${{ steps.version.outputs.tag }}"
echo " title=$title"
# Multi-line outputs need the heredoc form.
{
echo "title<<EOT"
echo "$title"
echo "EOT"
} >> "$GITHUB_OUTPUT"
- name: Tag + create GitHub Release
if: steps.tag_check.outputs.exists == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
tag="${{ steps.version.outputs.tag }}"
title="${{ steps.notes.outputs.title }}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag -a "$tag" -m "$tag — $title"
git push origin "$tag"
gh release create "$tag" \
--title "$tag — $title" \
--notes-file /tmp/release-notes.md
echo " ✓ released $tag"
# Package the skill directory as a tarball and publish it as a release
# asset, so vendored installs (no `.git`) can self-upgrade via
# `bstack upgrade --self` (≥ 0.9.0). The tarball excludes ephemeral
# state — only the in-repo skill source ships.
- name: Package + publish vendored upgrade tarball
if: steps.tag_check.outputs.exists == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
tag="${{ steps.version.outputs.tag }}"
tarball="bstack-${tag}.tar.gz"
# Build a clean staging tree — the extracted root must contain
# VERSION + bin/ + scripts/ + assets/ + references/ + schemas/ +
# SKILL.md + CHANGELOG.md, mirroring a fresh `npx skills add` layout.
staging="$(mktemp -d)"
dest="$staging/bstack-${tag}"
mkdir -p "$dest"
# Copy the canonical skill payload; exclude .git, .github, tests
# (downstream installs don't need CI workflow or development tests).
tar --exclude='./.git' \
--exclude='./.github' \
--exclude='./tests' \
--exclude='./broomva.tech-worktrees' \
--exclude='./bstack-worktrees' \
--exclude='./.cache' \
-cf - . | tar -xf - -C "$dest"
# Build the tarball in a deterministic order for reproducible
# sha256 across runs (though we don't fail-close on this yet).
( cd "$staging" && tar --sort=name -czf "$tarball" "bstack-${tag}" )
mv "$staging/$tarball" "./$tarball"
# sha256 sidecar — single canonical line, "<hash> <filename>" format.
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$tarball" > "${tarball}.sha256"
else
shasum -a 256 "$tarball" > "${tarball}.sha256"
fi
echo " packaged $tarball ($(wc -c < "$tarball") bytes)"
echo " sha256: $(awk '{print $1}' "${tarball}.sha256")"
# Upload as release assets.
gh release upload "$tag" "$tarball" "${tarball}.sha256" --clobber
echo " ✓ uploaded $tarball + sha256 to $tag"
name: Validate release
on:
pull_request:
paths:
- VERSION
- CHANGELOG.md
permissions:
contents: read
jobs:
version-changelog-alignment:
name: VERSION ↔ CHANGELOG match
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect VERSION change
id: version
run: |
set -euo pipefail
base="${{ github.event.pull_request.base.sha }}"
if ! git diff --name-only "$base"...HEAD | grep -qx VERSION; then
echo "VERSION not modified in this PR — nothing to validate."
echo "changed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
new="$(cat VERSION | tr -d '[:space:]')"
if ! printf '%s' "$new" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error file=VERSION::VERSION '$new' is not semver X.Y.Z"
exit 1
fi
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "new=$new" >> "$GITHUB_OUTPUT"
- name: CHANGELOG has matching section
if: steps.version.outputs.changed == 'true'
run: |
set -euo pipefail
new="${{ steps.version.outputs.new }}"
if ! grep -qE "^## ${new}([[:space:]]|$)" CHANGELOG.md; then
echo "::error file=CHANGELOG.md::No '## ${new}' section found — every VERSION bump needs a matching CHANGELOG entry."
exit 1
fi
echo " ✓ CHANGELOG.md has '## ${new}' section"
- name: VERSION moves forward
if: steps.version.outputs.changed == 'true'
run: |
set -euo pipefail
base="${{ github.event.pull_request.base.sha }}"
new="${{ steps.version.outputs.new }}"
old="$(git show "$base:VERSION" 2>/dev/null | tr -d '[:space:]' || echo '0.0.0')"
# Lexicographic comparison works for left-padded semver but not generally.
# Use sort -V for correctness.
highest="$(printf '%s\n%s\n' "$old" "$new" | sort -V | tail -1)"
if [ "$highest" != "$new" ] || [ "$old" = "$new" ]; then
echo "::error file=VERSION::VERSION must increase. Previous: ${old}, this PR: ${new}."
exit 1
fi
echo " ✓ VERSION ${old} → ${new}"
# Python build artifacts
__pycache__/
**/__pycache__/
*.py[cod]
*$py.class
*.so
# macOS
.DS_Store
# Local-only scaffolding produced by running bstack (bootstrap/doctor/install-rcs)
# against the bstack repo itself (self-dogfood). These are generated artifacts,
# never committed — the bstack source repo uses .github/workflows/ci.yml and
# .git/hooks, not the L3 stability workflow / .githooks the installer scaffolds.
.control/
.claude/
.githooks/
.github/workflows/l3-stability.yml
# {{WORKSPACE_NAME}} — Agent Guidelines
## Self-Meta Definition
This file IS the control harness for agents operating in this workspace. Reading this file is not optional — it is the first action an agent takes. The rules here are enforced by pre-commit hooks, Claude Code hooks, and the control audit (`make control-audit`).
**If you are an agent reading this**: you are part of a self-improving system. Your session will be captured, indexed, and used to improve future agents. The bstack consciousness substrate is always active.
## Development Philosophy
Before the twenty primitives below — which are the *mechanism* — these four principles are the *intent*. They are widely-recognized engineering disciplines, articulated sharply in Andrej Karpathy's observations on where LLM-assisted coding goes wrong. bstack's contribution is to make each one **machine-checkable** instead of a hopeful instruction: a principle that lives only as prose decays into ritual — acknowledged in passing, then ignored. Each principle below therefore names the primitive(s) that back it.
| Principle | What it means | Failure it prevents | Backed by |
|---|---|---|---|
| **1. Think before coding** | Surface assumptions and trade-offs *before* writing. Trace what the change depends on and what depends on it. Ask only for what you genuinely cannot derive from the repo. | Hidden assumptions — confidently building the wrong thing. | **Dep-Chain (P14)** + **Snapshot (P15)** |
| **2. Simplicity first** | Deliver the minimal change that solves the actual problem. No speculative features, no premature abstraction, no scope creep. | Overcomplication — code nobody asked for, harder to maintain than the problem warranted. | **Cross-Review (P20)** anti-slop gate |
| **3. Surgical changes** | Change only what the task requires. Match the surrounding style. Don't refactor tangentially or reformat untouched lines. | Unintended edits — diffs that touch more than they should, hiding the real change and breaking unrelated things. | **Dep-Chain (P14)** (enumerating what's touched bounds the change surface) + **Cross-Review (P20)** (flags tangential edits / scope creep) |
| **4. Goal-driven execution** | Define measurable success criteria up front, then loop — building and *verifying by interaction* — until they are met. | No verifiable "done" — work that *looks* complete without evidence it works. | **Empirical (P11)** (interaction evidence for "done") + **Orchestrate (P19)** (the verify-until-met loop) |
**Enforcement strength varies by principle, and that is the point.** P14/P15 are *hard predicates* — a checker reads the response for a dependency enumeration / state snapshot. P20 is an *independent-judgment* gate that blocks a merge below threshold. Both beat prose, because in neither case is the agent the one grading itself — but only the first kind is a literal yes/no predicate. The goal is to push each principle as far down the gradient toward a hard predicate as it will go.
The binding rule across all four:
> **A discipline that recurs as a phrase must map to a concrete, machine-checkable behavior — or it does not count as discipline.**
"Think deeply", "follow best practices", "keep it simple", "make sure it works" are *rituals* until they produce a concrete artifact: a dependency enumeration, a state snapshot, a minimal diff, an interaction receipt. The primitives below are how this workspace converts each principle from intention into enforced behavior.
**This philosophy is yours to extend.** Add project-specific principles to this section so every agent and contributor inherits them by default; the primitives stay the enforcement layer beneath whatever principles you declare here.
## Bstack Core Automation Primitives
This workspace is governed by the **bstack** primitive contract — twenty irreducible building blocks. All are always active. Run `bstack doctor` to verify compliance.
Each primitive carries a **short name** for agent prose. When referencing a primitive in responses, PR bodies, commit messages, or comments, use the `Name (Pn)` form — *"applying Snapshot (P15)"*, *"via Dep-Chain (P14)"*, *"running Bookkeeping (P6)"* — not bare `Pn`. The number is the canonical identifier; the short name is the human-readable handle.
**Short-name index**: Bridge (P1) · Gate (P2) · Tickets (P3) · Pipeline (P4) · Fanout (P5) · Bookkeeping (P6) · Freshness (P7) · Janitor (P8) · Wait (P9) · Hygiene (P10) · Empirical (P11) · Persist (P12) · Dream (P13) · Dep-Chain (P14) · Snapshot (P15) · Crystallize (P16) · Lens (P17) · Audience (P18) · Orchestrate (P19) · Cross-Review (P20).
### P1 — Bridge: Conversation Bridge (Episodic Memory)
**What**: Every Claude Code session is automatically captured as a structured Obsidian doc with YAML frontmatter, tool calls, conversation threads, files touched, and wikilinks.
**How**: Stop hook → `conversation-bridge-hook.sh` → JSONL transcript parsed → written to `*/docs/conversations/` → symlinked into your Obsidian vault.
**Invariant**: Bridge stamp at `~/.cache/broomva-bridge-stamp` < 24h stale. If stale, the agent is silently amnesic — fix immediately.
### P2 — Gate: Control Gate (Safety Shield)
**What**: PreToolUse hook intercepts destructive shell ops before execution.
**How**: `control-gate-hook.sh` evaluates pending tool calls against `.control/policy.yaml` gates G1–G11. Blocks force-pushes, secret commits, `rm -rf` on protected paths, `git reset --hard` without backup, etc.
**Invariant**: G1–G4 are blocking and cannot be overridden. G5–G6 are soft warnings.
### P3 — Tickets: Linear Tickets (Work Tracking)
**What**: Every unit of work maps to a Linear ticket; state transitions Backlog → Todo → In Progress → Done track real progress.
**How**: Linear MCP — agents call `save_issue` directly.
**Invariant**: No significant work without a ticket. Don't mark Done until merged + verified.
### P4 — Pipeline: PR Pipeline (CI/CD Gate)
**What**: All code changes flow through PRs with automated CI checks before merging.
**How**: branch → `gh pr create` → CI runs (lint/typecheck/security/preview) → merge when green → production deploy triggers.
**Invariant**: Never merge with failing checks. Never `--no-verify`.
### P5 — Fanout: Parallel Agent Dispatch (Concurrent Execution)
**What**: Independent work streams execute concurrently via isolated agents (worktrees or background processes).
**How**: `git worktree add` per agent. Multiple `Agent` tool calls in one message run concurrently. Communicate through git branches and Linear tickets, not shared state.
**Invariant**: Agents must not write to the same files. Branch naming unique per agent. Results merge to main only after verification.
### P6 — Bookkeeping: Knowledge Bookkeeping (Knowledge Graph Maintenance)
**What**: Every knowledge item entering the graph is scored, promoted, and lint-validated through a 7-stage pipeline.
**How**: `bookkeeping run` → Ingest → Score → Scatter → Resolve → Promote → Synthesize → Lint. Items < 2/9 discarded. Items ≥ 7 fast-path promote.
**Invariant**: `research/entities/` never contains unscored items. All entity pages must pass lint.
**Reflexive Trigger Rule**: Bookkeeping — and knowledge capture generally — is a reflex, not a request, **and never a question**. Agents must invoke `bookkeeping.py run` and file graph-worthy material without being prompted in any of these situations:
1. Before committing a feature/page that reads from the graph.
2. Before committing a synced snapshot to a public surface.
3. At the close of any substantial work session that produced graph-relevant material.
4. The moment a session surfaces a discrete graph-worthy item (a decision, name, discovered tool/person/paper, recurring pattern, or inferred typed relation) — file it proactively (entity page, `related:` edge, or synthesis note) and report what you filed in one line.
**Never a question.** The interrogative form — *"do you want me to create an entry / file this into the knowledge graph?"* — is forbidden. Capture is the default action, not an opt-in the user approves; the agent files first and reports after (user vetoes after via `git revert`, never gates before). Deferring capture to a user yes/no is the **permission-to-document anti-pattern** — knowledge that waits for permission is knowledge lost. Capture stays bounded by the Nous gate (proactive ≠ indiscriminate).
**Retrieval discipline (`/kg` for discovery, never substrate grep).** Knowledge-graph *discovery* — "what do we know about X", "load context for X", finding the relevant entities before reasoning — goes through **`/kg load <topic>`** (add `--terms <synonyms>` for paraphrase/jargon topics); use `Read` only on a slug confirmed present in `docs/knowledge-index.md`. **Never** `find -name "$slug.md"` / `grep` / `cat` over `research/entities/` as a *discovery* mechanism: a guessed slug that doesn't exist returns nothing **silently** (a no-match is silent by default; often further masked by `2>/dev/null` / `if [ -n "$f" ]`), so the agent reasons over a *false-complete* context, and hand-picked slugs miss the relevant entities the catalog routing surfaces. This bans only *discovery* greps — `find`/`grep`/`cat` stay legitimate for operating on a **confirmed known file**, **tooling/skill internals** (the `/kg` loader's own body-grep, `bookkeeping` lint/index), and **bulk edits or counting** — just never as the step that decides what's relevant.
### P7 — Freshness: Skill Freshness Check (Stale-Install Detector)
**What**: Reports stale installed skills at SessionStart so they get refreshed before causing silent failures.
**How**: SessionStart hook → `skill-freshness-hook.sh` checks the timestamp of `~/.config/broomva/p7/last-skill-update-check`. If ≥ 7 days old, prints a one-line nudge. Always exits 0.
**Invariant**: Hook always exits 0. Threshold via `BROOMVA_P7_THRESHOLD_DAYS` env var (default 7). Dismiss with `npx skills update -g` then `touch ~/.config/broomva/p7/last-skill-update-check`.
### P8 — Janitor: Branch + Worktree Janitor (Hygiene)
**What**: Detects merged branches (including squash-merged) and dead worktrees, removes them safely.
**How**: `make janitor` (wraps `scripts/branch-janitor.sh`). Squash-merge detection via `git commit-tree` synthetic + `git cherry`. Worktrees on dead branches pruned.
**Invariant**: Default `--dry-run` — pass `--apply` to actually delete. Never touches main/master/develop/HEAD/gh-pages or branches in `~/.config/broomva/p8-janitor/protected.txt`.
### P9 — Wait: Productive Wait (Wait-Optimizer / Event-Driven Wait Loop)
**What**: A wait optimizer. Convert any blocking external operation (PR CI, push-triggered deploys, builds, long-running indexing) into work on the next priority. PR CI is the canonical implementation; the primitive is broader.
**How (PR CI canonical)**: `python3 skills/p9/scripts/p9.py watch <pr> --background` spawns `gh pr checks --watch` via `run_in_background`. While watcher runs, agent pulls work via `p9 wait-queue pop`. On bg-task notification: `p9 status` then green → `p9 merge-ready` → metalayer authorizes; red → `p9 heal --classify`.
**How (non-PR waits — today: manual)**: For waits without PR (push-triggered deploys, external builds, long index ops), p9 doesn't track yet. Do *one* direct check on completion after kicking off next-priority work; never `sleep`.
**Invariant**: Never `sleep` on a blocking wait. Every failure produces (a) a `state.jsonl` event, (b) a Linear ticket, or (c) both — silent state drops are forbidden. Heal actions scoped to PR diff. Setpoints in `.control/policy.yaml` `ci_watch:` / `ci_heal:` blocks fail closed if missing.
**Reflexive Trigger Rule**: P9 is a reflex. Agents must apply *productive-wait discipline* without being prompted in any of these situations:
1. Immediately after `git push` opening/updating a PR — `p9 watch <pr> --background`.
2. After `git push` triggering a non-PR deploy — single direct check after next-priority work; never sleep.
3. Whenever tempted to `sleep` while a blocking operation runs — hard ban; pull from `p9 wait-queue pop`.
4. When red CI bg-task notification fires — `p9 heal --classify` first.
5. When `p9 status` reports `MERGE_READY` — invoke `p9 auto-merge` rather than `gh pr merge` directly.
### P10 — Hygiene: Worktree Hygiene Discipline (Clean-Tree Reset Point)
**What**: Reflexive discipline binding every agent to (a) make a deliberate worktree-or-not decision before writing the first file, (b) keep `git status` clean throughout the PR lifecycle, (c) run P8 janitor immediately after merge.
**How**: Reasoning-enforced rule, not a hook. P5 provides the *mechanism* (git worktrees); P10 provides the *discipline*.
**Invariant**: After every PR merge, both worktree (if any) and branch are gone. Before new substantial work, `git status` is clean (or explicitly noted).
**Reflexive Trigger Rule**: P10 is a reflex. Agents must apply the following without being prompted:
1. Before writing the first file of any new substantial work — decide worktree-or-not, state the choice.
2. Before pushing to remote — `git status` check; dirty WIP gets committed/stashed/extracted, never pushed past.
3. After PR merge — immediate `make janitor` (P8).
4. At SessionStart — audit `git worktree list` + `git branch`; clean orphans before new work.
### P11 — Empirical: Empirical Feedback Loop (Closed-Loop Validation)
**What**: Reflexive discipline binding every agent to *validate by interacting* with what they build — not just by reasoning + lint + CI exit codes. Multi-modal (logs, screenshots, video, audio), multi-level (smoke, unit, integration, regression, E2E, deploy verification).
**How**: Composition of existing tools and skills:
- Server logs → `run_in_background` tailing dev server output
- Browser E2E → `gstack` (fast headless) / `agent-browser`
- Visual diff → `before-and-after` skill
- Smoke / unit / integration / regression → project test runners + `qa` / `dogfood`
- Deploy verification → Vercel preview URL → screenshot via `gstack`
The agent picks the right subset, runs as parallel watchers, and **captures evidence**.
**Invariant**: Before claiming any work *complete*, the agent has interacted with the deployed/running version (or stated explicitly why interaction wasn't possible). The interaction is captured and surfaced in the response. *Reasoning isn't validation; interaction is.*
**Reflexive Trigger Rule**: P11 is a reflex. Agents must apply the following without being prompted:
1. Before writing the first file of substantial work — identify validation surfaces. State the validation plan as a contract.
2. During development of work touching a running process — keep at least one log-tail or watcher in `run_in_background`.
3. Before claiming complete — exercise the change end-to-end. Capture multi-modal evidence.
4. After deploy — capture deployed-state evidence. *Compile-time success is not deploy-time correctness.*
5. When CI or tests fail — capture full context first before attempting a fix.
6. At session end — produce a *dogfood receipt*.
7. **Dogfood Plan keyed to detected stack** — before substantive feature work, produce a Dogfood Plan (entry surface · driver · evidence · smoke · end-to-end · receipt anchor) in the response and PR body, citing the per-stack pattern from the bstack cookbook (Tauri+sidecar / Next.js / Expo RN / Rust CLI / REST API / MCP server). Interceptor is mandatory for visual deploy verification; gstack / cliclick / screencapture / curl+jq compose per stack. The plan anchors at `## Dogfood Plan (Stack: <pattern>)` in this AGENTS.md, or `docs/dogfood-plan.md`, or the PR body — `bstack doctor` §13 looks for any of the three.
## Dogfood Plan (Stack: TBD)
<!-- bstack onboard stubs this section the first time the repo is bootstrapped.
Detected stack is auto-filled when the repo signals match a known pattern
(Cargo.toml + src-tauri/ → Tauri; next.config.* → Next.js; etc.).
Fill the rows below for the current substantive work unit; the receipt
anchor at session end is the artifact that closes the loop. -->
- **Entry surface**: <URL / window / CLI command the user touches>
- **Driver**: <Interceptor / gstack / cliclick+screencapture / curl+jq / xcrun simctl>
- **Evidence**: <screenshot path / response body path / log line>
- **Smoke**: <one-line "didn't obviously break" check>
- **End-to-end**: <multi-step user flow that catches regression a smoke test misses>
- **Receipt anchor**: <file / line / PR comment ID where the receipt lives>
Reference: `bstack/references/dogfood-patterns.md` for the per-stack surfaces matrix, canonical arc, gotchas, and receipt template.
### P12 — Persist: Persistent Loop Discipline (Cross-Context Restart Loop)
**What**: Reflexive discipline binding every agent to *restart the context window when it rots*, while preserving state in the filesystem. Long-horizon work (>1h, the METR 80%-reliability ceiling) decays inside a single conversation as the context window passes ~100K tokens.
**How**: `python3 skills/persist/scripts/persist.py iterate <PROMPT.md>` substrate. Each iteration spawns a fresh agent context; state persists in PROMPT.md + git tree + state.jsonl. Validation backpressure from compilers/tests/linters, not model self-grading.
**Invariant**: state lives in the filesystem. Each iteration is a fresh subprocess. Budget: default 50 iterations / 14400s wall-clock.
**Reflexive Trigger Rule**: P12 is a reflex. Apply without being prompted:
1. Before any work that may exceed ~1h of unsupervised agent time — write PROMPT.md, call `persist iterate`. Don't try >1h work in-context.
2. When session token usage crosses ~100K — restart, don't continue in the rotted context.
3. When the same fix has been attempted ≥3 times without convergence — stop in-context; spawn fresh persist loop.
4. When orchestrating long-horizon work — default to persist + periodic checkpoints; compose with P5 worktrees.
5. When the user says "run this in the background for an hour" — that's persist territory.
### P13 — Dream: Dream Cycle Discipline (Tier-Crossing Consolidation)
**What**: Reflexive discipline binding every agent to apply the **5-phase dream shape** (*gather → replay → prune → consolidate → index*) for any consolidation that crosses a cadence-tier boundary. Closes the *shadow dream* corruption mode.
**How**: Reasoning-enforced. Composes with P6 (`bookkeeping replay` is the canonical reference instance) and future Life primitives (askesis T1→T2, anamnesis T2→T3, when shipped).
**Invariant**: any consolidation that crosses a cadence-tier boundary MUST replay against a frozen substrate before committing. Without replay, dense lower-tier signal corrupts sparse upper-tier rules.
**Reflexive Trigger Rule**: P13 is a reflex. Apply without being prompted:
1. Before any consolidation that promotes lower-tier signal to upper-tier rules — verify the consolidation primitive has a replay phase.
2. For knowledge-graph promotion — use `bookkeeping replay` (not `bookkeeping run`) for substantial promotion runs.
3. For governance changes (L3 tier) — every PR is a dream cycle: gather (PR description), replay (worktree + CI + doctor), prune (CI failures), consolidate (squash merge), index (commit history).
4. When designing a NEW consolidation primitive — implement the 5-phase shape from day 1; don't ship shadow-dream form.
5. When you observe a new dream instance shipping — record it for the rule-of-three counter.
The morpheus crate (shared abstraction across implementations) is deferred per rule-of-three until ≥2 dream instances ship beyond P6.
### P14 — Dep-Chain: Dependency-Chain Reasoning Discipline
**What**: Reflexive discipline binding every agent to *explicitly enumerate dependencies* before any substantive write. Closes the "think deeply" ritual failure mode — the phrase recurs without producing concrete behavior change.
**How**: Before any code/doc edit that affects >1 file or any public surface, the agent surfaces:
- **Upstream**: files, functions, types, contracts, deployed state this write depends on
- **Downstream**: consumers, tests, CI gates, docs, in-flight PRs depending on this
The enumeration is concrete (file paths, function names, contract identifiers) and lives in the response, PR body, or commit message — never the agent's head.
**Invariant**: When the user prompt contains phrases like "think deeply through chain of dependencies", "follow best practices", "consider the implications", the agent's response MUST include a concrete dep-chain block. Phrase acknowledgement without the block is ritual.
**Reflexive Trigger Rule**: P14 is a reflex. Apply without being prompted:
1. Before any write to a file that exports a public API — enumerate downstream callers.
2. Before any refactor — enumerate both directions.
3. Before any cross-project change — enumerate which other projects depend on the touched surface.
4. When user prompt contains a "think deeply"-class phrase — produce the dep-chain block, not the acknowledgement.
### P15 — Snapshot: State-Snapshot Before Action
**What**: Reflexive discipline binding every plan to a *fresh state snapshot* of the workspace. Closes the "help me understand where we stand" failure mode — agents report last-seen state instead of current state.
**How**: Before any plan or significant action, the agent surfaces:
- `git status` + branch + ahead/behind vs upstream
- In-flight PRs (`gh pr list --json number,title,headRefName,state`)
- Linear ticket state for the current work unit
- Bookkeeping / bridge freshness (cache stamps, last pipeline run)
- Last deploy state (relevant project's preview/production URL + commit)
The snapshot is *part of* the planning response — not deferred to a follow-up call.
**Invariant**: A plan built on stale state fails silently — re-solves solved problems, conflicts with parallel work, misses in-flight PRs. P15 makes state-checking a cheap reflex, not a request the user has to make.
**Reflexive Trigger Rule**: P15 is a reflex. Apply without being prompted:
1. At session start when reviewing prior context.
2. Before any plan that touches multiple files or cross-project surfaces.
3. When the user asks "where are we" / "what's left" / "is everything committed" — the answer is the snapshot, not a recollection.
4. After any long-running background operation completes — re-snapshot before next plan.
### P16 — Crystallize: Crystallization Discipline (the Bstack Engine)
**What**: Meta-primitive — the rule-of-three loop that produces every other primitive. When a pattern recurs ≥3 times across sessions, propose promotion to skill / SKILL.md / AGENTS.md section / `.control/policy.yaml` gate.
**How**: Four gate conditions for promotion:
1. ≥3 distinct instances of the pattern (logged with citations)
2. Concrete mechanism (not just a description)
3. Stated invariant (machine-checkable)
4. Stated failure mode (what goes wrong without it)
Candidates live in `research/entities/pattern/bstack-engine.md` (or equivalent ledger). Promotion is deliberate — L3 stability budget (λ₃ ≈ 0.006) constrains how rapidly governance changes.
**Invariant**: The crystallization loop runs inside the workspace, not in the user's head. Patterns that recur without being named are technical debt at the governance layer.
**Reflexive Trigger Rule**: P16 is a reflex. Apply without being prompted:
1. When you observe the same instruction repeated across ≥3 sessions — log it as a candidate.
2. When a user prompt phrase recurs without producing concrete behavior change — flag as ritual; queue for promotion or carve-out.
3. At session end — survey what was learned; promote candidates with all four gates passing.
4. Before adding any new primitive — verify all four gates, not three.
### P17 — Lens: Lens-Routed Request Articulation (`role/x`)
**What**: Reflexive discipline routing every substantive user input through a typed lens (`role/x` intake). Replaces "act as X" persona prompting (debunked: MMLU drops 71.6% → 66.3% with naive personas) with substantive context loading.
**How**: Lens registry at `roles/<name>.md`. Score signals (paths + prompt keywords + branch + Linear labels) against lens triggers; threshold ≥2 selects. Load substantive context (files, conventions, domain checklist via `extends:` chain). Decide mode: `augment` (default, silent), `rewrite` (surfaced), `decompose` (P5 fan-out, user-approved).
**Invariant**: No `act as X` persona rewrites. Lenses load substantive context only. Lens selection is logged. Mode decision is surfaced unless `augment`.
**Reflexive Trigger Rule**: P17 is a reflex. Apply without being prompted:
1. On every substantive user input — score lens triggers, log the selection (even if `augment`).
2. When user input matches `decompose` criteria — surface composition tree, request approval before P5 dispatch.
3. When lens has `status: candidate` — track outcome to feed rule-of-three promotion.
### P18 — Audience: Format-Follows-Audience Discipline
**What**: Reflexive discipline binding format choice to audience:
- **Agent-readable** (LLM, system-prompt loaded, in-repo reference) → **markdown**
- **Human-readable** (decisions, review, exploration, sharing) → **HTML**
- **Both** (README, CHANGELOG, GitHub-browseable) → markdown (GitHub renders)
- **Throwaway interactive UI** → HTML
**How**: Path conventions for substantive deliverables:
- Specs/plans/ADRs/designs → `docs/{specs,plans,adrs,designs}/<topic>.html`
- PR explainers for substantive PRs → `docs/pr-explainers/PR-<n>.html`
- Knowledge graph entities (LLM-loaded) → `research/entities/{type}/{slug}.md`
- README/CHANGELOG/SKILL.md → markdown
**Anti-patterns**: ASCII pseudo-diagrams, unicode-color approximations, >100-line markdown specs without HTML companion.
**Invariant**: Format follows audience, not habit. Markdown's expressiveness ceiling means humans bounce off agent-produced specs at ~100 lines; HTML's information density (tables, SVG, CSS, interactivity) carries the load. The 2-4× HTML generation cost is paid only on artifacts a human will actually read.
**Reflexive Trigger Rule**: P18 is a reflex. Apply without being prompted:
1. Before producing a spec/plan/ADR/design — default HTML.
2. Before a substantive PR description (>200 LOC OR public API OR multi-file) — produce an HTML PR-explainer at `docs/pr-explainers/PR-<n>.html`.
3. Before a report/retrospective/research synthesis for human consumption — HTML with embedded SVG diagrams.
4. When tempted to ASCII-diagram in markdown — STOP. SVG inside HTML is the correct primitive.
5. When editing `SKILL.md` / `AGENTS.md` / `CLAUDE.md` / `README.md` / `CHANGELOG.md` / entity pages — markdown is correct (LLM-loaded surfaces).
6. When user asks for "a doc explaining X" — apply the audience test, don't default to markdown.
### P19 — Orchestrate: Orchestration-Mechanism Selection Discipline
**What**: Names the autonomous-continuation family (six mechanisms across the 2×2×2 cube: `/goal` | Wait (P9) | `/loop` | Persist (P12) | Fanout (P5) | `bstack wave`) and the selection discipline. Picks the right mechanism for the work shape; composes dynamically; never returns control mid-arc when a mechanism would keep it closed.
**How**: At pre-flight of substantive autonomous work, apply the **2×2×2 mechanism cube**. Three axes: session-scope (within/across), trigger-source (external-event/internal-condition), agent-count (N=1/N>1).
**N=1 plane** (single-agent work):
| | Within session | Across sessions |
|---|---|---|
| **External trigger** (event-driven) | **Wait (P9)** `p9 watch --background` (CI/deploy/build blocking) | **Persist (P12)** `persist iterate PROMPT.md` (cross-context-rot, >1h) |
| **Internal trigger** (condition or time) | **`/goal <condition>`** (Haiku evaluator per turn) | **`/loop <interval>`** (Claude Code time-trigger) |
**N>1 plane** (parallel-agent work):
| | Within session | Across sessions |
|---|---|---|
| **External trigger** (event-driven) | **Fanout (P5)** — multiple `Agent` tool calls in one message; each isolated context | **`bstack wave dispatch <plan...>`** — one `claude --bg` per plan, worktree per plan, JSONL state in `~/.cache/bstack/wave/<id>/` |
| **Internal trigger** (condition or time) | Fanout (P5) + `/goal` per agent (rare; expensive) | (speculative — multiple `persist iterate` loops on a `/loop` interval) |
Decision logic:
1. Verifiable end state + bounded session + condition fits 4000 chars → `/goal <pipeline-completion-condition>`
2. External completion event blocking (CI, deploy, build) → Wait (P9) `p9 watch --background` + drain wait-queue
3. Time-triggered recurring routine → `/loop <interval> <slash-command>`
4. >1h work OR cross-session OR context window approaching ~100K → Persist (P12) `persist iterate PROMPT.md` with budget
5. Independent in-session subtasks with no shared mutable writes → Fanout (P5) — multiple `Agent` calls in one message
6. N independent plan files for cross-session parallel fan-out (spec sub-phases, multi-crate work) → `bstack wave dispatch <plan...>` — atomic validate + worktree per plan
Compositions are dynamic: Persist iterations can invoke `/goal` for sub-tasks; `/goal` sessions fire Wait (P9) watchers when CI is blocking; `/loop` schedules can spawn Persist for the long-horizon piece; `bstack wave` is the across-session sibling of Fanout (P5) — escalate to wave when parallel work doesn't fit one in-session message-fan-out.
**Invariant**: No autonomous-continuation work without (a) an explicit mechanism choice surfaced in the response, and (b) a one-line justification matched to a cell of the 2×2×2 cube. Returning control mid-arc when a mechanism would keep it closed is the failure mode P19 prevents.
**Reflexive Trigger Rule**: P19 is a reflex. Apply without being prompted:
1. Pre-flight of substantive autonomous work — state chosen mechanism + cite cube cell (session-scope × trigger-source × agent-count).
2. Before returning control mid-arc — verify no mechanism would keep the arc closed.
3. At mechanism boundary crossings (goal hits >1h, context ~100K, in-session N>1 work needs across-session fan-out) — explicit transition, not drift.
4. When composing mechanisms — surface the composition tree, don't compose silently.
5. Tempted to type "continue please" or wait for user prompts — STOP. That's the ritual P19 makes impossible.
### P20 — Cross-Review: Cross-Model Adversarial Review Gate
**What**: Names the rule that *the writer cannot be the final judge*. Before substantive PRs merge, fire a cross-model adversarial gate. Single-model planning + implementing + reviewing reproduces the model's systematic biases — what cross-model-agents research calls *slop* (over-engineered abstractions, unnecessary wrappers, template-paste patterns).
**How**: Three strata, ordered by strength:
| Strata | Mechanism | When |
|---|---|---|
| **A** True cross-vendor | `codex exec -m gpt-5.4` reads diff + scores | Codex CLI installed |
| **B** Cross-context same-model | Fresh `Agent` subagent under devil's-advocate brief | Always available |
| **C** Composed existing skills | `superpowers:constructive-dissent`, `devils-advocate`, `pr-review-toolkit:*`, `critique`, `premortem`, `plan-*-review` | Always — the toolkit P20 makes mandatory |
Scoring: anti-slop ≥7/10 to pass; max 3 fix rounds; verdict logged in PR comments + Linear ticket (if workspace uses Linear). Implementation: `broomva/cross-review` skill. The gate fires *before* P4 auto-merge — not after merge as code review.
**Invariant**: Substantive PRs (>200 LOC OR public API change OR multi-file OR governance-class) cannot merge without cross-model adversarial verdict ≥7/10. Self-review by the writing model is forbidden as the *sole* verdict.
**Reflexive Trigger Rule**: P20 is a reflex. Apply without being prompted:
1. Before pushing substantive PRs — fire the gate (Strata A if Codex, else B+C). Score + verdict precede merge.
2. When verdict <7 — fix → rescore. Max 3 rounds. Round 3 failure → escalate to user.
3. When the writer is the only model in the loop — STOP. Strata B at minimum is mandatory.
4. When tempted to skip P20 because "small PR" — threshold is *substantive* (>200 LOC OR public API OR multi-file OR governance). Trivial (typo, single-file doc) exempt.
5. P20 sits between Empirical (P11) validation and Pipeline (P4) auto-merge — does not replace either.
---
These twenty primitives compose into the full autonomous development loop:
```
User intent → Lens (P17) intake → Snapshot (P15) → Orchestrate (P19) mechanism choice → Tickets (P3) → Fanout (P5) dispatch
→ Prior context via Bridge (P1) [+ Freshness (P7)] [+ Hygiene (P10) audit]
→ Gate (P2) active
→ Dep-Chain (P14) trace → Hygiene (P10) worktree decision → Empirical (P11) validation plan
→ IF long-horizon (per Orchestrate (P19)) → Persist (P12) loop with PROMPT.md + budget
→ Code written + Empirical (P11) parallel watchers → PR via Pipeline (P4)
→ Wait (P9) CI watch + heal loop
→ Empirical (P11) deploy verification (preview URL, screenshots, browser session)
→ Cross-Review (P20) gate (Strata A or B+C, ≥7/10) → if pass, Pipeline (P4) auto-merge eligible
→ Merge → Hygiene (P10) post-merge cleanup via Janitor (P8) → Deploy
→ Dream (P13) for any consolidation (Bookkeeping (P6) replay first)
→ Empirical (P11) dogfood receipt → Session captured via Bridge (P1) → Knowledge via Bookkeeping (P6)
→ Audience (P18) check: spec/plan/report → HTML; .md/SKILL.md/CHANGELOG → markdown
→ Crystallize (P16) gate: did this session produce a new ≥3-instance pattern? → propose primitive
→ System improved (EGRI)
```
## Plugin Skill Precedence
Plugin skills (`superpowers:*`, `pr-review-toolkit:*`, `codex:*`, etc.) are **subordinate to bstack primitives**. Where they conflict, bstack wins. This is encoded in `superpowers:using-superpowers` itself: *"User's explicit instructions … highest priority. … If CLAUDE.md says X and a skill says Y, follow the user's instructions."* Reading CLAUDE.md → this file *is* that explicit instruction.
The most common collision: plugin skills that mandate user interaction before action — most notably `superpowers:brainstorming` (discovery interview), `superpowers:writing-plans` ("plan before touching code" even when the task is mechanical), and the meta-rule that prompts the agent to invoke a skill "even if 1% might apply." The bstack answer is **context-first, user-extract last**:
1. Before any "interview-the-user" plugin skill fires, apply **Dep-Chain (P14)** + **Snapshot (P15)** over:
- Workspace memory files (auto-memory directory; persona, project state, feedback)
- `research/entities/{concept,pattern,tool,person,project}/` — knowledge graph (grep by topic before asking)
- `docs/` (per-project) — architecture, specs, plans, conversations
- Task-mentioned files (CV, spec, ticket body, PR diff)
2. Synthesize what's already known from those sources.
3. **Ask the user only for irreducible residuals** — facts that genuinely cannot be derived from disk.
4. If steps 1–2 fully determine the task, the plugin interview is skipped. Proceed to execution.
### What this kills
The "form-fill ritual" — agent receives an application/CV/intake form, opens with a numbered table of N+ questions about facts that live in workspace memory + knowledge graph + project docs. The workspace's curated context exists precisely to remove ask-the-user-for-context loops; plugin skills that re-introduce those loops are violating the substrate's intent, not augmenting it.
### What this keeps
The disciplines plugin skills bring that DON'T conflict with bstack:
- `superpowers:test-driven-development` — TDD execution discipline
- `superpowers:verification-before-completion` — pairs with Empirical (P11)
- `superpowers:systematic-debugging` — diagnostic flow before proposing fixes
- `superpowers:requesting-code-review` — two-stage review pattern (spec-compliance + code-quality)
- `superpowers:executing-plans`, `subagent-driven-development`, `dispatching-parallel-agents` — subagent dispatch substrate
- `superpowers:using-git-worktrees` — composes with Hygiene (P10)
- `superpowers:finishing-a-development-branch` — composes with `/ship`
- `pr-review-toolkit:*`, `codex:*` — orthogonal toolkits
These run as before. The precedence rule is targeted at *plugin-skill rituals that ask before reading* — nothing else.
### Why this isn't a new primitive
Dep-Chain (P14) + Snapshot (P15) already define the required behavior — context-load before action. This section makes their precedence over plugin-skill rituals explicit but adds no new mechanism. The L3 stability budget favors clarifying existing rules over adding new ones.
## Conventions
- **Git**: feature branches, squash merge via PR. Never force push main.
- **OSS**: every public repo must have `README.md`, MIT `LICENSE`, and GitHub topics.
- **Skills**: every skill repo must have `SKILL.md` at root with frontmatter (`name`, `description`).
## Harness Commands
From workspace root:
```bash
bstack doctor # Verify primitive contract compliance
bstack repair # Fix specific gaps surfaced by doctor
bstack status # Show installed-vs-missing skills + harness health
bstack status --aggregate # Federation rollup across registered workspaces
bstack workspace register # Register this workspace in the host federation registry
bstack workspace list # List all registered workspaces
make control-audit # Full metalayer compliance audit
make janitor # P8 janitor (dry-run by default)
```
## Substrate Surfaces
### Federation (v0.18.0 — Phase 8)
`bstack workspace` is a substrate surface that maintains an **opt-in**
host-level registry of bstack-governed workspaces at
`~/.broomva/global/registry.yaml`. Federation is **read-only aggregation** —
each workspace remains the source of truth for its own state. The registry
is the index `bstack status --aggregate` walks to surface the composite
health of every registered workspace on this host.
Federation is **not a new primitive** (no P21). It composes existing
primitives: Snapshot (P15) emits the per-workspace audit signal that the
aggregate rollup reads; Bookkeeping (P6) and the multi-layer composite-ω
(v0.16.0 §19) feed the per-workspace verdict. The registry is the spine
that lets a developer see all bstack workspaces at once without inventing
a new control loop.
Registering is opt-in and idempotent:
```bash
bstack workspace register # registers $PWD (name = basename)
bstack workspace register --tag client-x --tag primary
bstack workspace list --json # machine-readable for scripts
bstack workspace info # is this workspace registered?
bstack workspace deregister --name X # remove an entry
```
Doctor §20 reports federation health (informational unless the registry
file is corrupted with `schema_version != 1`).
## Conversation Capture
Every Claude Code session under this workspace is automatically captured via P1. Session docs land in `*/docs/conversations/`, symlinked into your vault.
## Agent Boundaries
- **Read anything** in the workspace to understand context.
- **Write only** within the project you're tasked with.
- **Cross-project changes** require explicit user approval.
- **Secrets**: Never commit `.env`, credentials, or API keys.
- **Destructive git**: Never force push, reset --hard, or delete branches without asking.
- **PRs are checkpoints**: Create PRs for review, don't merge directly without CI green.
## Self-Improvement (EGRI Integration)
bstack supports EGRI (Evaluator-Governed Recursive Improvement):
- **Mutable artifact**: Agent behavior (conversation patterns, tool selection, code quality)
- **Immutable evaluator**: `bstack doctor` + `make control-audit`
- **Promotion policy**: Improvements that pass all gates get incorporated into AGENTS.md/policy.yaml
- **Rollback**: Git history is the safety net
When an agent discovers a better pattern:
1. Validate it works (run harness commands)
2. Document in conversation log (automatic via hook)
3. If significant, propose update to AGENTS.md or `.control/policy.yaml`
4. Future agents inherit the improvement
The L3 stability budget (λ₃ ≈ 0.006) constrains how rapidly governance can change. Observe patterns across multiple sessions before crystallizing rules.
# =============================================================================
# bstack — Closure-Contract Arcs (the (X, U, h, Π, T) 5-tuple, generalized)
# =============================================================================
#
# A closure-contract *arc* lifts the same 5-tuple already used at the 4 hard-
# coded RCS layers (see assets/templates/rcs-parameters.toml.template) to the
# N user-declared domain arcs the workspace actually runs every day. Each arc
# names one feedback loop the workspace promises to close:
#
# (plant_surfaces, sensor, actuator, termination, tau_a)
#
# read as:
#
# "for these plant surfaces, observe via this sensor, act via this
# actuator, terminate when this condition holds, within tau_a seconds."
#
# The agent's reasoning is the universal Π (controller). When
# actuator.kind == "agent_reasoning" the controller binding is implicit —
# the agent loop closes the arc by reading the sensor, deciding, and acting.
# Script / mcp_tool / http actuators bind specific mechanisms while keeping
# the agent in the supervisory role.
#
# Read by:
# - scripts/compute-arc-status.sh (per-arc verdict reader; mirrors
# compute-budget-status.sh shape)
# - scripts/doctor.sh §20 (arcs-declared health)
# - schemas/arcs.v1.json (declarative shape; bstack doctor
# runs json-schema validation in §10)
#
# Editing rules:
# - Bump schema_version below when adding/removing fields.
# - Run `bash scripts/compute-arc-status.sh --human` after edits to verify
# each arc still resolves to a verdict.
# - tau_a is in seconds (per-arc switching cost denominator). Keep it
# proportional to the natural cadence of the loop: PR CI is ~1800s,
# bookkeeping promotion-quality is ~86400s, etc.
# - Workspace files override this template: copy to .control/arcs.yaml,
# edit, and compute-arc-status.sh will prefer the workspace file.
schema_version: 1
arcs:
# ---------------------------------------------------------------------------
# Arc 1 — code-pr-greenflow
# ---------------------------------------------------------------------------
# Closes the loop: "every PR I open ends up merged with all checks green."
# Plant: GitHub PR checks. Sensor: `gh pr checks --json`. Actuator: agent
# reasoning (which calls heal-recipes from .control/policy.yaml ci_heal:
# block). Termination: predicate over checks_green AND merged. Window:
# 30 minutes (PR CI ceiling — beyond this the human steps in).
- id: code-pr-greenflow
description: PR CI greenflow — open, watch, heal, merge.
plant_surfaces:
- gh://${repo}/pulls
- fs://.github/workflows/
sensor:
kind: json_path
source: gh pr checks --json conclusion,name --jq '[.[] | select(.conclusion != null)]'
expr: all(.conclusion == "SUCCESS")
actuator:
kind: agent_reasoning
tools:
- gh
- skills/p9/scripts/p9.py
- skills/bookkeeping/scripts/bookkeeping.py
termination:
kind: predicate
expr: checks_green AND merged
tau_a: 1800
shield_ref: gates.hard.G-PR-MERGE
# ---------------------------------------------------------------------------
# Arc 2 — bookkeeping-promotion-quality
# ---------------------------------------------------------------------------
# Closes the loop: "every Layer-2 raw extract that ends up an entity page
# in research/entities/ scored ≥7/9 on the Nous gate." Plant: research/
# notes/ + research/entities/. Sensor: a hypothetical eval script that
# exits 0 when the most recent promotion run scored ≥ threshold.
# Actuator: agent reasoning (the agent re-runs bookkeeping replay if the
# score dips). Termination: score_threshold. Window: 1 day (matches the
# bookkeeping cadence and the L3 governance budget).
- id: bookkeeping-promotion-quality
description: Bookkeeping promotion quality — every entity page meets the Nous gate.
plant_surfaces:
- fs://research/entities/
- fs://research/notes/
sensor:
kind: exit_code
source: skills/bookkeeping/scripts/eval-promotion-quality.sh
actuator:
kind: agent_reasoning
tools:
- skills/bookkeeping/scripts/bookkeeping.py
termination:
kind: score_threshold
expr: score >= 7
tau_a: 86400
shield_ref: gates.governed.G-PROMOTION-NOUS
# {{WORKSPACE_NAME}} — bstack-governed workspace
## Identity
This workspace is governed by **bstack** — twenty irreducible primitives (P1–P20) that turn an agent-driven workspace into a self-operating system. The full primitive contract lives in [AGENTS.md](AGENTS.md). Run `bstack doctor` to verify compliance.
## Development Philosophy
Four principles govern every change in this workspace — *think before coding · simplicity first · surgical changes · goal-driven execution*. They are widely-recognized engineering disciplines (sharpened by Andrej Karpathy's observations on LLM coding pitfalls); bstack's job is to make each one **machine-checkable** rather than a hopeful instruction, because a discipline that lives only as prose decays into ritual. Each principle is backed by the primitive(s) that hold it — see [AGENTS.md § Development Philosophy](AGENTS.md#development-philosophy) for the full mapping (and a note on why enforcement strength varies). Extend it with project-specific principles; the primitives stay the enforcement layer.
## Bstack Core Automation Primitives
Twenty irreducible building blocks that make this workspace self-operating. All are always active. Full specification in `AGENTS.md`.
Each primitive carries a **short name** for agent prose. When referencing a primitive in responses, PR bodies, commit messages, or comments, use the `Name (Pn)` form — *"applying Snapshot (P15)"*, *"via Dep-Chain (P14)"*, *"running Bookkeeping (P6)"* — not bare `Pn`. The number is the canonical identifier; the short name is the human-readable handle.
**Short-name index**: Bridge (P1) · Gate (P2) · Tickets (P3) · Pipeline (P4) · Fanout (P5) · Bookkeeping (P6) · Freshness (P7) · Janitor (P8) · Wait (P9) · Hygiene (P10) · Empirical (P11) · Persist (P12) · Dream (P13) · Dep-Chain (P14) · Snapshot (P15) · Crystallize (P16) · Lens (P17) · Audience (P18) · Orchestrate (P19) · Cross-Review (P20).
| # | Primitive | Mechanism | Invariant |
|---|-----------|-----------|-----------|
| P1 | **Bridge** — Conversation Bridge | Stop hook → JSONL → Obsidian docs → vault | Bridge stamp < 24h stale |
| P2 | **Gate** — Control Gate | PreToolUse hook → `.control/policy.yaml` | G1–G4 blocking, never bypassed |
| P3 | **Tickets** — Linear Tickets | Every work unit tracked Backlog → Done | No significant work without a ticket |
| P4 | **Pipeline** — PR Pipeline | Branch → PR → CI → merge → deploy | Never merge with failing checks |
| P5 | **Fanout** — Parallel Agents | Concurrent isolated agents via worktrees | No shared mutable file writes |
| P6 | **Bookkeeping** — Knowledge Bookkeeping | `bookkeeping run` → score → promote → entity pages → synthesize | `research/entities/` never contains unscored items; knowledge capture is a reflex, not a request, and **never a question** (file proactively, report after — never ask permission to document) |
| P7 | **Freshness** — Skill Freshness Check | SessionStart hook → reports stale-skill nudge if last update check ≥ 7d ago | Never blocks; closes silent-rot bug for `npx skills add` snapshots |
| P8 | **Janitor** — Branch + Worktree Janitor | `make janitor` → detects squash-merged branches + dead worktrees, removes safely | Default `--dry-run`; never touches protected branches |
| P9 | **Wait** — Productive Wait (`broomva/p9` skill) | wait-queue drains while a blocking operation runs (PR CI is the reference impl: `gh pr checks --watch` via `run_in_background` → classifier + evaluator self-heal). For non-PR waits (push-triggered deploys, builds), do a single direct check after kicking off next-priority work. | Never `sleep` on a blocking wait; merge defers to control metalayer |
| P10 | **Hygiene** — Worktree Hygiene Discipline | Reflexive rule: decide worktree-or-not before first file; keep `git status` clean; auto-run P8 janitor after every merge | A clean tree is the only reliable reset point |
| P11 | **Empirical** — Empirical Feedback Loop | Reflexive rule: validate by *interacting* — log-tails, browser E2E, screenshots, deploy verification, multi-level test composition | Reasoning isn't validation; interaction is |
| P12 | **Persist** — Persistent Loop Discipline (`broomva/persist` skill) | Reflexive rule: cross-context restart loop — state in filesystem (PROMPT.md + git tree), each iteration spawns a fresh agent context | At long-horizon work (>1h), in-context loops decay; restart fresh, backpressure from compilers/tests |
| P13 | **Dream** — Dream Cycle Discipline | Reflexive rule: any consolidation that crosses a cadence-tier boundary MUST follow the 5-phase shape (gather → replay → prune → consolidate → index) | Replay against frozen substrate is the runtime form of stop-gradient; without it, dense lower-tier signal corrupts sparse upper-tier rules |
| P14 | **Dep-Chain** — Dependency-Chain Reasoning Discipline | Reflexive rule: before any substantive write, enumerate upstream (files, functions, types, contracts, deployed state this depends on) and downstream (consumers, tests, CI gates, docs, in-flight PRs depending on this). Concrete file paths + function names in the response or PR body — not in the agent's head. | "Think deeply through chain of dependencies" without a concrete enumeration step is ritual. P14 makes it machine-checkable. |
| P15 | **Snapshot** — State-Snapshot Before Action | Reflexive rule: before any plan, the agent surfaces `git status` + branch + ahead/behind, in-flight PRs (`gh pr list`), Linear ticket state, bookkeeping/bridge freshness, last deploy state. The snapshot is *part of* the planning response — not deferred. | Plans built on stale state fail silently. P15 makes state-checking a cheap reflex, not a request the user has to make. |
| P16 | **Crystallize** — Crystallization Discipline (the Bstack Engine) | Meta-primitive — the loop that produces every other primitive. Pattern recurs ≥3 times across sessions → propose promotion to skill / SKILL.md / AGENTS.md section / `.control/policy.yaml` gate, gated by the four conditions: ≥3 instances, concrete mechanism, stated invariant, stated failure mode. | The crystallization loop must run inside the workspace, not in the user's head. P1–P15 are *outputs* of this loop. |
| P17 | **Lens** — Lens-Routed Request Articulation (`broomva/role-x` skill) | Reflexive rule: every substantive user input passes through `role/x` intake — select lens(es) from `roles/<name>.md` registry by scoring signals, load substantive context, decide mode (`augment` / `rewrite` / `decompose`); P5 fan-out becomes typed graph. | No `act as X` persona rewrites — lenses load substantive context only. Lens selection is logged. Mode decision is surfaced unless `augment`. |
| P18 | **Audience** — Format-Follows-Audience Discipline | Reflexive rule: format follows audience. Agent-readable (LLM, system-prompt loaded, in-repo reference) → **markdown**. Human-readable (decisions, review, exploration) → **HTML**. Both (README, CHANGELOG, GitHub-browseable) → markdown (GitHub renders). ASCII pseudo-diagrams + unicode-color-approximation + >100-line markdown specs without HTML companion are explicit anti-patterns. Specs/plans/ADRs land in `docs/specs/`, `docs/plans/`, `docs/adrs/` as `.html`. | Format follows audience, not habit. Markdown's expressiveness ceiling means humans bounce off agent-produced specs at ~100 lines; HTML's information density carries the load. The 2-4× HTML generation cost is paid only on artifacts a human will actually read. |
| P19 | **Orchestrate** — Orchestration-Mechanism Selection Discipline | At pre-flight of substantive autonomous work, apply the **2×2×2 mechanism cube** (session-scope × trigger-source × agent-count). **N=1 plane:** `/goal <condition>` (internal+in-session), Wait (P9) `p9 watch --background` (external+in-session), `/loop <interval>` (internal+across-session), Persist (P12) `persist iterate PROMPT.md` (external+across-session). **N>1 plane:** Fanout (P5) multi-`Agent` (external+in-session), **`bstack wave dispatch <plan...>`** (external+across-session — worktree per plan, JSONL state). Compose dynamically. | No autonomous-continuation work without explicit mechanism choice + cube-cell citation. "Continue please" / waiting for user prompts mid-arc is ritual and forbidden. |
| P20 | **Cross-Review** — Cross-Model Adversarial Review Gate (`broomva/cross-review` skill) | Before substantive PRs merge, fire cross-model adversarial gate. Three strata: A (true cross-vendor via `codex exec`), B (fresh-context subagent under devil's-advocate brief), C (composed adversarial-review skills — `superpowers:constructive-dissent`, `devils-advocate`, `pr-review-toolkit:*`, `critique`, `premortem`). Anti-slop score ≥7/10; max 3 fix rounds; verdict logged in PR comments + Linear ticket (if workspace uses Linear). Fires *before* P4 auto-merge. | Substantive PRs (>200 LOC OR public API OR multi-file OR governance-class) cannot merge without cross-model verdict ≥7/10. Self-review by the writing model as sole verdict is forbidden. |
> **Naming note.** Skill repo names are stable and don't always match primitive numbers. P6's skill repo is `broomva/bookkeeping` (named for the function). P9's skill repo is `broomva/p9` — name matches primitive number. Renaming any skill repo would break every `npx skills add` install, so when a skill repo carries a number, the primitive numbering commits to keeping it stable.
## Plugin Skill Precedence
Bstack primitives (P1–P19) and bstack-native skills (`/autonomous`, `/shape`, `/persist`, `/ship`, `/bookkeeping`, `/p9`, etc.) **supersede** plugin skills (`superpowers:*`, `pr-review-toolkit:*`, `codex:*`) wherever they conflict. Plugin skills carry no weight when they collide with workspace governance — the `superpowers:using-superpowers` skill itself encodes this priority: *"User's explicit instructions … highest priority. … If CLAUDE.md says X and a skill says Y, follow the user's instructions."*
The most common collision: plugin skills that mandate user interaction before action (notably `superpowers:brainstorming`'s discovery interview, and the meta-rule that prompts the agent to invoke a skill "even if 1% might apply"). The bstack answer is **context-first, user-extract last**:
1. Before any "interview the user" plugin skill fires, perform **Dep-Chain (P14)** + **Snapshot (P15)** over:
- Workspace memory files (auto-memory directory)
- `research/entities/{concept,pattern,tool,person,project}/` — knowledge graph (grep by topic before asking)
- `docs/` (per-project) — architecture, specs, plans, conversations
- Task-mentioned files (CV, spec, ticket body, PR diff)
2. Synthesize what's known from those sources.
3. **Ask the user only for irreducible residuals** — facts that genuinely cannot be derived from disk.
4. If steps 1–2 fully determine the task, the plugin interview is skipped; proceed to execution.
This is a precedence rule, not a new primitive — P14 + P15 already exist; this clarifies that plugin-skill rituals do not override them. The failure mode it shuts down is the "form-fill ritual" — agent asks N+ clarifying questions about facts already curated in the workspace's memory files and knowledge graph.
## Governance Stack
```
CLAUDE.md ← Invariants (you're reading this)
AGENTS.md ← Operational rules + primitive contract
.control/policy.yaml ← Setpoints, gates, profiles (machine-readable)
```
## Hooks (Claude Code Integration)
This workspace registers Claude Code hooks in `.claude/settings.json`:
| Event | Hook | Purpose |
|-------|------|---------|
| `Stop` | `conversation-bridge-hook.sh` | Bridge (P1) — capture session to knowledge graph |
| `Notification` | `conversation-bridge-hook.sh` | Bridge (P1) — backup trigger for bridge |
| `PreToolUse` | `control-gate-hook.sh` | Gate (P2) — enforce safety shields |
| `SessionStart` | `skill-freshness-hook.sh` | Freshness (P7) — nudge user when skills are stale |
## Testing & Verification
```bash
bstack doctor # Verify primitive contract compliance
bstack repair # Fix specific gaps
bstack status --aggregate # Federation rollup across registered workspaces (≥ 0.18.0)
make control-audit # Full metalayer compliance audit
make janitor # Janitor (P8) dry-run
```
> **Federation (Phase 8, v0.18.0).** `bstack workspace` maintains an opt-in
> host-level registry at `~/.broomva/global/registry.yaml`. It is a substrate
> surface, not a new primitive — composes Snapshot (P15) + multi-layer
> composite-ω (v0.16.0 §19). Doctor §20 surfaces registry health.
## Conventions
- **Git**: feature branches, squash merge via PR. Never force push main.
- **Each project** in this workspace can have its own CLAUDE.md with project-specific context.
## Self-Documenting Standards
When modifying skills, architecture docs, or governance files:
1. **Threshold consistency**: A scoring cutoff, layer count, or primitive count changed in one file must be updated in ALL files that reference it. `SKILL.md` is the authoritative source; other files defer to it.
2. **Cross-reference integrity**: Adding a new entity type, status value, or pipeline stage requires updating both the schema/rubric AND the template files that use them.
3. **Primitive count**: Adding a primitive (P-N+1) requires bumping the count in this file's "Bstack Core Automation Primitives" header, adding the table row here, adding the section in `AGENTS.md`, and updating the composition-loop diagram. Run `bstack doctor` after changes to verify lockstep.
4. **Verification**: After modifying this file or any skill, run `bstack doctor` to confirm consistency.
These rules are enforced by agent reasoning + `bstack doctor`, not hooks. The agent reads them and applies them; the doctor surfaces gaps.
name: L3 stability gate
# bstack Gate G2 — RCS stability + governance rate enforcement on PRs.
# Installed by bstack/scripts/install-l3-stability.sh into
# .github/workflows/l3-stability.yml.
#
# Triggers on PRs touching L3-class paths (CLAUDE.md, AGENTS.md,
# .control/policy.yaml, .control/rcs-parameters.toml, METALAYER.md).
# Comments on the PR with per-level lambda + drift + rate-gate status.
# Status check `L3 stability gate / stability-check` can be made required via
# branch protection rules to block merges when lambda <= 0.
on:
pull_request:
branches: [main]
paths:
- 'CLAUDE.md'
- 'AGENTS.md'
- '.control/policy.yaml'
- '.control/rcs-parameters.toml'
- 'METALAYER.md'
jobs:
stability-check:
name: stability-check
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout PR head
uses: actions/checkout@v4
with:
fetch-depth: 50
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install bstack (skill snapshot)
run: |
# Resolve bstack — for repos that have it vendored or use the GitHub fetch.
if [ -d ".agents/skills/bstack" ]; then
BSTACK=".agents/skills/bstack"
else
git clone --depth 1 https://github.com/broomva/bstack.git /tmp/bstack
BSTACK=/tmp/bstack
fi
echo "BSTACK=$BSTACK" >> $GITHUB_ENV
- name: Compute lambda (RCS stability budget)
id: compute
run: |
set +e
out=$(bash $BSTACK/scripts/compute-lambda.sh --human)
status=$?
echo "$out"
{
echo "result<<EOF"
echo "$out"
echo "EOF"
echo "status=$status"
} >> $GITHUB_OUTPUT
# Always continue so the comment step runs; final exit is below
exit 0
- name: Run L3 rate gate
id: rate
run: |
set +e
out=$(BROOMVA_WORKSPACE="$PWD" bash $BSTACK/scripts/l3-rate-gate.sh)
status=$?
echo "$out"
{
echo "result<<EOF"
echo "$out"
echo "EOF"
echo "status=$status"
} >> $GITHUB_OUTPUT
exit 0
- name: Comment on PR
if: github.event.pull_request != null
uses: actions/github-script@v7
with:
script: |
const compute = `${{ steps.compute.outputs.result }}`;
const rate = `${{ steps.rate.outputs.result }}`;
const computeStatus = `${{ steps.compute.outputs.status }}`;
const rateStatus = `${{ steps.rate.outputs.status }}`;
const verdict =
computeStatus !== "0"
? "🔴 **lambda_i <= 0** — composite system unstable; do not merge"
: rateStatus !== "0"
? "🟡 **L3 rate exceeded** — RCS stability budget assumes <= 1 governance commit per tau_a_3 window"
: "🟢 **All gates pass** — composite stable, rate within budget";
const body = [
"## L3 stability gate report",
"",
verdict,
"",
"### Per-level lambda (compute-lambda.sh)",
"```",
compute,
"```",
"",
"### L3 rate gate (l3-rate-gate.sh)",
"```",
rate,
"```",
"",
"<sub>bstack Gate G2 — see `.github/workflows/l3-stability.yml`. RCS background: https://github.com/broomva/bstack/blob/main/references/primitives.md</sub>",
].join("\n");
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body
});
- name: Set final status
run: |
# Fail the check if lambda <= 0 (unstable) — this is the gate.
# L3 rate exceeded is informational (passes here; pre-commit blocks locally).
if [ "${{ steps.compute.outputs.status }}" != "0" ]; then
echo "FAIL: lambda_i <= 0; composite unstable"
exit 1
fi
echo "OK: all lambda_i > 0"
#!/usr/bin/env bash
# .githooks/pre-commit — bstack L3 rate gate (Gate G1).
#
# Installed by bstack/scripts/install-l3-stability.sh. Fires on every
# `git commit` and blocks if the L3 mutation rate exceeds the RCS stability
# budget (tau_a_3 from .control/rcs-parameters.toml, default 86400s = 1 day).
#
# Bypass with: git commit --no-verify (document why in the commit body)
#
# Composes with other pre-commit hooks: if a .githooks/pre-commit existed
# before bstack onboarding, install-l3-stability.sh chains it via the
# .githooks/pre-commit.local sidecar.
set -uo pipefail
# Try to locate the workspace's bstack scripts
WORKSPACE="$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")"
BSTACK_REPO=""
for candidate in \
"$HOME/.agents/skills/bstack" \
"$HOME/.claude/skills/bstack" \
"$WORKSPACE/.agents/skills/bstack" \
"$HOME/broomva/bstack" \
; do
if [ -x "$candidate/scripts/l3-rate-gate.sh" ]; then
BSTACK_REPO="$candidate"
break
fi
done
if [ -z "$BSTACK_REPO" ]; then
# bstack not findable — degrade gracefully (warn but don't block)
echo "[L3 gate] warn: bstack scripts not found; skipping rate check" >&2
# Fall through to .local chain if present
else
# Run the rate gate against staged + last-tau_a window
if ! BROOMVA_WORKSPACE="$WORKSPACE" bash "$BSTACK_REPO/scripts/l3-rate-gate.sh" --staged; then
echo "" >&2
echo "[L3 gate] commit blocked by RCS stability budget" >&2
echo "[L3 gate] override with: git commit --no-verify (document reason in body)" >&2
exit 1
fi
fi
# Chain to user's pre-commit.local if present
if [ -x "$WORKSPACE/.githooks/pre-commit.local" ]; then
"$WORKSPACE/.githooks/pre-commit.local" "$@"
fi
exit 0
# {{WORKSPACE_NAME}} — Control Metalayer
Behavioral governance manifest for the {{WORKSPACE_NAME}} workspace. This file is scaffolded by `bstack bootstrap` and is the authoritative declaration of the workspace's control plant, controller, safety shields, and feedback loop.
## Plant
The **plant** is this workspace — the composition of repos / apps / services that bstack governs. The plant's measurable signals are declared as setpoints S1-S15 in `.control/policy.yaml` and measured by `scripts/metrics/measure-S<n>.sh` shipped by bstack (≥ v0.4.0).
| Signal | Source | Type | Primitive |
|---|---|---|---|
| Git status across repos | `make status` (workspace-defined) | measured | — |
| CI/CD check results | GitHub Actions + provider-specific | measured | P4 (Pipeline) |
| Conversation bridge health | `~/.cache/broomva-bridge-stamp` mtime | measured | P1 (Bridge) |
| Skills installed | union of `~/.agents/skills/` + `~/.claude/skills/` | measured | — (S10) |
| Governance files present | `CLAUDE.md` + `AGENTS.md` + `METALAYER.md` + `.control/policy.yaml` + `schemas/` | measured | — (S11) |
| Hooks wired | `.claude/settings.json` (Stop + PreToolUse + UserPromptSubmit) + `.git/hooks/pre-commit` | measured | P1 + P2 + P17 (S12) |
| Control gate enforcement | `.control/policy.yaml` active gates G1-G11 | measured | P2 (Gate) |
| Workspace-specific signals | (extend this table per workspace) | — | — |
## Controller
Agents operating in this workspace follow the policy in `.control/policy.yaml` (default `profile: governed`).
**Decision flow per session:**
1. Read `CLAUDE.md` + `AGENTS.md` for workspace invariants
2. Read `.control/policy.yaml` for active gates + setpoints
3. Check `docs/conversations/` for prior session context on branch/topic
4. Apply reflexive primitives (P10 Hygiene, P11 Empirical, P14 Dep-Chain, P15 Snapshot, P18 Audience, P19 Orchestrate) before substantive work
5. Execute within harness gates (G1-G4 hard gates enforced by `control-gate-hook.sh`)
6. Create PRs as checkpoints — never merge with failing CI (P4 Pipeline)
## Safety Shields
Hard gates (G1-G4+) enforced by `control-gate-hook.sh` on every Bash/Write/Edit tool call. The full list lives in `.control/policy.yaml` `gates.hard` — at minimum:
| Gate | Rule | Severity |
|---|---|---|
| G1 | No force-push to protected branches | blocking |
| G2 | No `git reset --hard` without backup branch | blocking |
| G3 | No `rm -rf` on home / root / protected paths | blocking |
| G4 | No staging `.env`, credentials, secrets | blocking |
Soft gates (G5-G10+) are advisory — agent guidance only. Extend in `.control/policy.yaml` `gates.soft` as workspace needs emerge.
## Estimator
Agent confidence is derived from:
- **Code context**: files read, git history checked
- **Conversation history**: prior sessions on same branch/topic (via P1 Bridge captures)
- **Knowledge graph**: entity pages in `research/entities/` (via P6 Bookkeeping)
- **CI signals**: test pass rate, build status (via P4 Pipeline + P9 Wait)
- **Setpoint state**: current measurements via `bstack status` (≥ v0.5.0)
## Feedback Loop
```
Session start
→ SessionStart hooks fire (autoupdate, freshness, role-x coverage)
→ Agent loads CLAUDE.md + AGENTS.md + policy.yaml
→ Check docs/conversations/ for prior context
Task execution
→ Apply reflexive primitives (P10/P11/P14/P15/P18/P19)
→ PreToolUse hook gates every Bash/Write/Edit against policy.yaml
→ P9 watcher monitors CI in background after push
Checkpoint
→ PR opens (P3 Tickets + P4 Pipeline)
→ CI runs → P20 Cross-Review if substantive
→ Auto-merge when green per policy.yaml.auto_merge
Post-merge
→ release.yml auto-tag + GH release (if VERSION changed)
→ P8 janitor cleans worktree + branch
→ Stop hook captures session to docs/conversations/ (P1 Bridge)
Observation update
→ P6 Bookkeeping scores raw extracts → promotes to research/entities/
→ Patterns recurring ≥3 times → P16 Crystallize candidate
→ Eventually: new primitive promoted to substrate (rule-of-three)
```
## RCS Hierarchy (reference)
The substrate operates under the Recursive Controlled Systems (RCS) hierarchy with measured stability margins:
| Level | System | Controller Π | Time scale |
|---|---|---|---|
| L0 | External plant (codebase, deploy targets) | per-tool gate enforcement | seconds |
| L1 | Agent internal (per-turn state) | reflexive primitives (P10-P20) | per-turn |
| L2 | Meta-control (CI/CD, EGRI) | release pipeline + PR validation | minutes-days |
| L3 | Governance (this metalayer) | CLAUDE.md + AGENTS.md + policy.yaml | days-weeks |
**L3 has the narrowest stability margin** (λ₃ ≈ 0.006 measured in the reference Broomva workspace). Governance changes must be rare and deliberate — rule-of-three promotion gate.
For the formal framework + canonical parameters, see the [RCS paper repo](https://github.com/broomva/bstack/tree/main/specs/) and `research/rcs/data/parameters.toml` if your workspace ships the RCS substrate.
## Harness Commands
```bash
bstack doctor # Validate primitive contract + governance file presence
bstack metrics collect # Compute every setpoint (≥ 0.4.0)
bstack status # Render substrate health summary (≥ 0.5.0)
bstack repair # Idempotent fix for gaps (governance files, hooks, policy blocks)
bstack upgrade # Pull latest bstack release into this install
make janitor # P8 — branch + worktree cleanup (if workspace defines)
```
## Schemas
The substrate ships JSON Schemas for declarative surfaces in `schemas/`:
- `policy.v1.json` — full `.control/policy.yaml` shape
- `setpoint.v1.json` — single setpoint
- `gate.v1.json` — single gate
- `primitives.v1.json` — primitive registry shape
Schemas v1 are stable from bstack v1.0.0 onwards (currently pre-1.0, additive changes only). Breaking changes ship a v2 schema + migration via `scripts/migrate.sh`.
## Customization
Workspaces extend this template by:
1. Adding workspace-specific signals to the Plant table
2. Defining additional gates in `.control/policy.yaml` `gates.hard` / `gates.soft`
3. Adding workspace-specific harness commands to the Harness Commands section
4. Documenting workspace-specific RCS instantiation in the RCS section (if applicable)
The bstack-shipped sections (Controller, Safety Shields, Estimator, Feedback Loop, Schemas) are stable and should not be modified directly — they're the substrate contract.
# Agentic Control Kernel — bstack workspace policy
# Installed by `bstack bootstrap` when .control/policy.yaml is absent.
# Customize for your workspace; bstack doctor will validate required blocks.
version: "1.0"
profile: governed # baseline | governed | autonomous
setpoints:
- id: S1
name: "gate_pass_rate"
target: 0.85
alert_below: 0.70
severity: blocking
- id: S2
name: "audit_pass_rate"
target: 1.0
alert_below: 0.95
severity: blocking
gates:
governed:
- id: G1
rule: "No force-push to protected branches"
severity: blocking
- id: G2
rule: "No `git reset --hard` without backup branch"
severity: blocking
- id: G3
rule: "No `rm -rf` on protected paths"
severity: blocking
- id: G4
rule: "No staging .env, credentials, secrets"
severity: blocking
- id: G5
rule: "Verify tests pass before push"
severity: warn
- id: G6
rule: "Run smoke before commit"
severity: warn
# === P9 CI Watcher + Productive-Wait Primitive ===
# Required by skills/p9 (bstack P9 primitive — name matches number). Fails closed if absent.
ci_watch:
enabled: true
max_concurrent_prs: 1
isolation_tier_map:
research: none
docs: none
code_independent: worktree
code_dependent: stacked_branch
governance: blocked
ci_heal:
enabled: true
max_attempts: 5
stability_floor: 0.3
classified_failure_types: [lint, format, test_flaky, codegen_drift, import_missing]
escalation_channel:
linear_team: BRO
linear_label: ci-heal-escalation
notify_hook: skills/p9/scripts/p9-escalate-notify.sh
# === P9 Auto-merge actuator ===
# Closes the MERGE_READY → merged gap. Default-disabled; opt-in branch class.
auto_merge:
enabled: false
require_no_requested_changes: true
require_branch_up_to_date: true
merge_method: squash
delete_branch: true
rules:
# Governance paths ALWAYS block (matcher pre-pass enforces this regardless
# of rule order; listing them first protects against future reshuffles)
- path_touched: CLAUDE.md
action: require_human
- path_touched: AGENTS.md
action: require_human
- path_touched: METALAYER.md
action: require_human
- path_touched: .control/policy.yaml
action: require_human
# === Indirect-prompt-injection defense — editor-config paths (2026-05-15) ===
# Spec: specs/2026-05-15-indirect-prompt-injection-defense.md §4 Tier 1.
# Rationale: every documented incident in 2024-2026 that turned indirect prompt
# injection into RCE pivoted through a silent write to one of these paths:
# - .vscode/tasks.json + .vscode/settings.json (CVE-2025-53773 Copilot YOLO-Mode;
# blockchain-C2 gist 2026-05-06)
# - .cursor/mcp.json (CurXecute CVE-2025-54135; MCPoison
# CVE-2025-54136)
# - .claude/settings.json (Claudy Day Claude.ai exfil)
# - .gitignore (removal) (blockchain-C2 gist stage 5)
- path_touched: .vscode/*
action: require_human
- path_touched: .cursor/*
action: require_human
- path_touched: .idea/*
action: require_human
- path_touched: .continue/*
action: require_human
- path_touched: .aider/*
action: require_human
- path_touched: .claude/settings.json
action: require_human
- path_touched: .gitignore
action: require_human
# Auto-merge classes (uncomment to enable per branch pattern)
# - branch_pattern: "docs/*"
# action: auto
# - branch_pattern: "research/*"
# action: auto
default_action: notify
# === Indirect-prompt-injection defense — PreToolUse write gate (2026-05-15) ===
# Spec: specs/2026-05-15-indirect-prompt-injection-defense.md §4 Tier 1.
# Consumed by ~/broomva/scripts/check-file-write-safety.py (workspace-side, ships
# as PR #2 against broomva/workspace). This block defines the schema; the runtime
# is a separate concern. Schema lands first so the runtime can pin to a stable
# contract.
#
# Three sub-blocks:
# write_gate.content_patterns: regex refusal on dangerous content substrings.
# write_gate.magic_bytes_check: refuses files whose extension claims one type but
# whose magic bytes are script/executable.
# write_gate.gitignore_modification: refuses .gitignore edits that REMOVE patterns
# (additions are normal; removals enable silent
# commits of malicious files).
#
# Default state: enabled. Override per-workspace by setting
# write_gate.enabled: false in .control/policy.yaml — but the bstack-doctor
# command will warn loudly when this is off.
write_gate:
enabled: true
content_patterns:
# Each pattern is a Python `re` regex matched against the file content being
# written or edited. severity=blocking refuses the write with exit code 8
# (analogue to the marketing-shape detector in broomva/social-intelligence
# PR #2 — same refuse-to-send substrate pattern). severity=warn logs but
# allows.
- pattern: "runOn:\\s*folderOpen"
severity: blocking
rationale: "VS Code autoexec primitive. Universal trigger across Jamf Threat Labs Dec 2025 North Korea campaign, Tenable/ThreatLocker advisories, mihai-r-lupu blockchain-C2 gist 2026-05-06. https://github.com/microsoft/vscode/issues/309406"
- pattern: "task\\.allowAutomaticTasks:\\s*true"
severity: blocking
rationale: "VS Code autoexec-bypass key — blockchain-C2 gist used this exact setting to skip the 'Do you want to allow automatic tasks?' confirmation"
- pattern: "chat\\.tools\\.autoApprove:\\s*true"
severity: blocking
rationale: "GitHub Copilot YOLO-Mode (CVE-2025-53773, CVSS 7.8) — prompt injection writes this exact key to .vscode/settings.json then shell-exec auto-approves"
- pattern: "--dangerously-skip-permissions"
severity: blocking
rationale: "Claude Code unsafe-flag bypass — used by Nx s1ngularity (CISA-advisory) postinstall scripts to weaponize AI CLIs as recon"
- pattern: "api\\.trongrid\\.io|fullnode\\.mainnet\\.aptoslabs|bsc-dataseed\\.binance|bsc-rpc\\.publicnode"
severity: blocking
rationale: "Public-blockchain RPCs in non-blockchain code = dead-drop C2 signal (blockchain-C2 gist used TRON for XOR key + Aptos + BSC fallback)"
- pattern: "child_process\\.spawn\\([^)]*detached:\\s*true"
severity: warn
rationale: "Detached spawn in JS/TS = persistence primitive (blockchain-C2 gist Layer 4 used this to keep payload alive after parent exits)"
magic_bytes_check:
enabled: true
# Maps a forbidden file-extension family to a list of magic-byte / start-of-content
# signatures that MUST NOT appear at the file head. Catches the font-file-with-JS
# disguise from the blockchain-C2 gist (stage 4).
#
# Signatures are matched against the first 256 bytes of content (utf-8 decoded for
# text-style sigs; raw bytes for binary sigs). String signatures match literally.
rules:
- extension_match: [".woff2", ".woff", ".ttf", ".otf", ".eot"]
forbid_signatures_starting_with:
- "function"
- "(function"
- "const "
- "var "
- "let "
- "import "
- "module.exports"
- "#!/"
rationale: "Font file with script content = blockchain-C2 stage 4 (fa-solid-400.woff2 disguise)"
- extension_match: [".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".bmp", ".ico"]
forbid_signatures_starting_with:
- "function"
- "(function"
- "<?php"
- "<script"
- "#!/"
rationale: "Image file with script content = steganography/disguise class"
- extension_match: [".txt", ".md", ".json", ".yaml", ".yml", ".toml", ".ini"]
forbid_signatures_starting_with:
- "MZ"
- "\\x7fELF"
- "\\xca\\xfe\\xba\\xbe"
- "\\xfe\\xed\\xfa"
rationale: "Text/config file with PE/ELF/Mach-O magic = binary disguise class"
gitignore_modification:
enabled: true
removed_patterns_require_human: true
# Modifications that ADD patterns to .gitignore are normal and unaffected.
# Modifications that REMOVE patterns trigger require_human because removing
# e.g. `.vscode/*` from .gitignore enables silent commit of attacker-injected
# editor config (blockchain-C2 gist stage 5).
rationale: "blockchain-C2 gist (mihai-r-lupu 2026-05-06) explicitly removed .vscode/* from .gitignore to enable committing the malicious tasks.json"
# =============================================================================
# RCS — Workspace Stability Parameters (bstack default)
# =============================================================================
#
# Per-level parameters for the Recursive Controlled Systems (RCS) stability
# budget. These values are read by bstack/scripts/compute-lambda.sh and by
# bstack doctor §14 to verify the composite system is exponentially stable.
#
# Formula (papers/p0-foundations/main.tex, Theorem 1):
#
# lambda_i = gamma_i
# - L_theta_i * rho_i (adaptation cost)
# - L_d_i * eta_i (design evolution cost)
# - beta_i * tau_bar_i (delay cost)
# - ln(nu_i) / tau_a_i (switching cost)
#
# A level is stable iff lambda_i > 0. The composite hierarchy is exponentially
# stable iff every level is individually stable.
#
# Defaults below are calibrated from broomva's Life runtime (research/rcs/
# data/parameters.toml). For a generic bstack repo without Life, customize:
# - L0 (plant): match your runtime's inner loop (sub-second tool execution)
# - L1 (autonomic): match your agent's hysteresis / mode-transition layer
# - L2 (meta-control): match your EGRI / promotion cadence (default: hours)
# - L3 (governance): KEEP CONSERVATIVE — tau_a = 86400s (1 day) is the
# stability budget's load-bearing assumption. Faster governance churn
# destabilizes the whole hierarchy.
#
# Editing rules:
# - Bump schema_version below when adding/removing fields.
# - bstack doctor --strict verifies the cached [derived.lambda] block
# matches recomputed values; CI will fail if they drift.
# - Run `bash scripts/compute-lambda.sh --human` after edits to see the
# per-level impact before committing.
schema_version = 1
# -----------------------------------------------------------------------------
# L0 — Plant (agent inner loop)
# -----------------------------------------------------------------------------
# Sub-second timescale: tool execution, streaming output, immediate response.
# Source: Arcan agent loop default (or your equivalent).
[[levels]]
id = "L0"
name = "plant"
system = "Agent loop / tool execution"
gamma = 2.0
L_theta = 0.3
rho = 0.5
L_d = 0.1
eta = 0.2
beta = 1.0
tau_bar = 0.01
nu = 1.2
tau_a = 0.5
display_digits = 3
# -----------------------------------------------------------------------------
# L1 — Autonomic (per-session reasoning + hysteresis)
# -----------------------------------------------------------------------------
# Seconds timescale: hysteresis gates, mode transitions, validation backpressure.
[[levels]]
id = "L1"
name = "autonomic"
system = "Agent reasoning / per-session loop"
gamma = 0.5
L_theta = 0.2
rho = 0.1
L_d = 0.1
eta = 0.05
beta = 0.5
tau_bar = 0.1
nu = 1.5
tau_a = 30.0
display_digits = 3
# -----------------------------------------------------------------------------
# L2 — EGRI / meta-control
# -----------------------------------------------------------------------------
# Hours timescale: cross-session synthesis, candidate promotion, evaluator runs.
[[levels]]
id = "L2"
name = "EGRI"
system = "EGRI / Crystallize (P16) / Bookkeeping (P6)"
gamma = 0.1
L_theta = 0.05
rho = 0.01
L_d = 0.02
eta = 0.01
beta = 0.0005
tau_bar = 60.0
nu = 1.1
tau_a = 3600.0
display_digits = 3
# -----------------------------------------------------------------------------
# L3 — Governance
# -----------------------------------------------------------------------------
# Days timescale: CLAUDE.md / AGENTS.md / .control/policy.yaml mutations.
#
# CRITICAL: tau_a = 86400s (1 day) is the load-bearing assumption. Faster
# governance churn destabilizes the entire RCS hierarchy. The bstack pre-commit
# hook (`githook-pre-commit-l3-rate.sh`) enforces this rate by counting L3-class
# commits in the last tau_a window.
[[levels]]
id = "L3"
name = "governance"
system = "CLAUDE.md + AGENTS.md + .control/policy.yaml"
gamma = 0.01
L_theta = 0.001
rho = 0.001
L_d = 0.001
eta = 0.0005
beta = 0.000001
tau_bar = 3600.0
nu = 1.05
tau_a = 86400.0
display_digits = 4
# -----------------------------------------------------------------------------
# Derived values — cached for human readers, verified by compute-lambda.sh
# -----------------------------------------------------------------------------
# scripts/compute-lambda.sh --strict recomputes these and fails if drift > 1e-4.
[derived.lambda]
L0 = 1.455357
L1 = 0.411484
L2 = 0.069274
L3 = 0.006398
[derived.omega]
value = 0.006398
level = "L3"
# -----------------------------------------------------------------------------
# Governance path patterns (read by l3-rate-gate.sh)
# -----------------------------------------------------------------------------
# Files that match these git-pathspec patterns count as L3 mutations.
# Used by:
# - .githooks/pre-commit (pre-commit gate G1)
# - .github/workflows/l3-stability.yml (CI gate G2)
# - .claude/settings.json PreToolUse hook (Claude Code gate G0)
[gates.l3_paths]
patterns = [
"CLAUDE.md",
"AGENTS.md",
".control/policy.yaml",
".control/rcs-parameters.toml",
"METALAYER.md",
]
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Agentic Control Kernel — Action Schema",
"description": "Typed control directive (θ_t) emitted by the LLM agent. Not raw actuation — parameterizes deterministic controllers.",
"type": "object",
"required": ["directive_id", "timestamp", "directive_type"],
"properties": {
"directive_id": {
"type": "string",
"description": "Unique identifier for this control directive"
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 timestamp of directive emission"
},
"directive_type": {
"type": "string",
"enum": [
"setpoint_update",
"constraint_update",
"mode_switch",
"parameter_update",
"module_selection",
"experiment_request",
"model_update_trigger",
"plan_update"
],
"description": "Type of control directive"
},
"target_controller": {
"type": "string",
"description": "Which controller module this directive targets"
},
"payload": {
"type": "object",
"description": "Directive-specific payload (setpoints, parameters, etc.)",
"additionalProperties": true
},
"rationale": {
"type": "string",
"description": "LLM's reasoning for this directive (for audit/ledger)"
},
"priority": {
"type": "string",
"enum": ["critical", "high", "normal", "low"],
"default": "normal",
"description": "Execution priority"
},
"requires_approval": {
"type": "boolean",
"default": false,
"description": "Whether this directive needs human approval before execution"
},
"rollback_directive_id": {
"type": ["string", "null"],
"description": "Directive to execute if this one needs to be rolled back"
},
"budget_impact": {
"type": "object",
"description": "Estimated resource consumption",
"properties": {
"tokens": { "type": "integer" },
"compute_s": { "type": "number" },
"cost_usd": { "type": "number" }
}
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://broomva.tech/schemas/egri-event.schema.json",
"title": "EGRI Trial Event",
"description": "Payload for autoany EGRI trial records persisted to Lago via EventKind::Custom with 'egri.' prefix",
"type": "object",
"required": ["event_type", "trial"],
"properties": {
"event_type": {
"type": "string",
"pattern": "^egri\\.",
"description": "Event type with 'egri.' prefix, e.g. 'egri.trial'"
},
"trial": {
"$ref": "#/$defs/TrialRecord"
},
"session_id": {
"type": ["string", "null"],
"description": "Optional Arcan session ID for cross-reference"
}
},
"$defs": {
"TrialRecord": {
"type": "object",
"required": ["trial_id", "timestamp", "parent_state", "mutation", "outcome", "decision"],
"properties": {
"trial_id": { "type": "string" },
"timestamp": { "type": "string", "format": "date-time" },
"parent_state": { "type": "string" },
"mutation": { "$ref": "#/$defs/Mutation" },
"execution": { "$ref": "#/$defs/ExecutionResult" },
"outcome": { "$ref": "#/$defs/Outcome" },
"decision": { "$ref": "#/$defs/Decision" },
"strategy_notes": { "type": ["string", "null"] }
}
},
"Mutation": {
"type": "object",
"required": ["operator", "description"],
"properties": {
"operator": { "type": "string" },
"description": { "type": "string" },
"diff": { "type": ["string", "null"] },
"hypothesis": { "type": ["string", "null"] }
}
},
"ExecutionResult": {
"type": ["object", "null"],
"properties": {
"duration_secs": { "type": "number" },
"exit_code": { "type": "integer" },
"error": { "type": ["string", "null"] },
"output": {}
}
},
"Outcome": {
"type": "object",
"required": ["score", "constraints_passed"],
"properties": {
"score": {},
"constraints_passed": { "type": "boolean" },
"constraint_violations": { "type": "array", "items": { "type": "string" } },
"evaluator_metadata": {}
}
},
"Decision": {
"type": "object",
"required": ["action", "reason"],
"properties": {
"action": { "type": "string", "enum": ["promoted", "discarded", "branched", "escalated"] },
"reason": { "type": "string" },
"new_state_id": { "type": ["string", "null"] }
}
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Agentic Control Kernel — Evaluator Schema",
"description": "Score vectors and promotion decisions for EGRI-compatible evaluators.",
"type": "object",
"required": ["evaluator_id", "timestamp", "scores", "decision"],
"properties": {
"evaluator_id": {
"type": "string",
"description": "Identifier of the evaluator instance"
},
"timestamp": {
"type": "string",
"format": "date-time"
},
"trial_id": {
"type": "string",
"description": "EGRI trial being evaluated"
},
"controller_version": {
"type": "string",
"description": "Controller version under evaluation"
},
"scores": {
"type": "object",
"description": "Score vector — scalar or multi-dimensional metrics",
"properties": {
"primary": {
"type": "number",
"description": "Primary objective score (the one driving promotion)"
},
"secondary": {
"type": "object",
"description": "Additional metrics tracked but not driving promotion",
"additionalProperties": { "type": "number" }
}
},
"required": ["primary"]
},
"baseline": {
"type": "object",
"description": "Baseline scores for comparison",
"properties": {
"primary": { "type": "number" },
"secondary": {
"type": "object",
"additionalProperties": { "type": "number" }
}
}
},
"constraints": {
"type": "object",
"required": ["all_passed"],
"properties": {
"all_passed": {
"type": "boolean",
"description": "Whether all hard constraints were satisfied"
},
"violations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"constraint_id": { "type": "string" },
"measured": { "description": "Measured value" },
"threshold": { "description": "Threshold that was violated" },
"severity": {
"type": "string",
"enum": ["hard", "soft"]
}
}
}
}
}
},
"decision": {
"type": "object",
"required": ["action"],
"properties": {
"action": {
"type": "string",
"enum": ["promoted", "discarded", "branched", "escalated"],
"description": "Promotion decision"
},
"reason": {
"type": "string",
"description": "Why this decision was made"
},
"new_controller_version": {
"type": ["string", "null"],
"description": "Version ID of promoted controller (null if discarded)"
},
"rollback_target": {
"type": ["string", "null"],
"description": "Version to rollback to if this promotion fails in deployment"
}
}
},
"scenario_coverage": {
"type": "object",
"description": "Which scenarios were evaluated",
"properties": {
"total_scenarios": { "type": "integer" },
"passed": { "type": "integer" },
"failed": { "type": "integer" },
"holdout_passed": {
"type": "integer",
"description": "Anti-gaming holdout scenarios passed"
},
"holdout_total": { "type": "integer" }
}
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Agentic Control Kernel — State Schema",
"description": "Typed plant/belief state for agentic control systems. Separates measured, estimated, and context fields.",
"type": "object",
"required": ["timestamp", "observation_id", "measured"],
"properties": {
"timestamp": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 timestamp of observation"
},
"observation_id": {
"type": "string",
"description": "Unique identifier for this observation"
},
"plant_id": {
"type": "string",
"description": "Identifier of the plant being observed"
},
"measured": {
"type": "object",
"description": "Directly measured signals from the plant (sensors, metrics, CI results)",
"additionalProperties": {
"type": "object",
"required": ["value"],
"properties": {
"value": {
"description": "Measured value (number, string, boolean, or array)"
},
"unit": {
"type": "string",
"description": "Unit of measurement (e.g., 'ms', 'percent', 'count')"
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Confidence in measurement (1.0 = ground truth)"
}
}
}
},
"estimated": {
"type": "object",
"description": "Inferred/estimated signals (model predictions, aggregated metrics)",
"additionalProperties": {
"type": "object",
"required": ["value"],
"properties": {
"value": {
"description": "Estimated value"
},
"uncertainty": {
"type": "number",
"minimum": 0,
"description": "Uncertainty bound on estimate"
},
"estimator": {
"type": "string",
"description": "Name of estimator that produced this value"
}
}
}
},
"context": {
"type": "object",
"description": "Semantic/contextual fields (branch name, user intent, session info)",
"additionalProperties": true
},
"constraints": {
"type": "object",
"description": "Currently active constraints on this plant",
"properties": {
"hard": {
"type": "array",
"items": { "type": "string" },
"description": "Constraints that must never be violated"
},
"soft": {
"type": "array",
"items": { "type": "string" },
"description": "Constraints that should be satisfied but can be relaxed"
}
}
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Agentic Control Kernel — Trace Schema",
"description": "Canonical trace entry for the append-only ledger. Compatible with Autoany EGRI ledger format.",
"type": "object",
"required": ["trace_id", "timestamp", "plant_id", "state_snapshot", "action_proposed", "action_applied", "outcome"],
"properties": {
"trace_id": {
"type": "string",
"description": "Unique identifier for this trace entry"
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 timestamp"
},
"plant_id": {
"type": "string",
"description": "Identifier of the plant"
},
"controller_version": {
"type": "string",
"description": "Version/hash of the active controller configuration"
},
"state_snapshot": {
"type": "object",
"description": "Belief state at decision time (or hash + artifact pointer for large states)",
"properties": {
"hash": { "type": "string" },
"artifact_path": { "type": "string" },
"inline": { "type": "object", "additionalProperties": true }
}
},
"directive": {
"description": "The LLM's control directive θ_t (ref: action.schema.json)",
"type": "object",
"additionalProperties": true
},
"action_proposed": {
"type": "object",
"description": "Controller's proposed action before safety filtering",
"additionalProperties": true
},
"action_applied": {
"type": "object",
"description": "Actual action applied after safety shield filtering",
"additionalProperties": true
},
"shield": {
"type": "object",
"description": "Safety shield results",
"properties": {
"feasible": {
"type": "boolean",
"description": "Whether the shield found a feasible safe action"
},
"modification_magnitude": {
"type": "number",
"description": "||u_safe - u_proposed|| — how much the shield modified the action"
},
"certificate": {
"type": "object",
"description": "Safety certificate proving constraint satisfaction",
"additionalProperties": true
},
"fallback_used": {
"type": "boolean",
"default": false,
"description": "Whether emergency fallback was activated"
}
}
},
"constraints_checked": {
"type": "array",
"items": {
"type": "object",
"required": ["constraint_id", "satisfied"],
"properties": {
"constraint_id": { "type": "string" },
"satisfied": { "type": "boolean" },
"value": { "description": "Measured value for the constraint" },
"threshold": { "description": "Constraint threshold" }
}
}
},
"outcome": {
"type": "object",
"required": ["success"],
"properties": {
"success": {
"type": "boolean",
"description": "Whether the action succeeded"
},
"observation_after": {
"type": "object",
"description": "Plant observation after action",
"additionalProperties": true
},
"error": {
"type": ["string", "null"],
"description": "Error message if action failed"
}
}
},
"evaluator_metrics": {
"type": "object",
"description": "Micro-metrics scored by evaluator for this tick",
"properties": {
"cost": { "type": "number" },
"constraint_violations": { "type": "integer" },
"latency_ms": { "type": "number" },
"robustness_indicator": { "type": "number" }
},
"additionalProperties": true
},
"egri": {
"type": "object",
"description": "EGRI loop context (if this trace is part of an improvement trial)",
"properties": {
"trial_id": { "type": "string" },
"parent_state": { "type": "string" },
"mutation_operator": { "type": "string" },
"decision": {
"type": "string",
"enum": ["promoted", "discarded", "branched", "escalated", "pending"]
}
}
}
}
}
{
"_doc": "bstack L3 stability — Claude Code PreToolUse hook entry (Gate G0). Merged into .claude/settings.json by bstack/scripts/install-l3-stability.sh. Fires on Edit/Write tool calls against L3-class paths and surfaces a warning to the agent reflecting that the edit is consuming stability budget.",
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "$BSTACK_REPO/scripts/l3-stability-pretool-hook.sh",
"_bstack_primitive": "L3-G0"
}
]
}
]
}
}
{
"_doc": "bstack RCS multi-layer audit — Claude Code PostToolUse (L0) + Stop (L1) hook entries. Merged into .claude/settings.json by bstack/scripts/install-rcs-stability.sh. Composes with the existing L3-G0 PreToolUse hook from v0.14.0 (see settings.json.l3-stability-hook.snippet).",
"hooks": {
"PostToolUse": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "$BSTACK_REPO/scripts/l0-tool-audit-hook.sh",
"_bstack_primitive": "L0-audit"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "$BSTACK_REPO/scripts/l1-reflex-audit-hook.sh",
"_bstack_primitive": "L1-audit"
}
]
}
]
}
}
{
"_comment": "bstack-managed hooks — bootstrap merges these into your existing .claude/settings.json. Does NOT overwrite existing entries; only adds missing ones. ${BROOMVA_WORKSPACE} is replaced with the workspace root; ${BROOMVA_HOME} is replaced with $HOME (where npx skills add -g installs).",
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "${BROOMVA_HOME}/.claude/skills/bstack/scripts/bstack-autoupdate-hook.sh",
"timeout": 10,
"_bstack_primitive": "P7"
},
{
"type": "command",
"command": "${BROOMVA_WORKSPACE}/scripts/skill-freshness-hook.sh",
"timeout": 5,
"_bstack_primitive": "P7"
},
{
"type": "command",
"command": "${BROOMVA_HOME}/.agents/skills/role-x/scripts/role-x-coverage-hook.sh",
"timeout": 5,
"_bstack_primitive": "P17"
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "${BROOMVA_HOME}/.agents/skills/role-x/scripts/role-x-intake-hook.sh",
"timeout": 5,
"_bstack_primitive": "P17"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "${BROOMVA_WORKSPACE}/scripts/conversation-bridge-hook.sh",
"timeout": 5,
"_bstack_primitive": "P1"
},
{
"type": "command",
"command": "${BROOMVA_WORKSPACE}/scripts/knowledge-catalog-refresh-hook.sh",
"timeout": 5,
"_bstack_primitive": "P6",
"_purpose": "Regenerate dense LLM-loadable catalog (LLM-as-index architecture; routes /kg load)"
}
]
}
],
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "${BROOMVA_WORKSPACE}/scripts/conversation-bridge-hook.sh",
"timeout": 5,
"_bstack_primitive": "P1"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${BROOMVA_WORKSPACE}/scripts/control-gate-hook.sh",
"timeout": 5,
"_bstack_primitive": "P2"
}
]
},
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "${BROOMVA_WORKSPACE}/scripts/control-gate-hook.sh",
"timeout": 5,
"_bstack_primitive": "P2"
}
]
},
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "${BROOMVA_WORKSPACE}/scripts/control-gate-hook.sh",
"timeout": 5,
"_bstack_primitive": "P2"
}
]
}
]
}
}
#!/usr/bin/env bash
# bstack-bench — skill-evolution benchmark dispatcher (BRO-1205, v0.10.0).
#
# Thin bash wrapper that delegates to scripts/bench/orchestrator.py.
# Mirrors bin/bstack-crystallize's shape (Phase 7).
#
# Subcommands:
# run [--tasks SET] [--runner R] [--evaluator E] [--phase {1|2|both}]
# [--provider P] [--model M] [--judge-model M] [--allow-same-judge-model RATIONALE]
# [--budget-usd N] [--resume RUN_ID] [--no-dry-run]
# Two-phase bench against a task set.
# compare [--run-id RUN_ID] Build REPORT.md from existing phase results.
# tasks list List registered task sets.
# status [--run-id RUN_ID] Summarize recent runs.
# help | --help This message.
#
# Env overrides:
# BSTACK_BENCH_HOME Override default ~/.config/bstack/bench/.
# BSTACK_BENCH_TASKS_DIR Override default scripts/bench/tasks/.
#
# Exit codes (from orchestrator.py):
# 0 success
# 2 invalid arguments
# 3 task set not found
# 4 budget exceeded mid-run (or prior spend already exceeds budget on resume)
# 5 resume / status run-id not found
# 6 all task runs failed (structurally broken — e.g. stub runner without SDK)
# 7 compare requires both phase 1 + phase 2 results
# 8 P20 violation: judge model equals agent model without --allow-same-judge-model
# 9 provider not configured (missing DATABRICKS_TOKEN, etc.)
# 10 provider SDK not installed (e.g. `pip install openai`)
set -euo pipefail
BSTACK_DIR="$(cd "$(dirname "$0")/.." && pwd)"
ORCHESTRATOR="$BSTACK_DIR/scripts/bench/orchestrator.py"
# Pick the best available Python interpreter (3.10+ required for PEP 604
# `|` unions in annotations). Checks PATH first, then falls back to common
# absolute install locations (Homebrew, /usr/local) so the dispatcher works
# in restricted-PATH environments (e.g. CI matrices, agent sandboxes).
pick_python() {
local cand resolved ver
# 1. PATH lookup
for cand in python3.13 python3.12 python3.11 python3.10 python3; do
if command -v "$cand" >/dev/null 2>&1; then
resolved="$(command -v "$cand")"
ver="$("$resolved" -c 'import sys; print(sys.version_info[:2] >= (3,10))' 2>/dev/null || echo False)"
if [ "$ver" = "True" ]; then
echo "$resolved"
return 0
fi
fi
done
# 2. Well-known install locations (Homebrew, /usr/local)
local probe
for probe in \
/opt/homebrew/bin/python3.13 /opt/homebrew/bin/python3.12 \
/opt/homebrew/bin/python3.11 /opt/homebrew/bin/python3.10 \
/usr/local/bin/python3.13 /usr/local/bin/python3.12 \
/usr/local/bin/python3.11 /usr/local/bin/python3.10; do
if [ -x "$probe" ]; then
ver="$("$probe" -c 'import sys; print(sys.version_info[:2] >= (3,10))' 2>/dev/null || echo False)"
if [ "$ver" = "True" ]; then
echo "$probe"
return 0
fi
fi
done
return 1
}
usage() {
cat <<'EOF'
bstack-bench — skill-evolution benchmark dispatcher
Usage:
bstack bench run [--tasks SET] [--runner R] [--evaluator E]
[--provider P] [--model M] [--judge-model M]
[--allow-same-judge-model RATIONALE]
[--phase {1|2|both}] [--budget-usd N]
[--resume RUN_ID] [--no-dry-run]
bstack bench compare [--run-id RUN_ID]
bstack bench tasks list
bstack bench status [--run-id RUN_ID]
bstack bench --help
Defaults:
--tasks bstack-smoke --runner dry-run --evaluator rubric-match
--phase both --dry-run
Live mode (v0.11.0+):
bstack bench run --runner live --evaluator llm-judge \\
--provider databricks \\
--model databricks-claude-haiku-4-5 \\
--judge-model databricks-claude-opus-4-5
# Or, with Railway as credential broker:
railway run --service stimulus-api -- bstack bench run --runner live ...
State:
~/.config/bstack/bench/runs/<run-id>/ (override via BSTACK_BENCH_HOME)
Spec: specs/bench-skill-evolution.md
Providers: references/provider-standards.md
Tickets: BRO-1205 (MVP), BRO-1211 (live mode)
EOF
}
if [ $# -eq 0 ] || [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ] || [ "${1:-}" = "help" ]; then
usage
exit 0
fi
PY="$(pick_python || true)"
if [ -z "$PY" ]; then
echo "bstack-bench: requires Python >= 3.10 (none found in PATH)." >&2
exit 2
fi
if [ ! -f "$ORCHESTRATOR" ]; then
echo "bstack-bench: orchestrator missing at $ORCHESTRATOR" >&2
exit 2
fi
exec "$PY" "$ORCHESTRATOR" "$@"
#!/usr/bin/env bash
# bstack-config — read/write ~/.bstack/config.yaml
#
# Usage:
# bstack-config get <key> — read a config value
# bstack-config set <key> <value> — write a config value
# bstack-config list — show all config
set -euo pipefail
STATE_DIR="${BSTACK_STATE_DIR:-$HOME/.bstack}"
CONFIG_FILE="$STATE_DIR/config.yaml"
case "${1:-}" in
get)
KEY="${2:?Usage: bstack-config get <key>}"
grep -E "^${KEY}:" "$CONFIG_FILE" 2>/dev/null | tail -1 | awk '{print $2}' | tr -d '[:space:]' || true
;;
set)
KEY="${2:?Usage: bstack-config set <key> <value>}"
VALUE="${3:?Usage: bstack-config set <key> <value>}"
mkdir -p "$STATE_DIR"
if grep -qE "^${KEY}:" "$CONFIG_FILE" 2>/dev/null; then
sed -i '' "s/^${KEY}:.*/${KEY}: ${VALUE}/" "$CONFIG_FILE"
else
echo "${KEY}: ${VALUE}" >> "$CONFIG_FILE"
fi
;;
list)
cat "$CONFIG_FILE" 2>/dev/null || true
;;
*)
echo "Usage: bstack-config {get|set|list} [key] [value]"
exit 1
;;
esac
#!/usr/bin/env bash
# bstack-cross-review — P20 cross-model adversarial review for GitHub PRs.
#
# Thin shim that dispatches to scripts/cross-review.py. Mirrors the
# bstack-wave shim pattern. Forwards argv unchanged.
#
# See BRO-1227 — fixes the Cato sub-agent cwd-mismatch failure mode by
# reading PR contents via `gh api …/contents/<path>?ref=<sha>` instead
# of the local working tree.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PY="$SCRIPT_DIR/scripts/cross-review.py"
if [ ! -f "$PY" ]; then
echo "bstack-cross-review: scripts/cross-review.py not found at $PY" >&2
exit 1
fi
exec python3 "$PY" "$@"
0.28.0
Related skills
FAQ
How do I install bstack?
Run npx skills add broomva/bstack, then use /bstack bootstrap in your agent session to install skills, scaffold governance, wire hooks, and run doctor.
What does bstack doctor do?
It verifies primitive contract compliance and always exits 0, surfacing gaps that bstack repair can then fix.