Focused Agentic Context Toolkit — Spec Kit + RPI for Claude Code
Project description
FACT — Focused Agentic Context Toolkit
An integration layer that gives Claude Code spec discipline, context discipline, and the cross-cutting reviews engineers normally do off-screen.
Context
FACT is the integration layer between three agent-engineering ideas that already work well on their own:
- Spec Kit — GitHub's spec-driven development discipline (Constitution → Spec → Plan → Tasks → Implement).
- RPI — HumanLayer's Research-Plan-Implement discipline: stay under the 40% context window, fork context with sub-agents, write semantic summaries at every phase boundary.
- Skills — Anthropic's procedural-knowledge format, refined in collections like obra/superpowers.
On top of those, FACT layers the cross-cutting concerns an agent typically forgets when left to its own devices:
- Architecture, security, code quality — continuous reviews that pause the workflow on real findings until the human decides.
- Context-window discipline — at 60% of the model's context the
agent stops and writes a semantic summary to disk, then asks you to
decide: type
/compact(you have to type it; the agent can't run slash commands), close and reopen, or push through. The summary survives crashes so the next session resumes cleanly. - Test-first proactivity — TDD before code, verification checklist before any task is marked done.
It runs alongside Claude Code, never wrapping it. Hooks observe the session; a local dashboard shows kanban + tokens + cost in real time.
Installation
Prerequisites
| Tool | Why |
|---|---|
| Python 3.10+ | FACT and its hooks (Claude Code calls them directly — no shell required, including on Windows) |
Claude Code on PATH |
the agent harness FACT plugs into |
git |
repo operations + Spec Kit |
uv or pipx |
to install FACT in an isolated env |
specify-cli (Spec Kit) is auto-installed on first fact init.
Fresh machine — macOS
brew install python git uv
# Claude Code: download from https://claude.com/claude-code
uv tool install fact-toolkit
Fresh machine — Windows (PowerShell)
winget install --id Python.Python.3.12 -e
winget install --id Git.Git -e
# Claude Code: download from https://claude.com/claude-code
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# Close + reopen PowerShell so PATH refreshes, then:
uv tool install fact-toolkit
FACT hooks are pure Python — no
bash, no Git Bash on PATH required.
Why not pipx on Windows? Its
pipx.exeshim is hard-coded to a single Python install; if you upgrade Python the shim breaks withUnable to create process using ...python.exe.uvdoesn't have that problem.
Already have the prerequisites? Pick one
uv tool install fact-toolkit # recommended
# or:
pipx install fact-toolkit
# or, clone for development:
gh repo clone holaPymbu/fact ~/.fact
python3 -m venv ~/.fact/.venv
~/.fact/.venv/bin/pip install -e ~/.fact
Quickstart
cd my-project/
fact init # creates .specify/, .claude/, CLAUDE.md; starts the dashboard
claude # open Claude Code in the same directory
> /fact-start # picks workflow type and begins
The dashboard opens at http://localhost:7842. Keep that tab open
while you work; it updates in real time.
Updating
uv tool upgrade fact-toolkit # uv users
pipx upgrade fact-toolkit # pipx users
git -C ~/.fact pull # dev clone
# Then, inside any FACT project:
fact upgrade
Configuration
Dashboard port (default 7842):
fact init --port 7900
# or edit .specify/fact/config.json
Pricing data lives in the bundled pricing.json and refreshes with
fact upgrade. Hook wiring lives in .claude/settings.json —
don't hand-edit; fact upgrade is the supported way to change it.
Maintainers: see CONTRIBUTING.md for the release process, project layout, and design principles.
Workflow
FACT is human-in-the-loop by design. The agent never blasts through phases — at every meaningful gate, it stops and asks. Below is the full path from "empty directory" to "feature done", with every user-input gate marked.
flowchart TD
Start(["fact init → claude → /fact-start"]) --> Resume{prior session<br/>state on disk?}
Resume -->|yes| Pick["fact-onboarding asks how<br/>to continue (review · resume · reset)"]
Resume -->|no| Type{project type?}
Pick -->|YOU pick| Type
Type -->|Greenfield| Disc["fact-discovery<br/>Socratic Q&A,<br/>one question at a time"]
Type -->|Brownfield| Res["fact-research<br/>7 parallel mappers"]
Type -->|Demo| Tiny["tinyspec extension<br/>fast-tracks idea → plan → implement"]
Disc -->|YOU shape it| Vision["Vision draft"]
Vision -->|YOU approve, max 2 iterations| Const
Res --> ResMd["research.md"]
ResMd -->|YOU validate| Const
Tiny --> Plan
Const["speckit.constitution"]
Const --> Spec["speckit.specify → spec.md"]
Spec --> Clar["speckit.clarify"]
Clar -->|YOU resolve ambiguities| Plan["speckit.plan → plan.md"]
Plan -->|YOU review the plan| Gate{Pre-implement<br/>audit gate}
Gate -->|critical findings| Plan
Gate -->|clean| Tasks["speckit.tasks → tasks.md"]
Tasks --> Loop["For each task<br/>(see 'Inside the implementation loop' below)"]
Loop --> AuditEdit["per-edit audit<br/>Haiku · security/quality"]
AuditEdit -->|YOU decide on findings| More{more tasks<br/>in user story?}
More -->|yes| Loop
More -->|no| AuditUS["per-user-story audit<br/>Sonnet × 3 · sec/arch/qual"]
AuditUS -->|YOU decide on findings| Next{more user<br/>stories?}
Next -->|yes| Loop
Next -->|no| Done(["Feature done"])
Done -. opt-in .-> FactAudit["/fact-audit all<br/>full review + run test suite"]
classDef user fill:#fff3cd,stroke:#856404,color:#000
classDef gate fill:#f8d7da,stroke:#721c24,color:#000
class Pick,Disc,Vision,Res,ResMd,Clar,Plan,AuditEdit,AuditUS user
class Gate gate
Yellow boxes = your input. Red diamond = blocking gate.
Where you give input
| Stage | What you do |
|---|---|
| Onboarding | Pick greenfield / brownfield / demo. If FACT detects prior session state, the agent shows a continuity recap and asks: continue from the last checkpoint, review/change something first, or (if a task was abandoned mid-flight) reset that task and start it over. |
| Discovery (greenfield) | Answer ~7 topics, one at a time: what to build, who for, what problem, 3-5 v1 features, references, constraints, stack. You can redirect any time ("first tell me about X"). |
| Vision draft (greenfield) | Read the draft and iterate (max 2 rounds). The agent pushes back on scope creep — "is this v1 or are you imagining v2?". |
| Research validation (brownfield) | Read research.md, flag what's missing or wrong. |
| Constitution & spec | Approve / revise the principles + spec the agent produces. |
| Clarify | The agent surfaces ambiguities; you answer them in chat. |
| Plan review | Read plan.md before tasks decomposition. fact-rpi-harness §6 explicitly stops here. |
| Audit gate (pre-implement) | If there are critical findings on the plan, you decide: revise plan, override (with logged reason), or rollback. |
| Per-edit audits | Every Edit/Write to a source file triggers a Haiku security/quality review on that single file. |
| Per-task audits | When you mark a task [x] in tasks.md, a Sonnet sec/arch/qual review runs over the files this task touched. On findings: fix automatically / fix manually / override / rollback. |
[P] parallel tasks |
Tasks marked [P] in tasks.md are delegated to sub-agents in their own worktrees and reviewed in two stages (spec-compliance → code-quality). On needs_rework, you decide: re-dispatch, fix in main, or accept divergence. |
| End-of-user-story audit | Agent-led. After closing the last task of a User Story, fact-implement triggers a parallel 3-dimension review over all files modified across the whole story. Same approval flow. |
| Compaction (60% context) | When context fills, the agent proposes 3 options: /compact, close+reopen, or push through. You pick. |
/fact-audit all |
Anytime, run a full review on demand. |
Inside the implementation loop
The Loop node above is one task. Internally each task can take two
shapes — sequential (the main agent does it) or parallel (a [P]-tagged
task delegated to a sub-agent in a worktree). FACT uses sub-agents in
two distinct ways during implementation:
- Context-forking sub-agents (always available, every task): when the main agent needs to read a lot to act on a little — find call sites, summarize tests, look up library docs — it spawns a short-lived Haiku/Sonnet sub-agent that returns 10-30 lines of distilled findings. The main agent stays focused on the change.
- Task-delegation sub-agents (only for
[P]-tagged tasks): independent tasks that don't share state can run in parallel, each in its own git worktree, each driven by its own sub-agent.
flowchart TD
Task[/Task line in tasks.md/]
Task --> P{"tagged [P]?"}
P -->|no| TddSeq["fact-tdd:<br/>RED → GREEN → REFACTOR"]
TddSeq --> CodeSeq["implement<br/>(forks Haiku/Sonnet sub-agents<br/>for codebase lookups, doc reads,<br/>test summaries while coding)"]
CodeSeq --> VfySeq["fact-verify checklist"]
VfySeq --> Mark["mark x in tasks.md"]
P -->|yes| Spawn["spawn sub-agent<br/>in its own worktree<br/>(model per fact-rpi-harness §3)"]
Spawn --> SubRun["sub-agent runs the task<br/>(applies fact-tdd inside)"]
SubRun --> Stage1["Stage 1 review<br/>Haiku · spec-compliance<br/>against tasks.md + plan.md"]
Stage1 --> Stage2["Stage 2 review<br/>Sonnet · code-quality<br/>diff review"]
Stage2 --> Mark
Mark --> AuditE["per-edit audit<br/>Haiku · security/quality"]
AuditE --> Next([next task])
classDef user fill:#fff3cd,stroke:#856404,color:#000
class VfySeq,Stage1,Stage2,AuditE user
The dashboard surfaces the difference visually: sequential work
pulses blue on the active card; [P] worktree sub-agent work
pulses violet, with a ⤵ subagent · model chip on the card so
you can see which model is doing what.
Cost discipline notes (from fact-rpi-harness §3 and §8):
- Lookup sub-agents: Haiku (~10× cheaper than Opus). Pass
model="haiku"explicitly — without it sub-agents inherit Opus and cost balloons. - Synthesis sub-agents: Sonnet (~5× cheaper than Opus).
- Stage 1 spec-compliance reviews: Haiku (cheap pattern-match).
- Stage 2 code-quality reviews: Sonnet (judgement work).
- The two-stage review typically adds < 5% to total session token cost and catches real bugs the main agent would have merged silently.
The three project types
Greenfield (new project)
The agent loads fact-discovery. You'll have a short, Socratic
conversation — one question per message, with room to redirect. The
topics it needs to leave the conversation having covered:
- What you want to build (one paragraph).
- For whom (target users, not "everyone").
- What problem it solves.
- Scope v1 — 3-5 core features.
- References — projects you admire / want to avoid.
- Constraints — budget, deadline, deployment, language.
- Stack preference (or it suggests after the vision draft).
After every answer, the agent decides: dig deeper, pivot to a topic you opened, or move on. If you say "wait, first I want to talk about X", it follows you. Six exchanges is usually enough.
Then the vision draft, your approval, and Spec Kit:
speckit.constitution → 4-6 principles derived from your vision
speckit.specify → first spec.md
speckit.clarify → ambiguities surfaced; you answer
speckit.plan → tech stack, architecture, code snippets
[ pre-implement audit gate ] ← MANDATORY (see Functionalities → Audits)
speckit.tasks → decompose plan into T-NNN tasks
speckit.implement → write code, task by task
Brownfield (existing repo)
The agent loads fact-research. It spawns 7 parallel sub-agents
(Haiku/Sonnet) that map, in one pass:
- Folder structure
- Stack & dependencies (
pyproject.toml,package.json, etc.) - Code conventions (3-5 representative files)
- Main modules / entry points
- Test framework & coverage shape
- Build & deploy (CI configs, Dockerfile, scripts)
- Existing docs (README, ARCHITECTURE.md, ADRs)
Result: a research.md under 200 lines. You read it and flag what's
missing or wrong. Then constitution + delta spec + plan + audit gate
- tasks + implement, same as greenfield from there.
If the repo already has an AGENTS.md / CLAUDE.md / GEMINI.md,
the agent absorbs its domain knowledge into the constitution and
replaces the old file with a one-paragraph pointer back to
.specify/memory/constitution.md.
Demo (quick experiment)
Uses the tinyspec Spec Kit extension to fast-track from idea to
plan to implement. fact-onboarding skips its own discovery / Q&A
phase and hands off straight to tinyspec; the rest of the path
(spec, plan, audit gate, tasks, implement) follows the same shape
as greenfield. Useful for spike work where you don't want the full
ceremony.
Session summaries between phases
Between every phase, the agent writes a short summary to
.specify/fact/sessions/<UTC>.md (What was done, What was decided, What's pending / next). These power continuity — if the
session crashes or you close at any point, the next session picks up
from the last summary.
Functionalities
Skills
FACT ships nine base skills. Loading is automatic — they're invoked by other skills, by hooks, or by slash commands.
| Skill | When loaded | What it does |
|---|---|---|
fact-onboarding |
first thing in /fact-start |
Detects continuity, asks for project type, hands off to a workflow skill. |
fact-rpi-harness |
always loaded | The 40% rule, sub-agent strategy, intentional compaction, session summaries, two-stage [P] review. |
fact-discovery |
greenfield workflow | Socratic Q&A → vision → constitution → specify → clarify → plan. |
fact-research |
brownfield workflow | Parallel sub-agents map the codebase → research.md → delta spec. |
fact-implement |
implement phase | Per-task discipline: read plan, apply skills, write code, mark done. |
fact-tdd |
by fact-implement for tasks that touch business logic |
RED-GREEN-REFACTOR cycle. Failing test first, smallest code to pass, refactor under green. |
fact-verify |
by fact-implement before flipping [x] on any task |
Verification checklist: tests pass, type-check clean, behavior matches plan, no TODOs / skipped tests, diff matches files the plan listed. |
fact-skill-installer |
when an external skill is needed | Search skills.sh, present to user, install with explicit confirmation. |
fact-audit |
when a hook trigger arrives | Orchestrates security / architecture / quality reviews; also runs the project test suite as a separate action when the user invokes /fact-audit all. |
CLI commands
| Command | What it does |
|---|---|
fact init |
Idempotent project setup. Auto-installs specify-cli. |
fact init --port 7900 |
Use a non-default dashboard port. |
fact init --no-dashboard |
Set up the project without starting the dashboard. |
fact init --no-speckit |
Skip the auto-install of specify-cli. |
fact dashboard |
Start (or check) the dashboard server. |
fact dashboard --restart |
Force restart the dashboard. |
fact stop |
Stop the dashboard. |
fact doctor |
Diagnose: what's missing, what's broken. |
fact doctor --fix |
Try to install anything missing (currently: specify-cli). |
fact upgrade |
Re-copy bundled skills / commands / hooks into the project. |
Slash commands (inside Claude Code)
| Command | What it does |
|---|---|
/fact-start |
First time: pick workflow type and begin. Resumed sessions: detects continuity. |
/fact-next |
Continue the current phase or advance to the next. |
/fact-status |
Quick status report in chat (≤10 lines). |
/fact-audit [security|architecture|quality|all] |
Run an audit on demand. |
Plus all of Spec Kit's /speckit.* commands (constitution,
specify, clarify, plan, tasks, implement, verify-tasks,
…) which the FACT skills call internally.
Dashboard
A local single-page app on port 7842, live during the session.
Three live zones:
- Header — phase pill (
constitution,specify,plan,tasks,implement,done); tasks counterdone/total; tokens (with input/output/cache breakdown on hover); cost in USD; saved vs Opus counterfactual showing what the workload would have cost if every sub-agent had used Opus. - Sidebar — file tree (every
.mdclickable, opens rendered); tokens grouped by model (opus-4-7,sonnet-4-6,haiku-4-5). - Kanban — stories from
tasks.md(User Story / Phase / Workflow / Foundation), each with a progress bar + count pills- click-through to a task-detail modal. The active card pulses
blue;
[P]worktree sub-agent work pulses violet with a⤵ subagent · modelchip showing which model is running.
- click-through to a task-detail modal. The active card pulses
blue;
Search (focus with /), feature picker, filter by kind / priority
/ task tag, hide-workflow toggle. The footer shows live WebSocket
status and auto-reconnects.
Audits
Hooks fire on tool use; they never run linters or audits themselves.
Each trigger emits a structured prompt that pauses the workflow and
instructs the agent to load the fact-audit skill, which spawns
sub-agents loaded with domain skills from
skills.sh.
| Trigger | When | Sub-agent | Dimensions |
|---|---|---|---|
source-edit |
every Edit/Write to .py/.ts/etc |
Haiku | security, quality |
task-close |
edit to tasks.md (typically when a task is marked [x]) |
Sonnet | security, architecture, quality |
| end-of-user-story | agent-led, not a hook — fact-implement runs it after closing the last task in a User Story |
Sonnet × 3 in parallel | security, architecture, quality |
/fact-audit all |
user invokes on demand | Sonnet × 3 in parallel | security, architecture, quality (also runs pytest / npm test / cargo test if available; test failures count as critical) |
There is no auto-fire audit at session close. Earlier versions fired one
on every Stop event and it interrupted normal flow (every "waiting for your
reply" turn re-fired the hook). End-of-session reviews are now opt-in via
/fact-audit all.
When findings of severity ≥ high exist, the agent surfaces them
verbatim and gives you four choices:
- Fix automatically — agent edits the affected files; the next write re-triggers the audit and must come back clean.
- Fix manually — agent pauses while you edit.
- Override — agent records the override + your reason in the session summary, then continues.
- Rollback — agent proposes the inverse of its last edit.
Lower-severity findings (medium/low/info) are mentioned in passing without blocking.
A separate pre-implement audit gate is invoked by
fact-discovery / fact-research after /speckit.plan and before
/speckit.tasks: three Sonnet sub-agents review the plan against
constitution + spec; critical findings → return to plan iteration.
Audit reports are written to .specify/fact/audits/<UTC>-<dim>.md.
The conversation between agent and user is the canonical surface;
the file is for record.
Continuity
FACT persists state continuously — not at session-close. If you
Ctrl+C Claude or the process crashes, the latest snapshot is
already on disk. On reopen, fact-onboarding reads:
session_state.json— mechanical state (active task, recent files, model, last update).- The latest
.specify/fact/sessions/<UTC>.md— semantic state (decisions, what was tried, what's next).
It then asks if you want to continue. Three cases handled:
- Clean close — last task was
[x]. Continue with the next pending task? - Mid-task abandon — last task
[ ]but files modified. Pick up where you left, or reset and start over? - Corrupt state —
session_state.jsonmissing/garbled. Falls back to the Spec Kit files alone, asks what to do.
If both layers are gone (rm -rf .specify/fact/), FACT degrades to
Spec Kit-only — exactly how Spec Kit projects work without FACT.
Troubleshooting
| Problem | Fix |
|---|---|
| Dashboard shows nothing — empty kanban | The agent hasn't run /speckit.tasks yet. Phase cards still appear; T-NNN cards arrive when tasks.md is generated. |
| Dashboard isn't reflecting changes | Hard refresh the browser (Cmd+Shift+R). Cache headers should prevent this but a stale tab can stick. |
specify not found / install failed |
Run fact doctor --fix. If still failing, install manually with uv tool install --from git+https://github.com/github/spec-kit.git specify-cli. |
🔒 FACT AUDIT keeps re-firing on Stop |
Update FACT (fact upgrade). The Stop hook now fires at most once per session. |
Cost shows $0.00 despite agent activity |
The dashboard reads tokens from the Claude Code transcript. Make sure the project was init'd with fact init; then fact upgrade to refresh hook helpers. |
Agent forgot to write active_task_id |
The dashboard infers in-progress from the recent file edit buffer. Should self-correct after the next file edit. |
fact upgrade didn't pick up a change you made to a bundled skill / hook |
fact upgrade always overwrites the project's copies with the bundled ones (it does rmtree per skill before copying). If a change is missing, you're on an older fact-toolkit — uv tool upgrade fact-toolkit (or pipx upgrade fact-toolkit) first, then fact upgrade inside the project. |
| I want to restart from scratch | fact stop && rm -rf .specify .claude/skills/fact-* .claude/commands/fact-* .claude/hooks && fact init. Your code is untouched. |
Windows: pipx install ... fails with Unable to create process using ...python.exe |
The pipx shim is hard-coded to a Python that no longer exists at that path. Either reinstall pipx (python -m pip install --user --upgrade pipx) or switch to uv (recommended on Windows). |
| Hooks don't fire / dashboard stays empty | Hook commands in .claude/settings.json reference an absolute path to the Python interpreter that ran fact init. If that interpreter has since moved or been uninstalled, the hooks silently fail. Re-run fact upgrade to refresh the paths. |
Claude Code shows Unknown hook event "SubagentEnd" |
Old FACT version. Run fact upgrade inside the project — it renames the event to SubagentStop (Claude Code's current name) and removes the stale entry from settings.json. |
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fact_toolkit-0.3.6.tar.gz.
File metadata
- Download URL: fact_toolkit-0.3.6.tar.gz
- Upload date:
- Size: 259.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61a55741cf3c72310a7453a78fa90c96df5048a8dd91d63de13e3e9f01dd723c
|
|
| MD5 |
622b20bb1ca113f4c4b1687c2457e970
|
|
| BLAKE2b-256 |
78be01ee24519aac0608f08d184ec53addbf9d04136511168de7527a6254c93f
|
Provenance
The following attestation bundles were made for fact_toolkit-0.3.6.tar.gz:
Publisher:
release.yml on holaPymbu/fact
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fact_toolkit-0.3.6.tar.gz -
Subject digest:
61a55741cf3c72310a7453a78fa90c96df5048a8dd91d63de13e3e9f01dd723c - Sigstore transparency entry: 1463022503
- Sigstore integration time:
-
Permalink:
holaPymbu/fact@a60852c27efb7fc74e2f61984a69c1c9bd29c5a6 -
Branch / Tag:
refs/tags/v0.3.6 - Owner: https://github.com/holaPymbu
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a60852c27efb7fc74e2f61984a69c1c9bd29c5a6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fact_toolkit-0.3.6-py3-none-any.whl.
File metadata
- Download URL: fact_toolkit-0.3.6-py3-none-any.whl
- Upload date:
- Size: 106.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
07f1695f4d4b9b17852c85725625b5d67a2b13a94026b153c5cfa06a8096455f
|
|
| MD5 |
88ba7e22d55e9df0b8ad06e2f831b518
|
|
| BLAKE2b-256 |
21a1442357f29607bff53079abebe02306259071fcac35b6b7a0334e490fb3c3
|
Provenance
The following attestation bundles were made for fact_toolkit-0.3.6-py3-none-any.whl:
Publisher:
release.yml on holaPymbu/fact
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fact_toolkit-0.3.6-py3-none-any.whl -
Subject digest:
07f1695f4d4b9b17852c85725625b5d67a2b13a94026b153c5cfa06a8096455f - Sigstore transparency entry: 1463022561
- Sigstore integration time:
-
Permalink:
holaPymbu/fact@a60852c27efb7fc74e2f61984a69c1c9bd29c5a6 -
Branch / Tag:
refs/tags/v0.3.6 - Owner: https://github.com/holaPymbu
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a60852c27efb7fc74e2f61984a69c1c9bd29c5a6 -
Trigger Event:
push
-
Statement type: