Skip to main content

Focused Agentic Context Toolkit — Spec Kit + RPI for Claude Code

Project description

FACT — Focused Agentic Context Toolkit

A harness that turns Claude Code into an agent that follows Spec Kit + RPI by default, with a local dashboard for progress, tokens, and cost — and a hook-driven audit layer that pauses the workflow on real security / architecture / quality / testing issues until the human approves.

Status: v0.1 (private repo). Battle-tested on a 46-task greenfield FastAPI project with continuous security & quality audits.


Table of contents


What is FACT

FACT is the glue between three independent pieces:

  1. Spec Kit — GitHub's spec-driven development toolkit. Constitution → Spec → Plan → Tasks → Implement.
  2. RPI (Research-Plan-Implement) — HumanLayer's discipline: stay under the 40% context window, fork context with sub-agents, write semantic summaries at every phase boundary.
  3. Skills — Anthropic's procedural-knowledge format. FACT ships seven base skills and pulls domain skills from skills.sh on demand for audits.

It runs alongside Claude Code, never wrapping it. Hooks observe the session and feed three things:

  • a local dashboard showing the kanban of stories, token cost, and the file tree,
  • a session-state file that survives crashes so the agent can resume cleanly tomorrow,
  • a hook-driven audit layer that triggers security / architecture / quality / testing reviews via sub-agents loaded with domain skills, and pauses the workflow until the human approves.

Install

Prerequisites

Tool Why
Python 3.10+ FACT and its hooks (Claude Code calls FACT's Python helpers directly — no shell required, including on Windows)
Claude Code on PATH the agent harness FACT plugs into
git repo operations + Spec Kit
gh (only while the repo is private) gh auth login is the simplest way to authenticate git for the install
uv or pipx to install FACT in an isolated env

specify-cli (Spec Kit) is auto-installed on first fact init.

From a fresh machine — macOS

# 1. Homebrew (skip if already installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 2. Prerequisites
brew install python git uv
# Claude Code: download the desktop installer from https://claude.com/claude-code

# 3. Install FACT (pick the line that matches your situation — see below)
uv tool install fact-toolkit                                                    # PyPI (once published)
# or, while the repo is private / for unreleased dev builds:
# brew install gh && gh auth login
# uv tool install --from git+https://github.com/holaPymbu/fact.git fact-toolkit

From a fresh machine — Windows (PowerShell)

# 1. Prerequisites via winget
winget install --id Python.Python.3.12 -e
winget install --id Git.Git -e
# Claude Code: download from https://claude.com/claude-code

# 2. uv (recommended over pipx — avoids the broken-launcher problem when Python is upgraded)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

# >>> Close and reopen PowerShell so PATH refreshes <<<

# 3. Install FACT
uv tool install fact-toolkit                                                    # PyPI (once published)
# or, while the repo is private:
# winget install --id GitHub.cli -e ; gh auth login
# uv tool install --from git+https://github.com/holaPymbu/fact.git fact-toolkit

FACT hooks are pure Python — no bash, no Git Bash on PATH required.

Why not pipx on Windows? pipx installs a pipx.exe shim hard-coded to one Python install. If you upgrade or reinstall Python the shim breaks with Unable to create process using ...python.exe. uv doesn't have this problem. If you must use pipx, sidestep the shim: python -m pipx install ....

Already have the prerequisites? Pick one:

Option A — uv tool (recommended)

uv tool install fact-toolkit                                                    # PyPI
# or for unreleased dev builds:
uv tool install --from git+https://github.com/holaPymbu/fact.git fact-toolkit

uv handles the isolated environment for you.

Option B — pipx

pipx install fact-toolkit                                                       # PyPI
# or:
pipx install git+https://github.com/holaPymbu/fact.git

Option C — clone for development

gh repo clone holaPymbu/fact ~/.fact
python3 -m venv ~/.fact/.venv
~/.fact/.venv/bin/pip install -e ~/.fact
echo "alias fact='~/.fact/.venv/bin/fact'" >> ~/.zshrc

After install, fact --help should work in any directory.

Updating

uv tool upgrade fact-toolkit                          # Option A
pipx upgrade fact-toolkit                             # Option B
git -C ~/.fact pull                                   # Option C

After updating FACT itself, run fact upgrade inside any project to refresh its bundled skills, commands, and hooks.

Releasing to PyPI (maintainers)

The repo ships a trusted-publishing workflow at .github/workflows/release.yml. One-time setup on PyPI:

  1. Claim the project name (fact-toolkit) — first manual upload, or by reserving via the PyPI account UI.
  2. On the project's Publishing page, add a Trusted Publisher for owner holaPymbu, repository fact, workflow release.yml, environment release.
  3. In this repo's Settings → Environments, create an environment named release (no secrets needed — OIDC handles it).

Then to cut a release:

# bump the version in pyproject.toml, commit, push
git tag v0.1.0
git push --tags

The workflow checks the tag matches pyproject.toml, builds the sdist

  • wheel, and publishes them to PyPI. No tokens, no secrets to rotate.

Quickstart

In a new directory (greenfield) or an existing repo (brownfield):

cd my-project/
fact init           # one-time setup. Creates .specify/, .claude/, CLAUDE.md.
                    # Auto-installs specify-cli. Starts the dashboard.
claude              # open Claude Code in the same directory
> /fact-start       # picks workflow (greenfield/brownfield/demo) and begins

fact init opens the dashboard at http://localhost:7842. Keep that tab open while you work; it updates in real time as the agent edits files and tasks close.


Dashboard tour

FACT dashboard

A single-page local app on port 7842. Four zones, all live:

Header (top)

  • BrandFACT • <project-name> • <phase>. Phase pill reflects the current Spec Kit phase (constitution, specify, plan, tasks, implement, done).
  • TASKS<done> / <total> aggregated across the visible scope (one feature or all features).
  • TOKENS — total tokens read from the Claude Code transcript, formatted as K/M. Hover to see the input / output / cache breakdown.
  • COST — total session cost in USD, computed from pricing.json. If a model wasn't priced, it's flagged with ?.
  • SAVED VS OPUS — counterfactual: what the workload would have cost if every sub-agent had been Opus. The bigger this number, the more the Haiku/Sonnet sub-agent strategy is paying off.

Sidebar (left)

  • Files tree — every .md file in the project, recursive. Click any to open it in a markdown-rendered modal. Folders are collapsible; defaults expand .specify/, .specify/specs/, .specify/fact/sessions/, .specify/memory/. Ignored automatically: node_modules, .venv, .git, __pycache__, dist, build, *.egg-info, etc.
  • By model — token spend grouped by model (opus-4-7, sonnet-4-6, haiku-4-5). Cost + total tokens per model. Hover for the input/output/cache split.

Kanban (center)

Stories go into Pending / In Progress / Done columns. A story is one of:

Kind Source Visual
foundation the project's Constitution alone yellow border, foundation badge
workflow per-feature pre-implement tasks yellow border, workflow badge
user_story a tasks.md section labeled User Story N, enriched with the title from spec.md blue border, US N badge, optional P1/P2/P3 priority pill
phase any other tasks.md section (Setup, Foundational, Polish, …) gray border, phase badge

Each card shows:

  • a feature badge (which feature it belongs to, e.g. 001·tea),
  • the kind badge + optional priority pill,
  • a counter pill done/total,
  • a slim progress bar (done | in-progress | pending),
  • three count pills ✓ N done · ● N in progress · ○ N pending.

Click a card to open the story detail modal — it lists every task underneath with chips for tags (P, US1, REVIEW, …), files referenced (clickable, opens the file viewer), and dependencies (clickable, jumps to that task's detail).

In-progress signal

When the agent is currently working in a story, the card has:

  • a pulsing blue glow around the border (CSS keyframes, 2.4s),
  • a blinking blue dot next to the kind badge,
  • a started Xm ago footer that updates every 20 seconds.

If a [P] task is delegated to a sub-agent in a worktree, that specific task pulses violet instead of blue, and the card shows a ⤵ subagent · model chip indicating which model is running it.

Toolbar above the kanban

  • Search — matches story title or any field of any task in it (id, title, file, tag, dependency). Tip: press / from anywhere to focus the search.
  • Feature picker — switches between features, or All features (default when there are >1).
  • Filter dropdown — grouped: story kind (User Story / Phase / Workflow / Foundation), priority (P1 / P2 / P3), and task tag (P, US1, US2, …).
  • Hide workflow — toggles foundation + workflow cards off, so you only see real implementation stories.
  • tags? — opens the tag legend explaining P, US N, REVIEW, BLOCKED, etc.

Footer

A live status line: live · updated HH:MM:SS when the WebSocket is connected, reconnecting… when it's down. The dashboard auto-reconnects.


The workflow

/fact-start asks for the project type:

1. Greenfield

Loads fact-discovery, which conducts a structured Q&A (target users, problem, core features, references, stack, constraints) to produce a vision draft. Then runs Spec Kit in order:

/speckit.constitution   → 4–6 principles derived from the vision
/speckit.specify        → first spec.md
/speckit.clarify        → resolves ambiguities with the user
/speckit.plan           → tech stack, architecture, code snippets
[ pre-implement audit gate ]   ← MANDATORY (see Audits section)
/speckit.tasks          → decompose plan into T-NNN tasks
/speckit.implement      → write code, file by file

2. Brownfield

Loads fact-research, which spawns parallel sub-agents (Haiku/Sonnet) to map structure, stack, conventions, modules, tests, and CI configs of the existing codebase. Produces a research.md map. Then constitution + delta spec + plan + audit gate + tasks + implement.

3. Demo

Quick experiment via the tinyspec extension. Skips discovery and clarify; one shot from idea → plan → implement.

Between every phase, the agent writes a session summary to .specify/fact/sessions/<UTC>.md (What was done, What was decided, What's pending / next). These power continuity (see below).


Audits

FACT runs continuous audits driven by hooks. Hooks are pure triggers — they never run linters or audit logic themselves. When a hook fires, it emits a structured prompt that pauses the workflow and instructs the agent to load the fact-audit skill. The skill then orchestrates the actual review using sub-agents loaded with domain skills from skills.sh.

Edit / Stop                                        Agent next turn
    │                                                    │
    ▼                                                    ▼
Hook fires  ─►  emits structured trigger  ─►  Agent loads fact-audit
                  + exits with code 2                    │
                                                         ▼
                                              Spawns sub-agents per
                                              dimension, each loaded
                                              with a domain skill
                                              from skills.sh
                                                         │
                                                         ▼
                                              Aggregates findings,
                                              shows them verbatim
                                              to the user
                                                         │
                                                         ▼
                                              User picks: fix /
                                              manually / override /
                                              rollback
                                                         │
                                                         ▼
                                              Workflow resumes

Three triggers

Trigger When Sub-agent Dimensions
source-edit every Edit/Write to .py/.ts/.go/etc Haiku security, quality
task-close edit to tasks.md (likely a task closed) Sonnet security, architecture, quality
session-stop the agent tries to close session Sonnet (×3 parallel) security, architecture, quality, testing

Tests run via pytest / npm test / cargo test if available. Test failures count as critical.

User-approval flow

When findings of severity ≥ high exist, the agent shows them verbatim and offers four options:

  1. Fix automatically — agent edits the affected files. The next file write re-triggers the audit; it must come back clean for the workflow to resume.
  2. Fix manually — agent pauses while the human edits.
  3. Override — agent records the override + the user's reason in the session summary, then continues.
  4. Rollback — agent proposes the inverse of its last edit; on confirmation, applies it.

Lower-severity findings (medium/low/info) are mentioned in passing without blocking.

Pre-implement gate

Not hook-triggered — explicitly 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.

On demand

> /fact-audit                 # run all dimensions on full session changes
> /fact-audit security        # only that one
> /fact-audit architecture
> /fact-audit quality

Reports

Every audit writes a markdown report to .specify/fact/audits/<UTC>-<dim>.md with YAML frontmatter (severity counts, scope, skill used). They surface in the file tree but not as a dashboard panel — the conversation between agent and user is the canonical audit surface.


CLI reference

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

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 Run an audit on demand. Optional arg: security / architecture / quality / all.

Plus all of Spec Kit's /speckit.* commands (constitution, specify, clarify, plan, tasks, implement, verify-tasks, …) which the FACT skills call internally.


Skills shipped with FACT

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.
fact-discovery greenfield workflow Structured 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-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 / testing reviews.

Project layout

When FACT manages a project:

my-project/
├── .claude/
│   ├── skills/
│   │   ├── fact-*/SKILL.md                  (FACT base skills, listed above)
│   │   └── speckit-*/SKILL.md               (Spec Kit's own skills)
│   ├── commands/
│   │   ├── fact-start.md
│   │   ├── fact-next.md
│   │   ├── fact-status.md
│   │   └── fact-audit.md
│   ├── hooks/                               (pure-Python — Claude Code calls them directly)
│   │   ├── fact_hook.py                     (FACT observation; tool/session/subagent events)
│   │   ├── fact_audit.py                    (per-file audit trigger on PostToolUse)
│   │   ├── fact_audit_stop.py               (testing-audit helper, invoked on demand)
│   │   ├── fact_compact_progress.py         (60% context-window compaction trigger)
│   │   ├── fact_compact.py                  (compaction helper, invoked on demand)
│   │   └── fact_session_resume.py           (resume nudge on SessionStart)
│   └── settings.json                        (hook wiring)
├── .specify/
│   ├── memory/
│   │   └── constitution.md                  (Spec Kit)
│   ├── specs/
│   │   └── <NNN-feature>/                   (Spec Kit per-feature)
│   │       ├── spec.md, plan.md, tasks.md, research.md
│   │       ├── checklists/, contracts/, …
│   └── fact/                                (FACT operational state)
│       ├── config.json                      (port, host, agent type)
│       ├── dashboard.pid                    (running dashboard pid)
│       ├── events.jsonl                     (append-only hook log)
│       ├── session_state.json               (mechanical state)
│       ├── sessions/<UTC>.md                (semantic summaries)
│       ├── audits/<UTC>-<dim>.md            (audit reports)
│       └── .stop-audit-<id>.fired           (loop guard markers)
├── CLAUDE.md                                (~20 lines, points at skills)
└── (your code: src/, tests/, etc)

Key principle: everything FACT writes lives under .specify/fact/. There is no parallel ~/.fact/ or ./fact/ directory in the project. If you rm -rf .specify/, you reset both Spec Kit AND FACT — clean slate.


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:

  1. fact-onboarding reads session_state.json for mechanical state (active task, recent files, model, last update).
  2. It reads the latest sessions/<UTC>.md summary for semantic state (decisions, what was tried, what's next).
  3. It presents a continuity message and asks if you want to continue from where you were.

Three resumption cases handled by the skill:

  • Clean close — last task was marked [x]. Asks: continue with the next pending task?
  • Mid-task abandon — last task was [ ] but files were modified. Asks: pick up where I left, or reset and start over?
  • Corrupt statesession_state.json missing/garbled. Falls back to the Spec Kit files alone, asks the user 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.


Configuration

Dashboard port

Default: 7842. Override at init time:

fact init --port 7900

Or edit .specify/fact/config.json:

{
  "version": "0.1.0",
  "agent": "claude-code",
  "dashboard": { "host": "127.0.0.1", "port": 7842 }
}

Pricing

Token costs come from pricing.json shipped with FACT. Verify against Anthropic's pricing page at release time; update via fact upgrade when models change.

Hooks

.claude/settings.json is managed by fact init / fact upgrade. Don't hand-edit unless you know what you're doing — re-running fact upgrade will preserve your additions but might add FACT entries again if the markers change.


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 says nothing changed That's fine — it's idempotent. To force a refresh, delete .claude/skills/fact-* and re-run.
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.

Design principles

These guide every implementation decision in FACT. If a change violates one, the change is wrong, not the principle.

  1. Single source of truth: Spec Kit .md files. FACT never writes parallel state files as a substitute. Every derived view (dashboard, status command) reads from the Spec Kit files.
  2. The agent never spends tokens maintaining FACT metadata. What FACT needs to know is deduced from hooks, the filesystem, and the files Spec Kit already generates. Semantic summaries the agent writes are the same it would write under good RPI practice.
  3. CLAUDE.md is 20 lines or less. Detailed rules live in skills, loaded on demand.
  4. RPI rules are non-negotiable. The 40% smart-zone, intentional compaction, sub-agents for forking context, code snippets in plans — these aren't bendable.
  5. Sub-agents fork context, not roles. No "frontend agent" or "backend agent". Sub-agents are a compression mechanism.
  6. Sub-agents use differentiated models. Haiku for lookup, Sonnet for synthesis, the main model for deep reasoning.
  7. External skills require explicit user confirmation. The agent never downloads a skill without a clear "yes" in chat.
  8. FACT runs alongside, never in the middle. No wrapping, no proxying.
  9. Cheap extensibility, not expensive. A single Protocol (AgentAdapter), one concrete impl. No plugin registry.
  10. Honest metrics. If a number can't be computed accurately, show a placeholder, never fabricate.
  11. One project folder. Everything FACT writes is under .specify/fact/. No parallel root directories.
  12. Continuity is automatic. The user never runs a pause or save ritual. Close anytime, reopen, the agent catches up.

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fact_toolkit-0.1.1.tar.gz (259.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fact_toolkit-0.1.1-py3-none-any.whl (101.0 kB view details)

Uploaded Python 3

File details

Details for the file fact_toolkit-0.1.1.tar.gz.

File metadata

  • Download URL: fact_toolkit-0.1.1.tar.gz
  • Upload date:
  • Size: 259.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fact_toolkit-0.1.1.tar.gz
Algorithm Hash digest
SHA256 e75c048ea15528e9a38c11ea99ab3f8b41d083055652593bf5b5ee10024de769
MD5 cbe5f273276f78094bdc8110f247dbd4
BLAKE2b-256 3ac955dbdf5c285afb9b2b9e774b34f1864e95bc664f20497d1022b1fa18cd60

See more details on using hashes here.

Provenance

The following attestation bundles were made for fact_toolkit-0.1.1.tar.gz:

Publisher: release.yml on holaPymbu/fact

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fact_toolkit-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: fact_toolkit-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 101.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fact_toolkit-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3e5072317ca977a3908122da8eb78d0b862b1d4254c1f9d1a705271e3f254700
MD5 fcfe29f08cf14fbcef2e53410903529d
BLAKE2b-256 cf2275fc0e075e24a827c05658befc64e500d7f1e34ade8fb819fadcd2b4847b

See more details on using hashes here.

Provenance

The following attestation bundles were made for fact_toolkit-0.1.1-py3-none-any.whl:

Publisher: release.yml on holaPymbu/fact

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page