Skip to content
Open
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
90 changes: 90 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,54 @@ follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]

### Fixed
- The shell profile sourced the launcher from the cloned repo, so deleting or
moving the clone broke every new shell, and a re-install from a new path
silently kept the stale line. The installer now copies `fable.ps1`/`fable.zsh`
into `~/.claude/shell/` and sources the stable copy; a stale launcher line is
replaced, not kept.
- Auto/effort-activated sessions lost the playbook forever after a compaction:
SessionStart re-injected only under `FABLE_MODE=1`, while the session marker
blocked the UserPromptSubmit path. The trigger hook now re-injects on
`source == "compact"` whenever the marker proves the mode was active, and
drops the marker on `source == "clear"` so the once-per-session paths re-arm.
- `FABLE_PLAYBOOK.md` instructed the model to read the author's personal files
(`~/Downloads/Fable_Mindset_public.md`, `~/compare_models.py`,
`~/fable_dataset_delta.py`, `reference/llm-bias-awareness.md`) that no user
has — every fable session risked a failing Read. They are now provenance
notes, not paths; a content-guard test keeps them out.
- The `/fable` skill's fallback ("read the playbook from this skill's
repository") was unreachable after install — the installed skill is a lone
SKILL.md. The fallback now points at `fable doctor` / re-running the
installer.
- The installer silently `rmtree`'d a user's own `~/.claude/skills/<name>`
when it collided with a bundled skill name; it now preserves such
directories under `~/.claude/backups/skills/` and marks its own copies with
a `.fable-mode-bundled` file. The uninstaller removes only marked
directories.
- `test-after-edit.py` ran the suite even when the Edit tool itself had
failed (reporting a stale result), and `fable.ps1 doctor` hardcoded
`python`, breaking on machines where only `py`/`python3` exists. Both
fixed; the doctor subcommand now falls back across `python`/`py`/`python3`.
- Session/debounce marker files accumulated in `%TEMP%` forever on Windows;
both hooks now garbage-collect markers older than a week.
- "Invalid JSON provided for --settings" on Windows PowerShell 5.1 (#2): PS 5.1
strips embedded quotes when building the native command line, so the inline
`--settings '{"ultracode": true}'` reached claude as `{ultracode: true}`. The
launchers now pass a settings *file* (`~/.claude/ultracode.settings.json`,
shipped and installed), which survives quoting on every shell and PS version.
- The playbook injector never actually fired: the effort path needs `effort` in
the hook payload or `CLAUDE_EFFORT` in the hook environment, which Claude Code
≤ 2.1.198 did not provide, and the trigger phrases were undiscoverable. The
launcher now declares the mode via `FABLE_MODE=1` and `fable-trigger.py`
became dual-event — SessionStart injection (version-independent) plus the old
phrase/effort paths and a `FABLE_MODE` fallback on UserPromptSubmit.
- `merge_settings.py` overwrote `settings.json.bak` on every install run, so a
second install destroyed the pristine pre-install backup (contradicting the
"safe to re-run" promise). It now writes that backup only when absent, keeping
the original restore point intact.
- Closed leaked file handles (`json.load(open(...))` / `json.dump(..., open(...))`)
in `merge_settings.py`, `uninstall.py`, and `test-after-edit.py` — they now use
`with` blocks, which also avoids file-lock surprises on Windows.
- `fable-trigger.py` read the playbook from a hardcoded `/Users/ak/...` path, so
on-demand injection silently failed for everyone but the original author. It now
resolves `~/.claude/FABLE_PLAYBOOK.md`.
Expand All @@ -16,6 +64,43 @@ follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
`.lockb` skip entry.

### Added
- Double-injection guard: before the once-per-session auto/effort injection,
the trigger hook scans the session transcript for a "Fable mode active"
line — a session already activated via the `/fable` skill doesn't get a
second copy of the playbook.
- On Windows the launcher is now installed into the `$PROFILE` of **both**
PowerShell 7 and Windows PowerShell 5.1 when both are present.
- `fable doctor` now also verifies the launcher line in the shell profiles
(a line pointing at a missing file is a hard failure), accepts hooks
registered in `settings.local.json`, probes `claude --help` for the
`--effort` / `--append-system-prompt-file` flags the launcher relies on,
and checks the installed `~/.claude/shell/` launcher copies.
- The auto-activation heuristic learned more everyday task verbs
(update/upgrade/remove/delete/deploy/rename/write; удалить/обновить/
написать/запустить/перенести/убрать).
- Auto-activation: `fable-trigger.py` scores prompt complexity (ru+en signals:
task verbs, code fences, file paths, multi-step markers, length) and loads
the playbook by itself for task-shaped prompts, once per session, in any
session — no launcher or phrase needed. Opt out with `FABLE_AUTO=0`.
- `fable --ultra` (alias `-u`): launches with ultracode auto-orchestration; new
"Orchestration" section in the playbook (fan-out, adversarial verification
via `grounding-verifier`, plan-gating, calibration).
- `fable doctor`: one-command diagnosis of the install/activation chain —
files, registered hooks, interpreter paths, Claude Code version, a live-fire
injection test, and transcript evidence of past activations.
- The `/fable` skill triggers proactively at the start of non-trivial tasks.
- `fable-code.md`: an original Claude Code-native Fable behavior layer; the
launcher appends it instead of the 1,600-line consumer prompt (which stays
bundled for reference).
- `/fable` skill for explicit mid-session activation.
- The launcher pins `--model claude-opus-4-8`, making the README's "runs on
Opus 4.8" promise true regardless of the user's default model.
- Round-trip uninstall test (`tests/test_uninstall.py`).
- `test-after-edit.py` gained a `FABLE_TEST_HOOK_ALLOW` allowlist (os.pathsep-
separated trusted root prefixes) so the auto-run test hook can be confined to
repositories you trust, plus a per-project `.fable-test` file to pin the exact
command it runs (e.g. a fast, scoped command instead of the whole suite in a
monorepo). Documented in `SECURITY.md`; covered by new tests.
- **One-command, cross-platform installer** (`install.py`) for Windows, macOS, and
Linux. `install.sh` / `install.ps1` are thin wrappers that exec it.
- PowerShell launcher (`shell/fable.ps1`) alongside the zsh one.
Expand All @@ -28,6 +113,11 @@ follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
`SECURITY.md`, `CONTRIBUTING.md`, and this changelog.

### Changed
- The `fable` launcher now defaults to `--effort xhigh` instead of
`--settings '{"ultracode": true}'`. xhigh still trips the playbook trigger and
drives heavy reasoning, without ultracode's token-hungry multi-agent
auto-orchestration; ultracode is now an explicit opt-in (documented in the
launcher and README).
- `merge_settings.py` writes the absolute interpreter (`sys.executable`) and
absolute hook paths into `settings.json`, so the hooks fire without `$HOME` or
`python3` resolution at hook-run time.
Expand Down
76 changes: 59 additions & 17 deletions FABLE_PLAYBOOK.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# Execution Playbook — Fable-5 patterns for Opus 4.8 (measured companion)

This is the **measured** companion to *The Fable Mindset* (`~/Downloads/Fable_Mindset_public.md`).
That document is the full disposition manual; read it first. This file does one
thing it doesn't: it puts **your** fable-5 turns next to **your** opus-4-8 turns,
head to head, so every "adopt this / refuse that" call is backed by a number
from your own history — and it is honest about where the gap was smaller than it
first looked.
This is the **measured** companion to *The Fable Mindset*, the community
disposition manual (not bundled here — nothing below depends on having it).
This file does one thing that manual doesn't: it puts real fable-5 turns next
to real opus-4-8 turns, head to head, so every "adopt this / refuse that" call
is backed by a number — and it is honest about where the gap was smaller than
it first looked.

Measured: 1,307 fable-5 turns vs 10,470 opus-4-8 turns across 139 / 243 sessions.
Re-run anytime with `~/compare_models.py`.
Measured: 1,307 fable-5 turns vs 10,470 opus-4-8 turns across 139 / 243
sessions. The measurement tooling is not part of this bundle; the numbers are
the deliverable.

---

Expand Down Expand Up @@ -60,8 +61,9 @@ work (mostly write-heavy greenfield builds). What it confirms and what it compli
chain-of-thought on every event (100%); your Opus logs only store visible
thinking blocks. Don't read a reasoning delta off these two columns.

Ruler: `~/fable_dataset_delta.py`; extracted profile: `~/fable5_dataset_profile.json`.
The 22 MB raw dataset was deleted after the metrics were extracted.
The ruler script and extracted profile are part of the measurement tooling,
not this bundle. The 22 MB raw dataset was deleted after the metrics were
extracted.

---

Expand Down Expand Up @@ -203,8 +205,8 @@ makes the work correct; this layer makes the output read like Fable wrote it.
- **Own mistakes without grovelling.** When wrong, acknowledge it plainly, fix it,
stay on the problem — no self-abasement, no excessive apology, no caving on a
correct position just because you were challenged. Maintain self-respect; the
goal is steady honest helpfulness. (Pairs with `reference/llm-bias-awareness.md`:
a challenge is not an automatic signal to surrender.)
goal is steady honest helpfulness. A challenge is not an automatic signal to
surrender.
- **Epistemic honesty / no confabulation.** Partial recognition from training is
*not* current knowledge. For any library, version, product, or fact that may have
moved, verify (Context7 / web / the file itself) rather than answering from
Expand Down Expand Up @@ -232,6 +234,24 @@ makes the work correct; this layer makes the output read like Fable wrote it.
view of that file is stale — re-read the region before editing it again. (Extends
ADOPT 3 past the first edit; Fable states this outright for `str_replace`.)

### The Claude Code layer (first-party, 2026-07)

Observed first-party Fable 5 behavior in Claude Code adds three corrections to
the voice layer above — adopt them with the same weight:

- **The final message is the deliverable.** Mid-turn text may never be shown;
answers, findings, and conclusions must all appear in the turn's last
message, outcome first. A perfect investigation with a buried conclusion
reads as no conclusion.
- **Readable beats concise.** Shorten by selecting what matters, not by
compressing prose into fragments, arrow chains ("A → B → fails"), or
shorthand the reader must reverse-engineer. Complete sentences; explain in
place. If the reader must reread or ask a follow-up, the brevity saved
nothing.
- **Assessment mode.** When the user is describing a problem or thinking out
loud rather than requesting a change, the deliverable is the assessment:
report findings and stop; don't apply the fix until asked.

---

## Grounding — prove it before you call it done
Expand Down Expand Up @@ -305,18 +325,40 @@ levers the harness actually enforces:
that runs the project's test command, with `hooksEnabled: true`. This is the
fix for Fix 1; it fires every time, not most of the time.
- **Voice/formatting** → not hook-enforceable; it is pure disposition. The closest
lever is the bundled `stop-slop` skill — invoke it for any substantial prose
(docs, PRs, commit messages, user-facing summaries). For everything else the
voice-layer section above is the standing rule.
lever is a `stop-slop` skill, if one is installed — invoke it for any substantial
prose (docs, PRs, commit messages, user-facing summaries). For everything else
the voice-layer section above is the standing rule.
- **Grounding / verification independence** → the protocol ships as the `/ground`
skill (`~/.claude/skills/ground/`, invoke by name for the full self-terminating
ledger loop) and the cold `grounding-verifier` agent (`~/.claude/agents/`, spawn for
an independent read-only check that never sees your reasoning). Fable mode loads the
Grounding section above automatically via this playbook, so the standing discipline
is always on; the skill and agent are the heavier, explicit forms. For code changes
the bundled `/code-review` + `/verify` skills run alongside the verifier. Never
self-approve in the same active context.
Claude Code's built-in `/code-review` + `/verify` skills run alongside the verifier.
Never self-approve in the same active context.
- **Placement** → these rules belong in a `CLAUDE.md` (loads every session), not
auto-memory (relevance-gated, may not surface on a given turn). Point sessions
at this file and *The Fable Mindset* deliberately; wire the hook and effort
level as the hard guarantees.

---

## Orchestration — scale the harness to the task

Fable's discipline is single-context by default; escalate deliberately:

- **Fan out when the task decomposes.** Independent units (N files to migrate,
M subsystems to map, review dimensions) → parallel subagents, each with a
scoped brief; synthesize in the main context. Never serialize what has no
data dependency (Fix 3, applied to agents).
- **Verify adversarially.** Fan-in results are claims, not facts: route
non-trivial ones through the evidence ledger, and spawn the cold
`grounding-verifier` on the merged result — a subagent never self-approves
its own output (Grounding section above).
- **Plan-gate before long autonomy.** Multi-phase runs get a phased plan and a
live task list first; return to the plan at each phase boundary.
- **Calibrate ruthlessly.** One context that fits the whole task beats any
orchestration. No multi-agent machinery for typo-class work.
- **Mechanical lever:** `fable --ultra` launches with `ultracode` — the harness
auto-runs multi-agent workflows for substantive tasks. Heavy on tokens; the
calibration rule above is the counterweight.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ python install.py # Windows (use python3 on macOS / Linux)
Then reload your shell and launch:

```sh
fable # Opus 4.8 + Fable prompt + ultracode
fable # Opus 4.8 + Fable prompt + xhigh effort
```

Prefer a native one-liner? `./install.sh` (macOS / Linux) and `.\install.ps1` (Windows) just locate Python and run `install.py` for you.
Expand All @@ -48,24 +48,26 @@ Prefer a native one-liner? `./install.sh` (macOS / Linux) and `.\install.ps1` (W

> **Requirements:** Python on PATH (`python --version`) for the hooks, and Claude Code installed for the `fable` launcher. On Windows, if `.\install.ps1` is blocked by execution policy, run `python install.py` directly (no policy needed).

The installer copies everything into `~/.claude`, adds the `fable` launcher (to your shell rc on Unix, to your PowerShell `$PROFILE` on Windows), and merges your settings (with a backup) — writing the absolute interpreter and hook paths so the hooks fire on every platform. Idempotent: safe to re-run. Needs Python ≥ 3.9 (the hooks are stdlib-only — no pip installs). No model switch, no API key — it runs on the Opus 4.8 you already have.
The installer copies everything into `~/.claude` — including the launcher itself (`~/.claude/shell/`), so you can delete the clone afterwards — adds the `fable` launcher (to your shell rc on Unix, to the `$PROFILE` of both PowerShell 7 and Windows PowerShell on Windows), and merges your settings (with a backup) — writing the absolute interpreter and hook paths so the hooks fire on every platform. Idempotent: safe to re-run, and a same-named skill you wrote yourself is preserved under `~/.claude/backups/skills/` instead of being overwritten. Needs Python ≥ 3.9 (the hooks are stdlib-only — no pip installs). No model switch, no API key — it runs on the Opus 4.8 you already have.

## Uninstall

```sh
python uninstall.py # Windows (python3 on macOS / Linux; or ./uninstall.sh, .\uninstall.ps1)
```

Removes the bundled files from `~/.claude`, strips the `fable` launcher line, and drops the two Fable hooks from `settings.json` (writing a fresh backup). It's surgical — your own skills, unrelated hooks, and `alwaysThinkingEnabled` are left untouched.
Removes the bundled files from `~/.claude`, strips the `fable` launcher line, and drops the two Fable hooks from `settings.json` (writing a fresh backup). It's surgical — only skill directories carrying the installer's `.fable-mode-bundled` marker are removed; your own skills, unrelated hooks, and `alwaysThinkingEnabled` are left untouched.

## What's in the bundle

- **`FABLE_PLAYBOOK.md`** — the core. Fable-5 vs Opus-4-8 tool traces turned into rules: reasoning density (70% vs 47%), verify-after-edit, parallelism — plus a voice layer and an evidence-ledger grounding protocol. Original work, not the leaked prompt.
- **`fable-system.md`** — the leaked Fable 5 system prompt (Anthropic's; see note below).
- **Hooks** — `fable-trigger.py` injects the playbook at `xhigh`/`max`/`ultracode`; `test-after-edit.py` runs your project's tests after each edit and reports the result back — the one habit no model keeps on willpower.
- **`fable-code.md`** — an original Claude Code-native distillation of Fable's terminal behavior (final-message contract, readable-over-concise, tool discipline, autonomy rules). This is what the launcher actually appends; the consumer prompt above stays bundled for reference.
- **`/fable` skill** — explicit activation: reads the playbook + behavior layer and adopts both mid-session, no launcher required.
- **Hooks** — `fable-trigger.py` injects the playbook when the launcher declares the mode, at `xhigh`/`max`/`ultracode` effort, on a trigger phrase, or **by itself when the prompt looks like a real task** (ru+en heuristic; opt out with `FABLE_AUTO=0`); `test-after-edit.py` runs your project's tests after each edit and reports the result back — the one habit no model keeps on willpower.
- **`/ground` skill + `grounding-verifier` agent** — a self-terminating grounding loop and a cold verifier that assumes every claim is wrong until the live code proves it.
- **Skills** — `claude-design-patterns` (web-UI engineering), `webapp-testing`, `mcp-builder`, `skill-creator`, `explore-data`.
- **`fable` launcher** — Opus 4.8 + the prompt + `ultracode` effort (`fable.zsh` for Unix shells, `fable.ps1` for PowerShell).
- **`fable` launcher** — pins `--model claude-opus-4-8`, appends `fable-code.md`, sets `xhigh` effort, and declares the mode via `FABLE_MODE=1` so the playbook injects at session start on every Claude Code version (`fable.zsh` for Unix shells, `fable.ps1` for PowerShell). `fable --ultra` adds ultracode multi-agent orchestration; `fable doctor` verifies the whole install/activation chain in one command.

## The honest ceiling

Expand Down
Loading
Loading