🧬 FIA HARNESS
AI agents don't fail at writing code — they fail at staying on track. FIA Harness turns "spec, discipline and no fake results" from good intentions into merge checks the agent cannot silently skip — inside your Git + CI trust boundary. Local, zero-dependency, LLM-agnostic.
Python 3.8+ · Zero external dependencies · Single or multi-agent · 2 working modes · Rules verified in CI · LLM-agnostic (Claude, DeepSeek, GPT, OpenCode — whatever agent you use)
In one sentence: a local-first governance harness for AI-assisted software development — a handbrake, not a quality autopilot. It does not write code for you and it does not judge how good your code is: it makes the project's state verifiable and keeps the human in control of what gets merged.
📖 Español: README.es.md
⚡ What problem does it solve
An agent with a spec and a conscience still drifts: it closes a phase it never finished, relaxes its own rules, or writes a report full of tests that never ran. Chat prompts and "trust me" workflows can't stop that.
FIA Harness makes the project state a machine-validated datum and refuses to let the agent self-certify in silence:
| Raw prompts | Closed SaaS | FIA Harness | |
|---|---|---|---|
| Where it runs | your chat | someone's cloud | your machine |
| Spec before code | you hope so | vendor opinion | enforced |
| Rules have teeth | ❌ | partially | ✅ merge checks |
| Secrets leave your repo | ❌ | maybe | never |
| Cost | per token | subscription | free, local |
The full history is never re-sent: each phase loads only a handful of compressed control files. Small context = cheaper, faster answers with less drift.
⚡ Install in one command
uvx fia-harness init # or: pipx run fia-harness init
Sets up a new project instantly: kit templates in /docs, thin root facades
(bootstrap.py, task_generator.py) and a starter PRD.md. Then
python bootstrap.py and you're on rails. Prefer cloning? This repo is a
GitHub template — click Use this template.
🎬 See the interlock catch the agent (60 seconds)
The rules here are not advice — they are merge checks that no agent can skip.
The fia-harness-demo repo is
a real, small project whose CI blocks a cheater agent that tries to close a phase
without its task file, its checkpoint or verifiable evidence:
git clone https://github.com/mcpedrogm-art/fia-harness-demo.git && cd fia-harness-demo
pip install fia-harness
fia verify # ✅ PASS — merge eligible
cp PROGRESS.F2_tampered.md PROGRESS.md # Windows: copy ...
fia verify # ❌ exit 1 — the merge is blocked
🧭 The mental model (3 steps)
1. THINK — PRD → interview (M1) → SPEC.md approved by a human (M2). No code yet.
2. PLAN — the spec is sliced into small verifiable phases F0…Fn (M3).
3. BUILD — one phase = one task = one closed cycle: audit → design → code → verify.
Every transition leaves a validated artifact: PROGRESS.md is the editing
surface, progress.json is the compiled truth the CI reads. Editing the Markdown
without re-compiling turns CI red.
⚙️ How it works: three engines
1️⃣ Process phases (M0–M3) — think before building
| Phase | What happens | Deliverable |
|---|---|---|
| M0 | bootstrap.py reads the PRD and activates the harness |
CONTEXT.md + PROGRESS.md + templates |
| M1 | The agent interviews you: stack, DB, security, visibility, UI/UX, Skills/MCP | SECURITY.md and AEO_GEO_SEO.md filled in |
| M2 | The agent writes the technical spec (SDD) | SPEC.md approved by a human |
| M3 | The plan is split into small, verifiable phases | F0-Fn table pasted into PROGRESS.md |
🚫 Until M3 closes, not a single line of production code is written.
2️⃣ Execution phases (F0–Fn) — build phase by phase
Each planned phase = one task = one complete, closed cycle. Typical plan:
| Phase | Objective | Deliverable |
|---|---|---|
| F0 | Repo bootstrap, tooling, CI | Working repo |
| F1 | Data model + migrations | Versioned DB |
| F2 | Backend core | Minimal API |
| F3 | Frontend core | Navigable UI |
| F4 | Auth and permissions | Login/roles |
fia task auto-detects the first pending phase and generates its
task. You decide when to start the next one; the agent never chains phases alone.
3️⃣ The task cycle (A–L) — discipline inside every phase
A. Audit → B. Design → C. Hypotheses → E. Implementation → F. Edge cases
→ I. Tests → J2. Security → H2. Visibility → H3. UI/UX → K. Validation → L. Report
Security (J2), visibility (H2) and UI/UX (H3) are injected automatically only if
the phase needs them, with the real, living content of your SECURITY.md,
AEO_GEO_SEO.md and UI_UX_EXCLUSIVA.md. If they don't apply, the generator says
so explicitly — never omitted in silence.
🚀 Getting started in 4 steps
⚡ Or in one command (PyPI):
uvx fia-harness initmounts the new project automatically — templates in/docs, scripts at the root, starterPRD.md. Skip to step 2.
1. Prepare the new project
├── pip install fia-harness (root scripts are thin facades: they import the package)
├── bootstrap.py + task_generator.py at the root
├── /docs with the master templates
├── (optional) RAG_VECTOR_EXTENSION.md inside /docs if there will be semantic search
└── PRD.md at the root
2. python bootstrap.py → automatic Phase M0
Generates CONTEXT.md, PROGRESS.md, progress.json, DECISIONS.md,
activates the templates and emits .github/workflows/harness.yml
3. Open your agent with the folder → the interview starts (M1)
The agent reads CONTEXT.md and does NOT code anything yet.
4. Approve SPEC.md, paste the F0-Fn table into PROGRESS.md and compile:
fia sync → validates the state into progress.json (schema 3.0)
fia task → generates the task for the pending phase
fia run -- <your tests> → records evidence (EV-NNN, hashed artifacts)
fia receipt create F0 --tests N/N → phase receipt (rule #16): canonical manifest + hash
fia verify → merge gate: state + evidence + provenance + receipts
📖 Full protocol: templates/INICIO_PROYECTO.md (ES) · Spanish overview: README.es.md
📁 File map
In a user project the templates live at the root (copied by
fia init/bootstrap.py). In this repo they live undertemplates/, and the repo's own governed project lives undergovernance/.
| File | What it is |
|---|---|
⚙️ bootstrap.py · 🤖 task_generator.py |
Thin facades at the project root: the implementation lives in the installed package (ADR-001) |
📦 fia_harness/ + pyproject.toml |
PyPI package and single source of truth: fia init/check/sync/task/status/approve/seal/reopen/run/evidence/receipt/route/verify |
🗂️ templates/ |
Master templates of the kit: protocol (INICIO_PROYECTO.md), SECURITY.md, AEO_GEO_SEO.md, UI_UX_EXCLUSIVA.md, UI_RECIPES.md, UI_ASSETS.json, SKILLS_MCP.md, TASK_TEMPLATE.md, TASK_LITE_TEMPLATE.md, QUICKSTART_LITE.md, AGENTS.md, PRD_TEMPLATE.md, MODELOS.md and the RAG module |
🏛️ governance/ |
This repo's own dogfood project (operated with -d governance): PROGRESS.md, SPEC.md, DECISIONS.md, progress.json, TASK-F0…F11.md, evidence/ (incl. phase receipts) |
📖 docs/ |
v3 baseline (V3_BASELINE.md), the evidence-capture decision (ADR-005) and the v3.3 plan/design (PLAN_RECIBO_ROUTER.md, RECEIPT_DESIGN.md, RECEIPT_ROUTER.md) |
🧪 tests/ |
Automated tests of the parsers, the state machine, evidence, verification, packaging and the full cycle |
📜 CHANGELOG_FIXES.md |
History of fixes applied and how they were verified |
⚡ Two working modes
| 🔵 Full | ⚡ Lite | |
|---|---|---|
| For | MVPs, real products | Prototypes, vertical slices, bounded changes |
| Documentation | CONTEXT + SPEC + PROGRESS + DECISIONS |
Just QUICK_CONTEXT.md |
| Tasks | TASK-Fx.md from TASK_TEMPLATE.md |
TASK-QUICK.md from TASK_LITE_TEMPLATE.md |
| Security, human approval | ✅ Always | ✅ Always (never negotiable) |
Automatic promotion to Full if any of these appear: auth/roles, payments, PII/health, critical migrations, writes to external services, deploy/secrets, uncertain scope. Promotion keeps the already-validated work.
To enable Lite: declare
Modo de trabajo: LiteinCONTEXT.md(detected automatically bytask_generator.py) or force it with--lite.
🧩 Conditional modules
The base harness is common; these layers activate only when a project needs them:
| Condition | Module activated |
|---|---|
| The PRD mentions RAG, embeddings, semantic search or vector memory | RAG_VECTOR_EXTENSION.md — detected and copied by bootstrap.py |
| There are public indexable pages (landing, blog, docs) | AEO_GEO_SEO.md + Phase H2 in content tasks |
| There is a user interface | UI_UX_EXCLUSIVA.md + approved Design DNA before implementing |
| The project is multi-agent | AGENTS.md with roles and handoff protocol |
🚨 Enforcement: the rules have teeth
Since v3, the harness enforces by infrastructure, not just by convention.
bootstrap.py emits a GitHub Actions workflow that runs fia verify on every
push and PR:
| Golden rule | How it's mechanically enforced |
|---|---|
| Never close phases with open dependencies (#4) | Validated progress.json: closing F2 with F1 open breaks the build |
| Never close a phase without a Definition of Done (#5) | Every done phase requires its context checkpoint in PROGRESS.md |
| Never close a phase without real evidence (#7) | Every done F phase requires a raw validation block, Evidencia: <file> or Evidencia: EV-NNN (chain validated) |
| Never invent results (#7) | fia run evidence is hashed: editing an evidence/EV-*.txt artifact turns PROVENANCE red; CI artifact digests mark it trusted |
Never run a phase without its TASK-Fx.md (#7) |
The validator requires TASK-F<N>.md for every closed F phase |
| Never rewrite the rules (#2) | Normative docs are sealed (SHA-256); editing them turns CI red until --seal |
| Never drift the spec without approval (#6) | SPEC.md is snapshotted; changing it without --approval turns CI red |
| Never commit secrets (#8) | gitleaks scans the full history on every push |
| No dependencies with known vulnerabilities | npm audit / pip-audit according to the detected stack |
| Mandatory tests before closing a phase | CI job with pytest/unittest or npm test, whatever it detects |
| Traceable human approvals | Every APPROVAL-NNN cited in a TASK must exist in DECISIONS.md |
State flow: PROGRESS.md is the editing surface (human or agent);
fia sync compiles and validates it into progress.json. If you edit the
Markdown by hand and don't compile, CI turns red until you run fia sync.
And fia sync is fail-closed: if the state violates a rule, it writes nothing.
fia sync # compile & validate PROGRESS.md -> progress.json
fia verify # merge gate: state + dependencies + evidence + provenance + receipts + seals + spec
fia run -- pytest -q # execute + record evidence (EV-NNN, hashed artifacts)
fia evidence --ingest manifest.json # anchor CI artifact digests (trusted provenance)
fia seal / fia approve / fia reopen # seals, human approvals, audited reopen
fia receipt create F3 --tests 42/42 # phase receipt (rule #16): canonical manifest + hash
fia receipt verify F3 # recompute and check the receipt (always strict)
fia route "fix typo in docs" # deterministic Lite/Full proposal (fail-closed, v3.3)
fia assets fetch UI_ASSETS.json # download + verify the UI asset pack (v3.5)
fia verify --strict-receipts # CI: dirty (uncommitted) receipts block the merge
fia verify --reproduce EV-001 # re-runs allowlisted evidence and compares output (opt-in)
fia verify --scope-base origin/main # post-hoc scope: diff vs the TASK's declared scope
The v2.2 flags (
python task_generator.py --sync/--check/--seal/--approval/--reopen) still work through the facade — old projects and CI files keep running unchanged.
🆕 What v3 adds
| v2.2 | v3.0 | |
|---|---|---|
| State | harness-state/1 |
schema 3.0: stable IDs, timestamps, drift fingerprint + integrity hash, migration with .bak backup |
| Evidence | pasted block or file (existence) | EV-NNN records: command, exit code, timestamps, environment, hashed artifacts |
| Verification | --check |
fia verify: STATE · DEPENDENCIES · EVIDENCE · PROVENANCE · SEALS · SPEC SNAPSHOT |
| Provenance | — | local vs trusted (CI platform artifact digest, ADR-005) |
| PRD parsing | binary regex | confidence levels (high/medium/none) + versioned synonyms + regression corpus |
| Distribution | copyable scripts | package + thin facades (pip install fia-harness) |
| Scope | — | post-hoc: the diff must match the TASK's declared scope (fia verify --scope-base) |
| Reproduction | — | opt-in: fia verify --reproduce re-runs allowlisted commands and compares output |
🧾 What v3.3 adds
| v3.2 | v3.3 | |
|---|---|---|
| Phase closure | evidence + Definition of Done | receipt: canonical manifest (file hashes + checks) bound to a commit; tampering after closure is detectable |
| Receipts in CI | — | fia verify --strict-receipts: dirty (uncommitted) receipts block the merge |
| Lane choice | manual Lite/Full | fia route: deterministic proposal with reasons, fail-closed (risk or ambiguity → Full) |
Honest limit: a receipt binds content, not truth. It proves which files and checks existed at closure and anchors them to a commit; it cannot prove that the claimed test results are true. Locally you can re-emit a
dirtyreceipt against your working tree; CI only accepts clean ones.
🧭 What v3.4 adds
| v3.3 | v3.4 | |
|---|---|---|
| UI/UX directions | free-form "three directions" | four divergent directions with fixed roles (safe, opposite composition, interaction/motion, unexpected archetype) |
| Divergence check | — | recipe schema (12 fields) + divergence matrix (6 axes): extreme in ≥3 axes, no pair sharing >2, self-check before showing |
| Project artifact | — | UI_RECIPES.md records the recipes, the matrix and the human decision |
Honest limit: this is a method for the agent, not a mechanical gate yet (deferred to v3.5, ADR-011). Concrete reference recipes live in a private local library (
*.local.md, not distributed); the public kit ships the schema and the flow, and assets are always self-hosted.
📦 What v3.5 adds
| v3.4 | v3.5 | |
|---|---|---|
| UI assets | manual (download and copy) | fia assets fetch: manifest-driven pack (UI_ASSETS.json) with SHA-256 verification, idempotent and opt-in |
| Complete setup | — | fia init --assets <url>: project + asset pack in one step |
| Publishing | — | fia assets manifest generates the manifest (path/url/sha256) for your own hosting |
The kit never bundles third-party media: the mechanism is public (MIT), the content lives where you have distribution rights (e.g. a self-hosted bucket). See
docs/UI_ASSETS.md.Official pack (maintained by PGMIA): media + recipes in one command —
fia init --assets https://supabase.pgmia.es/storage/v1/object/public/fia-assets/UI_ASSETS.json
🛡️ The rules that never break
- 🚫 Never code without an approved spec — not a line before M3.
- 🗣️ Never assume in silence — every assumption is declared and confirmed.
- 📦 Never re-send unnecessary context — the control files are the compressed source.
- ✅ Never close a phase without its Definition of Done — and never mix phases.
- 🔐 Never close a security phase without its checklist — security is not postponed to a final audit.
- 🙋 Never install/search/connect a Skill, MCP or library without human approval — silence is not permission.
- 🧪 Never invent results — tests that didn't run don't exist.
- 🛑 Never commit/push/deploy without explicit authorization.
- 🧾 Never close an F phase without its verifiable receipt — the manifest (files + checks) is bound to a commit.
🚨 Since v3, rules 4, 5, 7, 8 and 9 are also verified automatically in CI on every project that starts with
bootstrap.py(previous section). Rule 5 is enforced as a recorded human decision on risk phases (v3.1); rule 8 via gitleaks; rule 9 withfia verify --strict-receipts.
⚠️ Limitations — what the CI cannot guarantee
FIA is a handbrake, not a quality autopilot. It makes dishonest state detectable and expensive; it does not judge quality. The boundary, explicitly:
| ✅ FIA guarantees | ❌ FIA does not guarantee | 🙋 The human must |
|---|---|---|
A phase cannot close dishonestly: dependencies, Definition of Done, TASK-Fx.md and evidence are checked mechanically |
That the code, the architecture or the SPEC are good | Own the quality decisions: spec review, architecture, priorities |
Evidence has integrity (hashes) and provenance (local vs trusted with the CI artifact digest) |
Independent reproduction of every result (opt-in, roadmap v3.2) | Review the evidence that matters — risk phases require a recorded human decision (v3.1) |
| Silent edits to normative docs, the spec or the state are detectable (seals, snapshots, integrity hash) | A sandbox: the agent shares the filesystem and shell | Keep the trust boundary where it belongs: Git + CI, not the agent's word |
| Merge is blocked when the state is not verifiable | Runtime behavior, performance, product-market fit | Write down what "done" means; FIA only checks that you did |
The harness raises the cost of drifting from trivial to deliberate and traceable, but it is not a tamper-proof boundary. Be aware of its edges:
- It trusts the machine, not the person. The agent and the validator share the same local filesystem and shell. A malicious actor with full write access could re-seal a doc or fabricate evidence. The harness makes that detectable and awkward, not impossible.
- Approvals are conversational, not cryptographic.
--approvalfreezes a snapshot ofSPEC.md, but the approval entry itself can still be authored by the agent. Git-authority signing is a planned option, not yet the default. - Evidence provenance is real, not magic.
fia runrecords are bound to hashed artifacts, so editing evidence is detectable; plain pasted blocks are still "existence only". Locally you own the machine, so a fabricated record can pass —trustedprovenance requires the CI platform's artifact digest (ADR-005). - Receipts bind content, not truth. The phase receipt (v3.3) hashes the final
files and checks against a commit, so post-closure tampering is detectable; it
does not prove the checks ran as claimed.
dirtyreceipts are local anchors until you commit and re-emit them (fia verify --strict-receiptsenforces clean ones). - Local-first trust model. There is no cloud, no telemetry and no remote authority — the trade-off of never sending your code anywhere.
These limits are the honest boundary of a kit that runs on your machine with your rules. For a solo dev + agent building MVPs, they are the right trade.
🐕 Dogfooding
This repository is governed by the kit it ships:
- The badge above is this repo's own CI: 282 tests, a self-application job
(
fia-harness init→bootstrap.py→--checkon a fresh temp project) and a governance job that runsfia verify --strict-receiptson this repo itself — its own evidence records (EV-001…EV-009) and phase receipts (F9,F10) are revalidated on every push. - The
fia-harness-demorepo is generated with the kit and its golden-rules CI catches the cheater agent live.
✅ Verify the kit
python -m unittest discover tests -v
The tests cover the PROGRESS.md parser, the PRD parser with confidence levels
(81% resolved over a 20-PRD corpus), marker-based injectors, keyword heuristics,
the state machine 3.0 (fingerprints, integrity, migration with backup,
dependencies, checkpoints, evidence, approvals, seals, spec snapshot, fail-closed,
reopen), the evidence engine (hashed artifacts, tamper detection, CI digests),
the verification engine (PASS/FAIL report, risk gate, scope, reproduction,
receipts), the phase receipt (canonical hash, determinism, tampering, CRLF/BOM,
grandfathering) and the lane router (risk → Full, allowlist → Lite, fail-closed)
plus the packaging (facades, init e2e, cp1252 consoles) and a complete e2e
cycle in a temp folder.
In a bootstrapped project, check its state at any time:
fia verify # full report — the CI gate
fia check # legacy state-only validation
📜 Documentation and sources of truth
| Document | Role |
|---|---|
README.md (this file) |
Index and system overview (English) |
README.es.md |
The same overview in Spanish |
INICIO_PROYECTO.md |
Source of truth of the protocol — if anything diverges, this one rules |
AGENTS.md |
Native agent governance: startup, 3×3 interview, approval guardrail, PRD amendment |
CHANGELOG_FIXES.md |
Version history: what changed, why and how it was verified |
📄 License
MIT — see LICENSE. The kit is yours: local, auditable, no cloud, no telemetry, no accounts.
Metadata
Release files for fia-harness 3.5.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fia_harness-3.5.1.tar.gz | 151.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fia_harness-3.5.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 290.5 kB
Release files / fia_harness-3.5.1.tar.gz
| Download URL | fia_harness-3.5.1.tar.gz |
|---|---|
| Size | 151.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0fa6ba22e93a11f7f73512a879f9eb78b32cec4f069ef5532cb3bdf93bef38dd
|
|
BLAKE2b-256 checksum How to use checksums |
18132392b1438abf2e7f027ff38128358443c335019b0ef38205eb981445daf2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logRelease files / fia_harness-3.5.1-py3-none-any.whl
| Download URL | fia_harness-3.5.1-py3-none-any.whl |
|---|---|
| Size | 139.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d58658205536248213c83178798fa90ebc4da36dd2ee4c68438474f68293936d
|
|
BLAKE2b-256 checksum How to use checksums |
abc2aaabdd90e9fcff7bafa784e97d2705d1303239d1f7bb8e6f8a1ea58acdee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency log