Skip to content
Draft
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
10 changes: 9 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Both suites drive scripts that call rg, which the runner image lacks.
- name: Install ripgrep
run: sudo apt-get update -qq && sudo apt-get install -y -qq ripgrep
- name: Run golden-input tests
run: bash claude/test-hooks.sh
# The reconciler edits CLAUDE.md and agent frontmatter, so a suite CI
# never runs is a suite that rots. It drives a throwaway CLAUDE_DIR and
# touches nothing outside it.
- name: Run override tests
run: bash claude/test-overrides.sh

installer:
name: Installer smoke test
Expand All @@ -39,7 +47,7 @@ jobs:
# actually exist — the drift that broke the installer before.
- name: Parse-check every script
run: |
for f in install.sh scripts/*.sh claude/*.sh claude/hooks/*.sh; do
for f in install.sh scripts/*.sh claude/*.sh claude/hooks/*.sh claude/gentle-ai-overrides/*.sh; do
bash -n "$f" || exit 1
done
- name: Verify every script install.sh invokes exists
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ This will install Homebrew, packages from the Brewfile, Oh My Zsh with plugins,
**Claude Code**
- Global `PreToolUse` guard hooks (secret scanning, destructive-command
blocking) merged into `~/.claude/settings.json` — see [claude/README.md](claude/README.md)
- Local SDD rules that outrank `gentle-ai`'s own, with a reconciler that
restores them after every sync
- Workflow scripts for the `Workflow` tool, symlinked into `~/.claude/workflows/`

#### Installing a new tool
```bash
Expand Down
89 changes: 84 additions & 5 deletions claude/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ Installed by `scripts/claude.sh`, which is called from `install.sh`.
| `hooks/bash-guard.sh` | `PreToolUse` on `Bash` — commit attribution, destructive commands, CLI preference |
| `hooks/write-guard.sh` | `PreToolUse` on `Edit\|Write\|MultiEdit` — credential scan |
| `statusline.sh` | Status line: model, branch, session cost, context and rate-limit budget |
| `settings.fragment.json` | The `hooks` and `statusLine` blocks merged into `~/.claude/settings.json` |
| `settings.fragment.json` | The `hooks`, `statusLine` and `subagentPromptCacheTtl` keys merged into `~/.claude/settings.json` |
| `test-hooks.sh` | 35 golden inputs, both directions |
| `gentle-ai-overrides/` | Local SDD rules that outrank gentle-ai's own, and the reconciler that keeps them alive |
| `workflows/` | Scripts for the `Workflow` tool, symlinked into `~/.claude/workflows/` |
| `test-overrides.sh` | 22 golden inputs for the reconciler, run against a throwaway `CLAUDE_DIR` |

## bash-guard.sh

Expand Down Expand Up @@ -65,10 +68,16 @@ passes everything — silently.
## What is deliberately NOT here

Everything under `~/.claude` carrying a `<!-- gentle-ai:... -->` marker —
`skills/`, `agents/`, `commands/`, `output-styles/`, and the global
`CLAUDE.md` — is generated and owned by `gentle-ai sync`. Tracking it here
would vendor a package manager's output and fight the next sync. The Brewfile
declares `gentleman-programming/tap/gentle-ai`; the tool owns its own files.
`skills/`, `agents/`, `commands/`, `output-styles/`, and the marked regions of
the global `CLAUDE.md` — is generated and owned by `gentle-ai sync`. Tracking
it here would vendor a package manager's output and fight the next sync. The
Brewfile declares `gentleman-programming/tap/gentle-ai`; the tool owns its own
files.

The exception is [`gentle-ai-overrides/`](#gentle-ai-overrides), which tracks
only what gentle-ai provably does not own: the region of `CLAUDE.md` past its
last marker, plus one frontmatter key the reconciler re-applies after each
sync. Nothing generated is copied into this repo.

Session state (`projects/`, `sessions/`, `history.jsonl`, `security/`) is
neither config nor portable.
Expand Down Expand Up @@ -102,3 +111,73 @@ not pass.
Remove its entry from `settings.fragment.json` and rerun `scripts/claude.sh`, or
edit `~/.claude/settings.json` directly for a one-machine change. Hooks reload
mid-session, so the change takes effect on the next tool call.

## gentle-ai-overrides/

`gentle-ai` owns `~/.claude/skills/`, `~/.claude/agents/` and most of
`~/.claude/CLAUDE.md`. This directory is the one seam where local rules can
outrank it without forking the tool.

### Why it can work at all

`gentle-ai sync` rewrites `CLAUDE.md` through
`filemerge.InjectMarkdownSection`, which rebuilds the file as
`before + block + after` for one `<!-- gentle-ai:NAME -->` region at a time.
Anything outside every marker is never touched. So `CLAUDE.local-overrides.md`
is appended past the last marker under its own
`<!-- dotfiles:local-sdd-overrides -->` sentinels, and survives on its own.

Agent definitions get no such courtesy: every file in gentle-ai's embed is
overwritten wholesale on each install (`WriteFileAtomic`, no merge). The
`memory: project` key on the reviewer agents therefore has to be re-applied,
which is the reconciler's second job.

### The rules

`CLAUDE.local-overrides.md` carries L1–L7. They come from measuring 10 archived
SDD changes in `reels-lab`, where the pipeline found zero implementation
defects by code review: every FAIL was a missing test, and the one change that
needed six remediation rounds was a single requirement that never enumerated
its entry points. The rules push work upstream — test tasks per scenario,
entry points per validation requirement — instead of paying for it in
verification rounds. The raw table is in the knowledge vault under
`03_Resources/Tech/IA Engineering/`.

### Keeping them alive

```bash
gentle-ai-overrides/reconcile.sh # apply, print what changed
gentle-ai-overrides/reconcile.sh --quiet # apply, print only on change
gentle-ai-overrides/reconcile.sh --check # report drift, exit 1, change nothing
```

Three things run it, so it should never need running by hand:

- `scripts/claude.sh`, on install.
- The `gentle-ai` wrapper in `zsh/functions.zsh`, after `install`, `sync` and
`upgrade` — the only commands that cause drift. It forwards every argument
and preserves the exit code.
- `--check` in CI or a pre-commit hook, if drift should ever fail a build.

It refuses to touch a `CLAUDE.md` whose gentle-ai markers are unbalanced: that
means a sync was interrupted, and splicing into a half-written file would put
the block inside a region about to be rewritten.

## workflows/

`~/.claude/workflows/` holds scripts for the `Workflow` tool, which runs a DAG
of agents deterministically instead of leaving the orchestration to the model.
gentle-ai never writes there, so these are plain symlinks.

`sdd-chain.js` encodes the SDD pipeline: exploration fanned out across three
scoped readers, spec and design in parallel (neither depends on the other —
both read only the proposal), a task schema that forces every work unit to
declare the files it writes, apply and verify pipelined per unit, and archive
only at zero CRITICALs. It proves the file partition before running writers in
parallel and degrades any overlapping units back to serial. Its verify schema
requires each CRITICAL to be classified `coverage`, `spec_ambiguity` or
`implementation`, which is what keeps the measurement behind L1-L7 current
instead of a one-off.

Running a workflow needs explicit opt-in per invocation; installing the script
does not run anything.
69 changes: 69 additions & 0 deletions claude/gentle-ai-overrides/CLAUDE.local-overrides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
## Local SDD Overrides (take precedence over the gentle-ai blocks above)

Derived from a measured baseline of 10 archived changes in `reels-lab` (2026-08-30).
Across that corpus the pipeline found **zero implementation defects by code review**:
all 3 FAIL verdicts were missing-test findings, and the single 6-round change was one
requirement that never enumerated its entry points. The raw table lives in the
knowledge vault under `03_Resources/Tech/IA Engineering/Auditoría SDD - Rondas hasta PASS.md`.

### L1. One test task per spec scenario (`sdd-tasks`)

`sdd-verify` marks any scenario without a test that actually ran as CRITICAL, however
correct the code is proven to be by other means. So `sdd-tasks` MUST emit an explicit
test task for every scenario in the delta specs, named with the scenario it covers.
A task list whose test tasks do not cover every scenario is incomplete — say so and fix
it before `sdd-apply`, rather than letting verify discover the gap later.

### L2. Validation requirements MUST enumerate entry points (`sdd-spec`)

A requirement of the form "X is validated" is incomplete. Every requirement that
constrains inbound data MUST carry one scenario per entry surface that can reach the
code path — CLI command, worker/queue boundary, HTTP handler, library API, each named
explicitly. Enumerate the surfaces by searching the codebase for call sites, never from
the proposal's prose alone.

### L3. Tiered preflight (overrides the four-question hard gate)

The `SDD Session Preflight` hard gate is scaled to what the command can actually do:

| Command | Preflight collected |
| --- | --- |
| `/sdd-status`, `/sdd-explore` | none — read-only, no artifacts, no PR |
| `/sdd-new`, `/sdd-ff`, `propose` → `tasks` | pace + artifact store only |
| `/sdd-apply` and beyond | all four, asked once the tasks forecast exists |

Collect the later groups when first needed and cache them, in one `AskUserQuestion`
call per tier. Never block a read-only command on a delivery decision.

### L4. Fan out `sdd-explore`

Exploration is breadth-first and read-only, so run it as three scoped explorers in
parallel — current state, prior art, constraints/entry points — then synthesize one
report. No file conflicts are possible.

### L5. Partitioned apply, and only when the partition is proven

`sdd-tasks` declares work units with the exact list of files each one writes. Units
whose file sets are disjoint may run as parallel writers in the same tree; any unit
that shares a file with another, or declares a dependency, stays serial. Never
parallelize writers on an unproven partition — two agents on one file overwrite each
other, which costs a whole run rather than saving one.

Verification of a unit may overlap with implementation of the next: it runs against
that unit's own frozen candidate, which the receipt machinery already guarantees.

### L6. Agent teams stay per-session

Never add `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` to `settings.json`. Enabling it makes
every subagent Claude names launch as a full teammate at 3–5× the tokens, including in
delegation never framed as team work. Enable it on the command line for a session that
specifically wants debate — a bug with an unclear root cause, an architecture review.
Default delegation stays on subagents.

### L7. Classify every CRITICAL by origin

When `sdd-verify` raises a CRITICAL, state its origin: `coverage` (the code is correct
but no test that ran covers the scenario), `spec_ambiguity` (the requirement was
under-specified), or `implementation` (the code is actually wrong). Do not default to
`implementation`. That classification is the measurement the rules above were tuned on,
and it is what keeps the next tuning honest instead of guessed.
Loading
Loading