← Files get-fableARCHIVED FILE

hooks/README.md

4.44 KB · Oct 2, 2026 · 00:30 UTC

↓ Download file

# get-fable lifecycle hooks

The hooks turn selected lifecycle invariants into mechanical host behavior. They are model-agnostic and operate only inside projects that have opted in with `.fable/`.

## Safety contract

- opt in: no `.fable/` directory means no project enforcement
- project local: durable workflow state lives in `.fable/state.json`
- bounded state: do not persist prompts, source contents, command output, credentials, or raw local paths as evidence metadata
- workspace identity: schema-v3 runtime state is bound to a digest of the canonical real project path; the tracked repository template remains workspace-neutral
- unexpected hook runtime failures remain fail-open so a broken helper does not brick the host
- an existing but invalid `.fable/state.json` is a workflow error and may block a substantial completion claim

## Five lifecycle scripts

| Hook | Typical event | Responsibility |
|---|---|---|
| `fable_profile_inject.py` | `SessionStart` | Restore phase, specialist skill, failure streak, active card, mutation generation, and verification freshness |
| `fable_spawn_guard.py` | `PreToolUse` on Agent/Task/Workflow | Require bounded delegated work before substantial spawning |
| `fable_fail_streak.py` | `PostToolUse` and `PostToolUseFailure` on Bash | Reset on success, record failures, and route two consecutive failures into `fable-recover` |
| `fable_mutation.py` | `PostToolUse` and `PostToolUseFailure` on write/edit tools | Conservatively advance `mutationGeneration` after a write attempt |
| `fable_close_guard.py` | `Stop` / `SessionEnd` where supported | Block unfinished cards, invalid state, stale proof, or substantial work that has not reached a valid complete state |

`_fable_common.py` provides shared state validation, schema-v1 migration, canonical workspace discovery, ledger parsing, atomic state writes, mutation tracking, and evidence-freshness rules.

## Mutation freshness

A successful recognized write advances the durable generation:

```text
before write
mutationGeneration = 6
verifiedGeneration = 6

after write
mutationGeneration = 7
verifiedGeneration = 6
```

The previous proof remains historical evidence but can no longer close substantial work.

`fable_mutation.py` contains its own write-tool allowlist in addition to host
matchers, so broad host events do not mark read-only commands as mutations. A
failed write attempt still advances the generation: editors can partially
change a file before reporting failure, so get-fable requires fresh evidence
instead of assuming the workspace stayed unchanged.

## Evidence freshness

The close guard accepts completion evidence only when:

1. `verifiedGeneration >= mutationGeneration`
2. the newest evidence accepted for the routed claim and current generation exists
3. that evidence passes and contains substantive detail
4. substantial durable state is actually in phase `complete`

For normal implementation work, accepted completion kinds are test, build, runtime, review, and observation.

Security evidence can close a pure security-review job when the durable routing decision identifies that job as security work. It does not by itself close a normal feature or bug repair. If security work leads to a product mutation, the changed behavior needs fresh behavior-appropriate verification.

Research, receipt, and handoff evidence do not close the behavior-completion gate.

## Failure recovery

A failure-relevant evidence record increments `failureStreak`. Two consecutive failures move active state to:

```json
{
  "phase": "recovering",
  "currentSkill": "fable-recover",
  "substantial": true
}
```

Recovery changes the diagnosis before another repair:

```text
harness and environment
-> actual execution path
-> product logic
-> violated invariant
```

A later successful failure-relevant evidence record resets the failure streak. It does not erase the recorded history.

## Session context

The profile injector supplies compact state only:

```text
phase
selected specialist
failureStreak
substantial
mutationGeneration
verifiedGeneration
activeCard
open ledger cards
```

It does not assign model tiers or claim that the active model changed capability.

## Host adapters

`hooks/hooks.json` is the Claude Code plugin declaration. `src/installer.ts` registers equivalent hook files for the repository's Antigravity / Gemini target.

Host event names and matchers may differ, but the Python state semantics are shared. Adapter behavior should be tested whenever canonical state or evidence rules change.

SHA-256: 59860fa423a3e3fde084905b74da665b6d6341da55a0c20579e382c5a76a9217