Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ This repository contains the Centaur Layer plugin (ships as both a Codex plugin

## Product Direction

Centaur Layer is the single installable product. It may borrow ideas from `claude-charter` and `software-engineer-agents`, but users should not need to install those projects separately.
Centaur Layer is one of three independent, composable layers: `software-engineer` (the engine — how work gets done, runtime state in `.se/`), `claude-charter` (the constitution — rules and trust boundaries) and Centaur Layer (the brake — did the human understand the diff). Each works fully standalone; none requires the others.

The composition model is **Detect & Defer**: when Centaur detects another layer it defers that concern to it instead of duplicating it, but it never requires the other to be installed. Centaur's role in the ecosystem is to question the human, not the machine.

Keep the product centered on one promise: AI can accelerate coding without weakening the developer's reasoning, review discipline, or ownership of risky decisions.

Expand All @@ -13,7 +15,7 @@ Keep the product centered on one promise: AI can accelerate coding without weake
- Keep the MVP small: contract, check, coach, health.
- Do not add remote telemetry.
- Do not write deliberate defect drills into real project files.
- Treat `.claude/` and `.sea/` as optional integrations.
- Treat `.claude/` and `.se/` as optional integrations.
- Prefer clear skill instructions over custom runtime code until the workflow proves it needs scripts.
- Every new skill should say when it stops, when it asks, and what evidence it reports.

Expand Down
39 changes: 31 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ bash /path/to/centaur-layer/scripts/centaur-init.sh --with-hooks /path/to/target
- `.centaur/metrics.jsonl` — local-only usage log
- `.gitignore` entries for runtime files (`metrics.jsonl`, `session.json`)

It also probes for optional integrations (`.claude/knowledge/charter/`, `.sea/`) and reports whether they were detected. Neither is required.
It also probes for optional integrations (`.claude/knowledge/charter/`, `.se/`) and reports whether they were detected. Neither is required.

Commit the initialization separately from product changes:

Expand Down Expand Up @@ -323,16 +323,39 @@ The script never downgrades risk based on optimism — it only ever escalates wh

---

## Relationship To Other Projects
## Ecosystem: Engine, Constitution, Brake

Centaur Layer is the single product you install. It borrows proven ideas from two companion projects without requiring you to install them separately:
Centaur Layer is one of three independent, composable layers. Each works fully standalone; none requires installing the others.

| Source | What Centaur uses |
|---|---|
| `claude-charter` | layered policy, trust boundaries, guardrails, self-audit |
| `software-engineer-agents` | scoped execution, risk gates, verification discipline, atomic work |
| Layer | Project | Role | Answers |
|---|---|---|---|
| Engine | [`software-engineer`](https://github.com/demwick/software-engineer) (`.se/`) | how work gets done | "execute the work, scoped and verified" |
| Constitution | `claude-charter` (`.claude/`) | what rules & boundaries hold | "is the AI allowed to do this?" |
| Brake | `centaur-layer` (`.centaur/`) | did the human understand | "do *you* understand this diff before accepting it?" |

### Detect & Defer

Each layer is independent and self-sufficient. When one layer detects another, it **defers** that responsibility to it and does not duplicate it — but it never requires the other to be installed. Centaur runs fully on its own; if the engine or charter is present, Centaur reads and respects their state instead of re-implementing their concerns.

Centaur's job in this ecosystem is to **question the human, not the machine.**

### Two moments of risk (no overlap)

- The **engine** warns *forward*, at planning time — before a change is made ("this change looks risky, here's what to watch").
- **Centaur** brakes *at acceptance* — scoring the diff and checking human comprehension at the moment of accept/commit.

Different moments, no collision: the engine warns while planning, Centaur brakes while accepting. Diff-risk scoring and the comprehension check at accept/commit time are Centaur's responsibility.

### Two guardrail surfaces (no duplication)

- **Charter** guards the **PreToolUse** surface — before the AI invokes a tool. It watches the *machine's action*.
- **Centaur** guards the **pre-commit** surface — when a human runs `git commit` on a high-risk diff. It watches the *human's commit*.

If charter is installed, Centaur keeps its own pre-commit hook: a different surface, not a repeat.

### Verification: machine vs human

If a project already has `.claude/` charter files or `.sea/` state, Centaur reads and respects them — but they are optional integrations, not dependencies.
`centaur-check` questions the **human** ("did you understand this?"), never the machine. Charter defines `/verify` and the engine's verifier runs it autonomously — those validate the *code*. Centaur stays separate in every case because its target is different: the human, not the code.

---

Expand Down
16 changes: 5 additions & 11 deletions scripts/centaur-health.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ has_verification_command=0
has_guardrails=0
has_git=0
git_clean=0
has_sea=0
has_se=0

missing=()
signals=()
Expand Down Expand Up @@ -65,13 +65,7 @@ if [ -d ".claude/knowledge/context" ] || [ -d "docs" ] || [ -f "README.md" ]; th
has_context=1
fi

if [ -f "package.json" ] && grep -q '"test"' package.json 2>/dev/null; then
has_verification_command=1
elif [ -f "pyproject.toml" ] || [ -f "pytest.ini" ]; then
has_verification_command=1
elif [ -f "go.mod" ] || [ -f "Cargo.toml" ]; then
has_verification_command=1
elif [ -f "Makefile" ] && grep -qE '^test:' Makefile 2>/dev/null; then
if centaur_has_test_runner "."; then
has_verification_command=1
fi

Expand All @@ -86,8 +80,8 @@ if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
fi
fi

if [ -d ".sea" ]; then
has_sea=1
if [ -d ".se" ]; then
has_se=1
fi

[ "$has_contract" -eq 1 ] && signals+=("contract: present") || missing+=("Run centaur-init to create .centaur/contract.md")
Expand Down Expand Up @@ -120,7 +114,7 @@ else
fi
[ "$has_git" -eq 1 ] && signals+=("git: repository") || missing+=("Initialize git before AI-assisted changes")
[ "$git_clean" -eq 1 ] && signals+=("git_clean: yes") || signals+=("git_clean: no")
[ "$has_sea" -eq 1 ] && signals+=("sea: detected") || signals+=("sea: absent")
[ "$has_se" -eq 1 ] && signals+=("se: detected") || signals+=("se: absent")

score=$((has_contract + valid_contract + has_policy_file + has_centaur_policy + has_context + has_verification_command + has_guardrails + has_git))
status="RISKY"
Expand Down
10 changes: 5 additions & 5 deletions scripts/centaur-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ if [ -d "$TARGET_DIR/.claude/knowledge/charter" ] || [ -d "$TARGET_DIR/.claude"
charter="detected"
fi

sea="absent"
if [ -d "$TARGET_DIR/.sea" ]; then
sea="detected"
se="absent"
if [ -d "$TARGET_DIR/.se" ]; then
se="detected"
fi

printf 'CENTAUR INIT: complete\n'
Expand All @@ -70,7 +70,7 @@ printf 'runtime_readme: %s (%s)\n' "$RUNTIME_README" "$([ "$created_readme" -eq
printf 'policy: %s (%s)\n' "$POLICY" "$([ "$created_policy" -eq 1 ] && printf created || printf preserved)"
printf 'gitignore: %s\n' "$([ "$updated_gitignore" -eq 1 ] && printf updated || printf unchanged)"
printf 'integration.claude_charter: %s\n' "$charter"
printf 'integration.sea: %s\n' "$sea"
printf 'integration.se: %s\n' "$se"
hooks_state="absent"
if [ "$with_hooks" -eq 1 ]; then
if bash "$PLUGIN_ROOT/scripts/centaur-install-hooks.sh" "$TARGET_DIR" >/dev/null 2>&1; then
Expand All @@ -87,7 +87,7 @@ centaur_emit_metric "$TARGET_DIR" "init" \
"contract_created=$created_contract" \
"policy_created=$created_policy" \
"charter=$charter" \
"sea=$sea" \
"se=$se" \
"hooks=$hooks_state"

exit 0
4 changes: 4 additions & 0 deletions scripts/lib/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ centaur_has_test_runner() {
return 0
elif [ -f "$dir/Makefile" ] && grep -qE '^test:' "$dir/Makefile" 2>/dev/null; then
return 0
elif [ -f "$dir/test.sh" ] || [ -f "$dir/run-tests.sh" ]; then
return 0
elif find "$dir" -maxdepth 3 -name '*.bats' -type f -print -quit 2>/dev/null | grep -q .; then
return 0
fi
return 1
}
8 changes: 4 additions & 4 deletions scripts/validate-plugin.sh
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ grep -qF "## Required Behavior" templates/claude.md \
|| fail "CLAUDE.md template missing Required Behavior"
ok "CLAUDE.md template has required sections"

grep -qE "Centaur Layer is the single product (users|you) install" README.md \
|| fail "README must state single-product positioning"
grep -qF "none requires installing the others" README.md \
|| fail "README must state standalone positioning (Detect & Defer independence)"
grep -qiE "opt-in synthetic|synthetic drills only|synthetic-only|defect drills should be opt-in" README.md \
|| fail "README must keep defect drills opt-in"
ok "README product guardrails present"
Expand Down Expand Up @@ -287,7 +287,7 @@ invalid_out="$(bash scripts/centaur-health.sh "$invalid_contract")"
assert_contains "centaur-health detects invalid contract" "$invalid_out" "Restore required sections"

integrated="$(mktemp_repo)"
mkdir -p "$integrated/.claude/knowledge/charter" "$integrated/.claude/hooks" "$integrated/.sea"
mkdir -p "$integrated/.claude/knowledge/charter" "$integrated/.claude/hooks" "$integrated/.se"
printf '# Policy\n' > "$integrated/.claude/knowledge/charter/principles.md"
printf '{"hooks":{}}\n' > "$integrated/.claude/hooks/hooks.json"
bash scripts/centaur-init.sh "$integrated" >/dev/null
Expand All @@ -297,7 +297,7 @@ assert_contains "centaur-init detects real charter integration" "$integration_in
assert_contains "centaur-health detects policy file" "$integration_out" "policy_file: present"
assert_contains "centaur-health detects charter policy" "$integration_out" "charter_policy: detected"
assert_contains "centaur-health detects guardrails" "$integration_out" "guardrails: detected"
assert_contains "centaur-health detects sea" "$integration_out" "sea: detected"
assert_contains "centaur-health detects se" "$integration_out" "se: detected"

drill_out="$(bash scripts/centaur-drill.sh boundary)"
assert_contains "centaur-drill is synthetic" "$drill_out" "mode: synthetic-only"
Expand Down
2 changes: 1 addition & 1 deletion skills/centaur-health/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Then use the script output as the evidence base. The script inspects:
5. Review or verification command signal
6. Dangerous-operation guardrails
7. Git cleanliness
8. Optional SEA state: `.sea/`
8. Optional software-engineer state: `.se/`
9. Centaur policy language in `CLAUDE.md`

## Scoring
Expand Down
2 changes: 1 addition & 1 deletion skills/centaur-init/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Initialize Centaur Layer for the current repository.
## Rules

- Do not overwrite an existing `.centaur/contract.md` without explicit user approval.
- Do not require `claude-charter` or `software-engineer-agents`; treat them as optional integrations.
- Do not require `claude-charter` or `software-engineer`; treat them as optional integrations.
- Keep initialization small. No scaffolding, no dependency installs, no git commits.
- If the repository is dirty, preserve all existing work.
- Commit `.centaur/contract.md`, `.centaur/README.md`, and `CLAUDE.md`; do not commit runtime metrics.
Expand Down
2 changes: 1 addition & 1 deletion templates/runtime-readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ Each line of `metrics.jsonl` is a single JSON object:

Event types: `init`, `check`, `health`, `drill`. Summarize with `centaur-stats`.

Centaur Layer treats `.claude/` and `.sea/` as optional integrations. This directory is the only required Centaur state.
Centaur Layer treats `.claude/` and `.se/` as optional integrations. This directory is the only required Centaur state.
11 changes: 11 additions & 0 deletions tests/bats/check.bats
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@ load helpers/setup.bash
centaur_assert_contains "$output" "dependency change without test command evidence"
}

@test "centaur-check detects bats suite as test runner" {
repo="$(centaur_mktemp_repo)"
mkdir -p "$repo/tests"
printf '@test "ok" { true; }\n' > "$repo/tests/smoke.bats"
printf '# Demo\n' > "$repo/README.md"
centaur_seed_commit "$repo" .
printf '\nMore docs.\n' >> "$repo/README.md"
out="$(centaur_run_script centaur-check.sh "$repo")"
centaur_assert_contains "$out" "test_runner: detected"
}

@test "centaur-check exit code respects CENTAUR_FAIL_ON=none" {
repo="$(centaur_mktemp_repo)"
printf '{"scripts":{"test":"echo ok"}}\n' > "$repo/package.json"
Expand Down
14 changes: 11 additions & 3 deletions tests/bats/health.bats
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,22 @@ load helpers/setup.bash
centaur_assert_contains "$out" "Restore required sections"
}

@test "centaur-health detects charter, guardrails, sea integrations" {
@test "centaur-health detects bats suite as verification command" {
repo="$(centaur_mktemp_repo)"
mkdir -p "$repo/.claude/knowledge/charter" "$repo/.claude/hooks" "$repo/.sea"
mkdir -p "$repo/tests"
printf '@test "ok" { true; }\n' > "$repo/tests/smoke.bats"
out="$(centaur_run_script centaur-health.sh "$repo")"
centaur_assert_contains "$out" "verification_command: detected"
}

@test "centaur-health detects charter, guardrails, se integrations" {
repo="$(centaur_mktemp_repo)"
mkdir -p "$repo/.claude/knowledge/charter" "$repo/.claude/hooks" "$repo/.se"
printf '# Policy\n' > "$repo/.claude/knowledge/charter/principles.md"
printf '{"hooks":{}}\n' > "$repo/.claude/hooks/hooks.json"
centaur_run_script centaur-init.sh "$repo" >/dev/null
out="$(centaur_run_script centaur-health.sh "$repo")"
centaur_assert_contains "$out" "charter_policy: detected"
centaur_assert_contains "$out" "guardrails: detected"
centaur_assert_contains "$out" "sea: detected"
centaur_assert_contains "$out" "se: detected"
}
Loading