fable-engine 1.3.4__tar.gz → 1.3.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fable_engine-1.3.4/fable_engine.egg-info → fable_engine-1.3.6}/PKG-INFO +53 -14
- {fable_engine-1.3.4 → fable_engine-1.3.6}/README.md +52 -13
- fable_engine-1.3.6/docs/ai-evidence-adjudicator.md +119 -0
- fable_engine-1.3.6/docs/stop-ai-agents-writing-too-early.md +139 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/actions/__init__.py +4 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/actions/deliberation.py +48 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/actions/fleet.py +32 -9
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/actions/lifecycle.py +14 -1
- fable_engine-1.3.6/fable_engine/adjudicator.py +509 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/fable_session.json +130 -33
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/schema.py +68 -15
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/scrapers/base.py +1 -1
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/server.py +3 -1
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/session.py +39 -2
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/test_server.py +14 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6/fable_engine.egg-info}/PKG-INFO +53 -14
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine.egg-info/SOURCES.txt +6 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_mode/__init__.py +1 -1
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_mode/manifest.py +1 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_mode/resources.json +1 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/design_engine.py +153 -109
- fable_engine-1.3.6/fable_v2/coder_fleet/sandbox_executor.py +314 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/cortical/plasticity_engine.py +46 -7
- {fable_engine-1.3.4 → fable_engine-1.3.6}/pyproject.toml +1 -1
- {fable_engine-1.3.4 → fable_engine-1.3.6}/rules/AGENTS.md +1 -1
- {fable_engine-1.3.4 → fable_engine-1.3.6}/rules/fable-mode.md +1 -1
- {fable_engine-1.3.4 → fable_engine-1.3.6}/setup.py +1 -1
- fable_engine-1.3.6/skills/fable-mode/SKILL.md +131 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/cortex/frontend_design.md +28 -109
- fable_engine-1.3.6/skills/fable-mode/references/design-system.md +102 -0
- fable_engine-1.3.6/tests/test_adjudicator.py +358 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_design_engine.py +22 -6
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_hebbian_plasticity.py +4 -1
- fable_engine-1.3.6/tests/test_red_team_seal_path.py +297 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_red_team_swarm.py +30 -14
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_stealth_browser.py +20 -0
- fable_engine-1.3.4/docs/stop-ai-agents-writing-too-early.md +0 -80
- fable_engine-1.3.4/skills/fable-mode/SKILL.md +0 -142
- {fable_engine-1.3.4 → fable_engine-1.3.6}/LICENSE +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/MANIFEST.in +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/docs/fable-v1-v2-migration.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/docs/fable-v2-architecture.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/docs/system3-architecture.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_compressor.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/__init__.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/actions/cas.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/actions/scrapers.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/actions/system3.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/browser.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/cas.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/guards.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/scrapers/__init__.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/scrapers/arxiv.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/scrapers/github.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/scrapers/reddit.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/scrapers/web.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/scrapers/x.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/scrapers/youtube.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine/updater.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine.egg-info/dependency_links.txt +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine.egg-info/entry_points.txt +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_engine.egg-info/top_level.txt +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_mode/__main__.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_mode/adapters.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_mode/installer.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_mode/launcher.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_mode/safety.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_mode/skill_bundle.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_mode_entry.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/__init__.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/adapters.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/__init__.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/ast_tools.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/compute.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/diagnostics.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/fleet_dispatcher.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/mock_auditor.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/mutation.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/property_oracle.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/receipt_attestor.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/red_team_swarm.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/test_harness.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/vector_engine.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/visual.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/coder_fleet/workspace.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/cortical/__init__.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/execution_broker.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/proof_engine.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/protocol.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/runtime.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/system3/__init__.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/system3/causal.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/system3/dialectical.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/system3/evolution.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/system3/executive.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/system3/free_energy.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/system3/hyperbolic.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/system3/induction.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/system3/kripke.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/system3/oracle.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/fable_v2/verifiers.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/rules/GEMINI.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/setup.cfg +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/cortex/concurrency.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/cortex/design_3d.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/cortex/process.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/cortex/python.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/cortex/research.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/cortex/rust.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/cortex/security.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/cortex/synaptic_matrix.json +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/cortex/system.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/cortex/target.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/examples/autonomous-agentic-migration.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/examples/breakthrough-algorithm-synthesis.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/examples/deepthink-analysis-proof.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/examples/distributed-system-design.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/examples/swe-bench-pro-debugging.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/examples/weak_model_ollama_setup.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/aaa-threejs-game-engine.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/adversarial-code-review-swarm.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/agentic-execution.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/anti-slop-frontend-architecture.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/architectural-blueprinting.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/cinematic-design-engine.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/cognitive-protocol.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/deepthink-mode.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/design-tokens-and-typographies.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/goal-rubric-and-pipeline-automation.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/hebbian-cortical-plasticity.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/innovation-engine.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/interleaved-verification.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/model-velocity-calibration.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/prompt-scaffolds.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/proof-architecture.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/svg-craft-and-vector-design.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/system2-session-engine.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/system3-meta-cognition.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/visual-imagination-engine.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/skills/fable-mode/references/weak-model-frontier-uplift.md +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/__init__.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_anti_loop_circuit_breaker.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_auto_updater.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_coder_fleet.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_delegation_compiler.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_descriptor_boundaries.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_epistemic_evidence_validator.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_execution_broker.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_fable_v2.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_fleet_transitions.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_fsm_redteam_evolution.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_goal_rubric_and_pipeline.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_packaging_runtime.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_proof_engine.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_redteam_remediation.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_registration_transaction.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_requested_regressions.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_scrapers.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_server_actions.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_server_frontier_actions.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_server_protocol.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_skill_distribution.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_system3.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_system3_deep_integration.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_system3_frontier.py +0 -0
- {fable_engine-1.3.4 → fable_engine-1.3.6}/tests/test_vector_engine.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: fable-engine
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.6
|
|
4
4
|
Summary: Independent deterministic System 2 cognitive engine and mechanical time-lock MCP server
|
|
5
5
|
Author: REX-codebase
|
|
6
6
|
License: MIT License
|
|
@@ -85,24 +85,49 @@ mechanical, not prompt advice: no timer, no proof, no write access.
|
|
|
85
85
|
<img src="./assets/flow-simple.svg" width="720" alt="Think → Prove → Attack → Write"/>
|
|
86
86
|
</div>
|
|
87
87
|
|
|
88
|
+
### Demo
|
|
89
|
+
|
|
90
|
+
**KERR // ORRERY**
|
|
91
|
+
|
|
92
|
+
One self-contained HTML file. Raw WebGL, zero libraries, zero external assets,
|
|
93
|
+
and zero build step.
|
|
94
|
+
|
|
95
|
+
https://github.com/user-attachments/assets/8287bbfe-e3ee-4dcf-ba0f-f9ff22ae79bd
|
|
96
|
+
|
|
97
|
+
<sub>7 renders rejected before final · 2 bugs caught · 10/10 red-team probes passed</sub>
|
|
98
|
+
|
|
99
|
+
<br/>
|
|
100
|
+
|
|
101
|
+
**Fable Mode overview**
|
|
102
|
+
|
|
88
103
|
https://github.com/user-attachments/assets/27f4f8a2-b1bb-4398-a08c-bc9fd93d69d7
|
|
89
104
|
|
|
90
105
|
<br/>
|
|
91
106
|
|
|
92
|
-
###
|
|
107
|
+
### Quick start
|
|
93
108
|
|
|
94
109
|
A session starts locked. Confidence does not unlock it.
|
|
95
110
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
111
|
+
1. Install the MCP server using one of the options below.
|
|
112
|
+
2. Add the optional Agent Skill if you want the full workflow.
|
|
113
|
+
3. Ask your agent to use Fable Mode for a concrete coding task and choose a time budget.
|
|
99
114
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
115
|
+
A new session starts with execution locked:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"action": "create_session",
|
|
120
|
+
"session_name": "demo-refactor",
|
|
121
|
+
"objective": "Refactor the parser without changing public behavior",
|
|
122
|
+
"time_budget_minutes": 2
|
|
123
|
+
}
|
|
104
124
|
```
|
|
105
125
|
|
|
126
|
+
The agent then records evidence and an invariant. An early `unlock_execution`
|
|
127
|
+
request is rejected until the authority timer and proof prerequisites pass.
|
|
128
|
+
Use `get_status` at any point to see the active phase, remaining time, evidence
|
|
129
|
+
counts, and lock state.
|
|
130
|
+
|
|
106
131
|
The same gates guard every phase: evidence receipts for claims, a five-vector
|
|
107
132
|
red-team swarm for code, and a sealed record of what was verified.
|
|
108
133
|
|
|
@@ -116,7 +141,7 @@ pip install fable-engine
|
|
|
116
141
|
|
|
117
142
|
Or install the MCP server in your editor:
|
|
118
143
|
|
|
119
|
-
[](vscode:mcp/install?%7B%22name%22%3A%22fable-engine%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22fable-engine%3D%3D1.3.
|
|
144
|
+
[](vscode:mcp/install?%7B%22name%22%3A%22fable-engine%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22fable-engine%3D%3D1.3.6%22%2C%22fable-engine%22%5D%7D)
|
|
120
145
|
[](cursor://anysphere.cursor-deeplink/mcp/install?name=fable-engine&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJmYWJsZS1lbmdpbmU9PTEuMy4zIiwiZmFibGUtZW5naW5lIl19)
|
|
121
146
|
|
|
122
147
|
These links configure Fable Engine for AI agents in VS Code Chat or Cursor. They do not install a standalone editor extension. Both use `uvx`, which downloads and runs the pinned PyPI release in an isolated environment.
|
|
@@ -124,13 +149,13 @@ These links configure Fable Engine for AI agents in VS Code Chat or Cursor. They
|
|
|
124
149
|
Point your agent at the MCP server manually:
|
|
125
150
|
|
|
126
151
|
```jsonc
|
|
127
|
-
// Claude Code: claude mcp add fable-engine -- uvx --from fable-engine==1.3.
|
|
152
|
+
// Claude Code: claude mcp add fable-engine -- uvx --from fable-engine==1.3.6 fable-engine
|
|
128
153
|
// Cursor: ~/.cursor/mcp.json
|
|
129
154
|
{
|
|
130
155
|
"mcpServers": {
|
|
131
156
|
"fable-engine": {
|
|
132
157
|
"command": "uvx",
|
|
133
|
-
"args": ["--from", "fable-engine==1.3.
|
|
158
|
+
"args": ["--from", "fable-engine==1.3.6", "fable-engine"]
|
|
134
159
|
}
|
|
135
160
|
}
|
|
136
161
|
}
|
|
@@ -152,7 +177,7 @@ The complete skill tree ships inside the wheel. To install it into your
|
|
|
152
177
|
project's skills directory (the cross-client `.agents/skills/` convention):
|
|
153
178
|
|
|
154
179
|
```bash
|
|
155
|
-
uvx --from fable-engine==1.3.
|
|
180
|
+
uvx --from fable-engine==1.3.6 fable-mode install-skill --yes
|
|
156
181
|
```
|
|
157
182
|
|
|
158
183
|
This copies the skill to `.agents/skills/fable-mode`. Preview first with
|
|
@@ -170,6 +195,18 @@ agent afterwards so it picks up the skill.
|
|
|
170
195
|
|
|
171
196
|
<br/>
|
|
172
197
|
|
|
198
|
+
### Optional: AI evidence adjudicator
|
|
199
|
+
|
|
200
|
+
The evidence in a session is written by an AI agent, so Fable can optionally
|
|
201
|
+
ask an external reviewer model to audit that evidence before the workspace
|
|
202
|
+
unlocks. Stdlib-only, one bounded HTTPS call, no local model, no extra RAM to
|
|
203
|
+
speak of. Off by default; fail-closed when enforcing. It raises the cost of
|
|
204
|
+
fabricated proof - it cannot guarantee deception is impossible, and the
|
|
205
|
+
mechanical gates stay the primary authority. Setup and honest limits:
|
|
206
|
+
[AI evidence adjudicator](./docs/ai-evidence-adjudicator.md).
|
|
207
|
+
|
|
208
|
+
<br/>
|
|
209
|
+
|
|
173
210
|
### What it is not
|
|
174
211
|
|
|
175
212
|
- Not a claim of flawless code. It is a checkable workflow, not a guarantee.
|
|
@@ -180,10 +217,12 @@ agent afterwards so it picks up the skill.
|
|
|
180
217
|
|
|
181
218
|
### Docs
|
|
182
219
|
|
|
220
|
+
- [Start here: practical guide](./docs/stop-ai-agents-writing-too-early.md)
|
|
221
|
+
- [Agent Skill reference](./skills/fable-mode/SKILL.md)
|
|
183
222
|
- [V1 → V2 migration](./docs/fable-v1-v2-migration.md)
|
|
184
223
|
- [V2 architecture](./docs/fable-v2-architecture.md)
|
|
185
224
|
- [System 3 (experimental)](./docs/system3-architecture.md)
|
|
186
|
-
- [
|
|
225
|
+
- [AI evidence adjudicator (optional)](./docs/ai-evidence-adjudicator.md)
|
|
187
226
|
|
|
188
227
|
<br/>
|
|
189
228
|
|
|
@@ -42,24 +42,49 @@ mechanical, not prompt advice: no timer, no proof, no write access.
|
|
|
42
42
|
<img src="./assets/flow-simple.svg" width="720" alt="Think → Prove → Attack → Write"/>
|
|
43
43
|
</div>
|
|
44
44
|
|
|
45
|
+
### Demo
|
|
46
|
+
|
|
47
|
+
**KERR // ORRERY**
|
|
48
|
+
|
|
49
|
+
One self-contained HTML file. Raw WebGL, zero libraries, zero external assets,
|
|
50
|
+
and zero build step.
|
|
51
|
+
|
|
52
|
+
https://github.com/user-attachments/assets/8287bbfe-e3ee-4dcf-ba0f-f9ff22ae79bd
|
|
53
|
+
|
|
54
|
+
<sub>7 renders rejected before final · 2 bugs caught · 10/10 red-team probes passed</sub>
|
|
55
|
+
|
|
56
|
+
<br/>
|
|
57
|
+
|
|
58
|
+
**Fable Mode overview**
|
|
59
|
+
|
|
45
60
|
https://github.com/user-attachments/assets/27f4f8a2-b1bb-4398-a08c-bc9fd93d69d7
|
|
46
61
|
|
|
47
62
|
<br/>
|
|
48
63
|
|
|
49
|
-
###
|
|
64
|
+
### Quick start
|
|
50
65
|
|
|
51
66
|
A session starts locked. Confidence does not unlock it.
|
|
52
67
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
68
|
+
1. Install the MCP server using one of the options below.
|
|
69
|
+
2. Add the optional Agent Skill if you want the full workflow.
|
|
70
|
+
3. Ask your agent to use Fable Mode for a concrete coding task and choose a time budget.
|
|
56
71
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
72
|
+
A new session starts with execution locked:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"action": "create_session",
|
|
77
|
+
"session_name": "demo-refactor",
|
|
78
|
+
"objective": "Refactor the parser without changing public behavior",
|
|
79
|
+
"time_budget_minutes": 2
|
|
80
|
+
}
|
|
61
81
|
```
|
|
62
82
|
|
|
83
|
+
The agent then records evidence and an invariant. An early `unlock_execution`
|
|
84
|
+
request is rejected until the authority timer and proof prerequisites pass.
|
|
85
|
+
Use `get_status` at any point to see the active phase, remaining time, evidence
|
|
86
|
+
counts, and lock state.
|
|
87
|
+
|
|
63
88
|
The same gates guard every phase: evidence receipts for claims, a five-vector
|
|
64
89
|
red-team swarm for code, and a sealed record of what was verified.
|
|
65
90
|
|
|
@@ -73,7 +98,7 @@ pip install fable-engine
|
|
|
73
98
|
|
|
74
99
|
Or install the MCP server in your editor:
|
|
75
100
|
|
|
76
|
-
[](vscode:mcp/install?%7B%22name%22%3A%22fable-engine%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22fable-engine%3D%3D1.3.
|
|
101
|
+
[](vscode:mcp/install?%7B%22name%22%3A%22fable-engine%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22fable-engine%3D%3D1.3.6%22%2C%22fable-engine%22%5D%7D)
|
|
77
102
|
[](cursor://anysphere.cursor-deeplink/mcp/install?name=fable-engine&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJmYWJsZS1lbmdpbmU9PTEuMy4zIiwiZmFibGUtZW5naW5lIl19)
|
|
78
103
|
|
|
79
104
|
These links configure Fable Engine for AI agents in VS Code Chat or Cursor. They do not install a standalone editor extension. Both use `uvx`, which downloads and runs the pinned PyPI release in an isolated environment.
|
|
@@ -81,13 +106,13 @@ These links configure Fable Engine for AI agents in VS Code Chat or Cursor. They
|
|
|
81
106
|
Point your agent at the MCP server manually:
|
|
82
107
|
|
|
83
108
|
```jsonc
|
|
84
|
-
// Claude Code: claude mcp add fable-engine -- uvx --from fable-engine==1.3.
|
|
109
|
+
// Claude Code: claude mcp add fable-engine -- uvx --from fable-engine==1.3.6 fable-engine
|
|
85
110
|
// Cursor: ~/.cursor/mcp.json
|
|
86
111
|
{
|
|
87
112
|
"mcpServers": {
|
|
88
113
|
"fable-engine": {
|
|
89
114
|
"command": "uvx",
|
|
90
|
-
"args": ["--from", "fable-engine==1.3.
|
|
115
|
+
"args": ["--from", "fable-engine==1.3.6", "fable-engine"]
|
|
91
116
|
}
|
|
92
117
|
}
|
|
93
118
|
}
|
|
@@ -109,7 +134,7 @@ The complete skill tree ships inside the wheel. To install it into your
|
|
|
109
134
|
project's skills directory (the cross-client `.agents/skills/` convention):
|
|
110
135
|
|
|
111
136
|
```bash
|
|
112
|
-
uvx --from fable-engine==1.3.
|
|
137
|
+
uvx --from fable-engine==1.3.6 fable-mode install-skill --yes
|
|
113
138
|
```
|
|
114
139
|
|
|
115
140
|
This copies the skill to `.agents/skills/fable-mode`. Preview first with
|
|
@@ -127,6 +152,18 @@ agent afterwards so it picks up the skill.
|
|
|
127
152
|
|
|
128
153
|
<br/>
|
|
129
154
|
|
|
155
|
+
### Optional: AI evidence adjudicator
|
|
156
|
+
|
|
157
|
+
The evidence in a session is written by an AI agent, so Fable can optionally
|
|
158
|
+
ask an external reviewer model to audit that evidence before the workspace
|
|
159
|
+
unlocks. Stdlib-only, one bounded HTTPS call, no local model, no extra RAM to
|
|
160
|
+
speak of. Off by default; fail-closed when enforcing. It raises the cost of
|
|
161
|
+
fabricated proof - it cannot guarantee deception is impossible, and the
|
|
162
|
+
mechanical gates stay the primary authority. Setup and honest limits:
|
|
163
|
+
[AI evidence adjudicator](./docs/ai-evidence-adjudicator.md).
|
|
164
|
+
|
|
165
|
+
<br/>
|
|
166
|
+
|
|
130
167
|
### What it is not
|
|
131
168
|
|
|
132
169
|
- Not a claim of flawless code. It is a checkable workflow, not a guarantee.
|
|
@@ -137,10 +174,12 @@ agent afterwards so it picks up the skill.
|
|
|
137
174
|
|
|
138
175
|
### Docs
|
|
139
176
|
|
|
177
|
+
- [Start here: practical guide](./docs/stop-ai-agents-writing-too-early.md)
|
|
178
|
+
- [Agent Skill reference](./skills/fable-mode/SKILL.md)
|
|
140
179
|
- [V1 → V2 migration](./docs/fable-v1-v2-migration.md)
|
|
141
180
|
- [V2 architecture](./docs/fable-v2-architecture.md)
|
|
142
181
|
- [System 3 (experimental)](./docs/system3-architecture.md)
|
|
143
|
-
- [
|
|
182
|
+
- [AI evidence adjudicator (optional)](./docs/ai-evidence-adjudicator.md)
|
|
144
183
|
|
|
145
184
|
<br/>
|
|
146
185
|
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# AI Evidence Adjudicator (optional)
|
|
2
|
+
|
|
3
|
+
An external reviewer model that audits a session's recorded evidence before
|
|
4
|
+
execution unlocks. It exists because the evidence in a Fable session is itself
|
|
5
|
+
written by an AI agent, and an AI agent can fabricate plausible-looking proof.
|
|
6
|
+
|
|
7
|
+
The adjudicator is a second opinion, not a guarantee. See
|
|
8
|
+
[Honest limits](#honest-limits) before relying on it.
|
|
9
|
+
|
|
10
|
+
## What it does
|
|
11
|
+
|
|
12
|
+
Two layers, code first:
|
|
13
|
+
|
|
14
|
+
1. **Deterministic evidence lint** (always local, stdlib, zero network, zero
|
|
15
|
+
extra RAM): flags fabrication-shaped patterns by rule - placeholder text
|
|
16
|
+
(`lorem ipsum`, `TBD`, `TODO`), generic success claims with no artifact
|
|
17
|
+
("it works", "all tests passed"), evidence that restates the claim
|
|
18
|
+
word-for-word (circular), the same evidence recycled across claims, empty
|
|
19
|
+
evidence, failed proof receipts, and padded refinement cycles.
|
|
20
|
+
2. **External reviewer model** (optional, needs an API key): the engine
|
|
21
|
+
bundles the session's evidence into a bounded JSON snapshot and sends it,
|
|
22
|
+
clearly marked as untrusted data, to an external LLM API. The lint's
|
|
23
|
+
findings travel with it as engine-computed ground truth. The model's reply
|
|
24
|
+
is strictly parsed into `pass`, `fail`, or `uncertain`.
|
|
25
|
+
|
|
26
|
+
Flow at `unlock_execution`, after the mechanical gates pass:
|
|
27
|
+
|
|
28
|
+
- The lint runs always. A critical lint finding is a `fail` verdict on its
|
|
29
|
+
own - deterministic findings outrank any model output.
|
|
30
|
+
- Without an API key, the lint alone is the verdict (the receipt records
|
|
31
|
+
`llm_status: skipped_no_api_key`). With a key, the model review runs too,
|
|
32
|
+
and its reply is merged with the lint findings.
|
|
33
|
+
- A receipt (verdict, issues, lint summary, bundle SHA-256, latency) is
|
|
34
|
+
recorded in the session's proof receipts. The API key and full prompt are
|
|
35
|
+
never stored.
|
|
36
|
+
- In `enforcing` mode, anything other than `pass` blocks the unlock.
|
|
37
|
+
In `advisory` mode (default), the receipt is recorded but never blocks.
|
|
38
|
+
|
|
39
|
+
You can also request a review at any time with the `adjudicate_evidence`
|
|
40
|
+
action of `fable_session`.
|
|
41
|
+
|
|
42
|
+
## Resource profile
|
|
43
|
+
|
|
44
|
+
- Stdlib only. No SDK, no embedded model, no GPU.
|
|
45
|
+
- RAM overhead is one JSON payload capped at 24 KB plus the HTTP response.
|
|
46
|
+
- One HTTPS request per adjudication, default 15 s timeout (clamped 3-60 s).
|
|
47
|
+
- Disabled by default: zero network calls and zero behavior change.
|
|
48
|
+
- Enforcing mode works fully offline: the deterministic lint is the gate,
|
|
49
|
+
the external reviewer only deepens it.
|
|
50
|
+
|
|
51
|
+
## Setup
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
export FABLE_ADJUDICATOR_ENABLED=1
|
|
55
|
+
export FABLE_ADJUDICATOR_API_KEY=your_key_here
|
|
56
|
+
# optional
|
|
57
|
+
export FABLE_ADJUDICATOR_STYLE=gemini # gemini (default) | openai
|
|
58
|
+
export FABLE_ADJUDICATOR_MODEL=gemini-2.0-flash
|
|
59
|
+
export FABLE_ADJUDICATOR_MODE=advisory # advisory (default) | enforcing
|
|
60
|
+
export FABLE_ADJUDICATOR_TIMEOUT_SECONDS=15
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `gemini` style calls `https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent`.
|
|
64
|
+
A free AI Studio key works.
|
|
65
|
+
- `openai` style calls an OpenAI-compatible chat-completions endpoint
|
|
66
|
+
(`https://api.openai.com/v1/chat/completions` unless
|
|
67
|
+
`FABLE_ADJUDICATOR_ENDPOINT` overrides it).
|
|
68
|
+
|
|
69
|
+
Start with `advisory`. Read the receipts. Move to `enforcing` only when the
|
|
70
|
+
verdicts are consistently sensible for your workloads.
|
|
71
|
+
|
|
72
|
+
## Failure behavior
|
|
73
|
+
|
|
74
|
+
Fail-closed. Timeouts, HTTP errors, unreachable endpoints, empty replies, and
|
|
75
|
+
malformed model output all resolve to `uncertain`. In enforcing mode,
|
|
76
|
+
`uncertain` blocks the unlock just like `fail`. If the API key is missing, no
|
|
77
|
+
network call is attempted; the deterministic lint still runs and its verdict
|
|
78
|
+
stands on its own.
|
|
79
|
+
|
|
80
|
+
## Injection resistance
|
|
81
|
+
|
|
82
|
+
Evidence is data, not instructions. The bundle is wrapped in explicit
|
|
83
|
+
untrusted-data markers (and any copy of those markers inside the evidence
|
|
84
|
+
itself is scrubbed), the model is told to judge rather than obey, the reply
|
|
85
|
+
must be a strict JSON object, and verdicts outside the known set are rejected.
|
|
86
|
+
The bundle itself is size-capped per field and in total.
|
|
87
|
+
|
|
88
|
+
## Measuring detection quality
|
|
89
|
+
|
|
90
|
+
`benchmarks/adversarial_evidence_benchmark.py` scores the verifier against a
|
|
91
|
+
labeled corpus of fabricated and legitimate evidence snapshots
|
|
92
|
+
(`benchmarks/fixtures/adversarial_cases.json`). Baseline on the seed corpus
|
|
93
|
+
(16 cases): 100% catch rate on fabricated evidence, 0% false flags on
|
|
94
|
+
legitimate evidence - run it yourself:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
python benchmarks/adversarial_evidence_benchmark.py
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
A seed corpus this small proves only that the rules fire. The corpus, not the
|
|
101
|
+
score, is the asset: every new fooling pattern found in the wild must land as
|
|
102
|
+
a fixture, and detection claims are only as strong as the corpus is
|
|
103
|
+
adversarial. `--llm` scores the full two-layer pipeline (one API call per
|
|
104
|
+
case, needs a key).
|
|
105
|
+
|
|
106
|
+
## Honest limits
|
|
107
|
+
|
|
108
|
+
- No verifier can guarantee that no AI will ever fool it. This adjudicator
|
|
109
|
+
raises the cost of fabricated evidence; it does not make deception
|
|
110
|
+
impossible.
|
|
111
|
+
- The reviewer model can be wrong in both directions: it can pass weak
|
|
112
|
+
evidence and fail good evidence.
|
|
113
|
+
- A submission crafted to mislead this specific reviewer can sometimes
|
|
114
|
+
succeed. Rotate models if you depend on this gate.
|
|
115
|
+
- The deterministic lint only knows the patterns it was taught; novel
|
|
116
|
+
fabrication styles slip past it until the benchmark corpus teaches them.
|
|
117
|
+
- The mechanical gates (immutable time-lock, deterministic proof receipts,
|
|
118
|
+
anti-idle refinement cycles) remain the primary authority. The adjudicator
|
|
119
|
+
is one more gate that must agree, never a replacement for the others.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Start here: stop AI coding agents from writing too early
|
|
2
|
+
|
|
3
|
+
AI coding agents often move from a plausible plan to editing files before they have gathered enough evidence. Fable Mode adds a mechanical session gate: the agent can inspect and reason, but the Fable Engine will not report write permission until the configured authority timer and proof prerequisites pass.
|
|
4
|
+
|
|
5
|
+
Fable Mode is two separate pieces:
|
|
6
|
+
|
|
7
|
+
- **Fable Engine** is the MCP server that stores session state and enforces its gates.
|
|
8
|
+
- **The Fable Mode Agent Skill** is the optional workflow that tells a compatible agent how to use those gates.
|
|
9
|
+
|
|
10
|
+
Installing one does not silently activate the other.
|
|
11
|
+
|
|
12
|
+
## Install the engine
|
|
13
|
+
|
|
14
|
+
You need Python 3.10+ and [uv](https://docs.astral.sh/uv/getting-started/installation/).
|
|
15
|
+
|
|
16
|
+
Run the pinned release without changing your global Python environment:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
uvx --from fable-engine==1.3.6 fable-engine
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Claude Code
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
claude mcp add fable-engine -- uvx --from fable-engine==1.3.6 fable-engine
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Cursor or another JSON-configured MCP client
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"mcpServers": {
|
|
33
|
+
"fable-engine": {
|
|
34
|
+
"command": "uvx",
|
|
35
|
+
"args": ["--from", "fable-engine==1.3.6", "fable-engine"]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Restart or reload the client, then inspect its MCP tools. You should see `fable_session` plus the browser tools exposed by the server.
|
|
42
|
+
|
|
43
|
+
## Install the optional Agent Skill
|
|
44
|
+
|
|
45
|
+
From the root of the project where you want the skill:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uvx --from fable-engine==1.3.6 fable-mode install-skill --dry-run
|
|
49
|
+
uvx --from fable-engine==1.3.6 fable-mode install-skill --yes
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The default destination is `.agents/skills/fable-mode`. Use `--target <dir>` for a different skill directory. The installer refuses to overwrite local edits unless you pass `--force`.
|
|
53
|
+
|
|
54
|
+
Reload the agent after installation.
|
|
55
|
+
|
|
56
|
+
## Run a first session
|
|
57
|
+
|
|
58
|
+
Ask your MCP client to call `fable_session` with:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"action": "create_session",
|
|
63
|
+
"session_name": "parser-refactor",
|
|
64
|
+
"objective": "Refactor the parser without changing its public behavior",
|
|
65
|
+
"time_budget_minutes": 2
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The result should show:
|
|
70
|
+
|
|
71
|
+
- `can_execute_code: False`;
|
|
72
|
+
- the active phase;
|
|
73
|
+
- the authority budget and remaining time;
|
|
74
|
+
- zero recorded evidence items and invariants.
|
|
75
|
+
|
|
76
|
+
Next, inspect the target repository and record real findings:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"action": "log_epistemic_item",
|
|
81
|
+
"session_name": "parser-refactor",
|
|
82
|
+
"tag": "PROVEN",
|
|
83
|
+
"claim": "The public parser entry point is parse(text)",
|
|
84
|
+
"evidence": "src/parser.py:18 and tests/test_parser.py"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Record a second evidence-backed claim and a falsifiable invariant:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"action": "record_invariant",
|
|
93
|
+
"session_name": "parser-refactor",
|
|
94
|
+
"invariant_name": "INV-01 public behavior",
|
|
95
|
+
"formal_statement": "For every existing parser fixture, output before == output after",
|
|
96
|
+
"proof_or_rationale": "Run the existing fixture suite before and after the change",
|
|
97
|
+
"domain": "compatibility"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Use `get_status` to inspect the gate. When the timer has elapsed and prerequisites are satisfied, call `unlock_execution` with an evidence-based rationale. A rejected unlock is expected when a condition is still missing.
|
|
102
|
+
|
|
103
|
+
## What the four gates mean
|
|
104
|
+
|
|
105
|
+
1. **Think**: inspect the system and classify claims as `PROVEN`, `HYPOTHESIS`, or `UNKNOWN`.
|
|
106
|
+
2. **Prove**: attach evidence to key claims and define invariants that can fail.
|
|
107
|
+
3. **Attack**: run normal tests and targeted adversarial checks against the proposed change.
|
|
108
|
+
4. **Write**: edit only after the engine reports that execution is unlocked, then verify the final tree.
|
|
109
|
+
|
|
110
|
+
The minimum authority budget is two minutes. It is a floor, not a claim that two minutes is enough for every task.
|
|
111
|
+
|
|
112
|
+
## Boundaries
|
|
113
|
+
|
|
114
|
+
Fable Mode does not guarantee correct code. It also does not replace:
|
|
115
|
+
|
|
116
|
+
- the host's filesystem permissions or sandbox;
|
|
117
|
+
- repository instructions and review rules;
|
|
118
|
+
- user approval for external side effects;
|
|
119
|
+
- a container or VM for hostile code;
|
|
120
|
+
- tests, type checks, static analysis, or human review.
|
|
121
|
+
|
|
122
|
+
The V2 broker can add a separate process and policy boundary. For hostile workloads, run it inside an OS-level sandbox or container with restricted permissions.
|
|
123
|
+
|
|
124
|
+
## Troubleshooting
|
|
125
|
+
|
|
126
|
+
**The client cannot find `fable_session`.** Run the `uvx` command directly, check the MCP client configuration, and reload the client. MCP servers communicate over standard input and output; the client manages the process after configuration.
|
|
127
|
+
|
|
128
|
+
**`unlock_execution` is rejected.** Read the returned reason. Common causes are an active authority timer, fewer than two `PROVEN` items, or no recorded invariant. Do not relabel assumptions to satisfy the counter.
|
|
129
|
+
|
|
130
|
+
**The skill is installed but not used.** Confirm the destination matches the client's skill-discovery convention, then reload the client. The package cannot activate a host skill by itself.
|
|
131
|
+
|
|
132
|
+
**You need a different workflow.** The skill is guidance around the engine. Host permissions and the user's instructions still win.
|
|
133
|
+
|
|
134
|
+
## Next steps
|
|
135
|
+
|
|
136
|
+
- [Agent Skill reference](../skills/fable-mode/SKILL.md)
|
|
137
|
+
- [V2 architecture](./fable-v2-architecture.md)
|
|
138
|
+
- [V1 to V2 migration](./fable-v1-v2-migration.md)
|
|
139
|
+
- [System 3 architecture](./system3-architecture.md)
|
|
@@ -27,6 +27,7 @@ from fable_engine.actions.deliberation import (
|
|
|
27
27
|
_handle_get_session_lineage,
|
|
28
28
|
_handle_inspect_plan,
|
|
29
29
|
_handle_verify_proof,
|
|
30
|
+
_handle_adjudicate_evidence,
|
|
30
31
|
_handle_record_visual_mockups,
|
|
31
32
|
_handle_validate_event_history,
|
|
32
33
|
)
|
|
@@ -186,6 +187,9 @@ ACTION_DISPATCH: Dict[str, Callable[[Dict[str, Any]], str]] = {
|
|
|
186
187
|
"plan": _handle_inspect_plan,
|
|
187
188
|
"inspect_blueprint": _handle_inspect_plan,
|
|
188
189
|
"verify_proof": _handle_verify_proof,
|
|
190
|
+
"adjudicate_evidence": _handle_adjudicate_evidence,
|
|
191
|
+
"adjudicate": _handle_adjudicate_evidence,
|
|
192
|
+
"ai_review": _handle_adjudicate_evidence,
|
|
189
193
|
"validate_proof": _handle_verify_proof,
|
|
190
194
|
"check_proof": _handle_verify_proof,
|
|
191
195
|
"record_visual_mockups": _handle_record_visual_mockups,
|
|
@@ -521,3 +521,51 @@ def _handle_validate_event_history(arguments: Dict[str, Any]) -> str:
|
|
|
521
521
|
)
|
|
522
522
|
|
|
523
523
|
|
|
524
|
+
def _handle_adjudicate_evidence(arguments: Dict[str, Any]) -> str:
|
|
525
|
+
"""On-demand AI adjudication of a session's recorded evidence.
|
|
526
|
+
|
|
527
|
+
Runs even in advisory mode; the env flag still gates whether any
|
|
528
|
+
external call happens at all.
|
|
529
|
+
"""
|
|
530
|
+
session_name = arguments.get("session_name", "").strip()
|
|
531
|
+
if not session_name:
|
|
532
|
+
return "Error: 'session_name' is required for action 'adjudicate_evidence'."
|
|
533
|
+
try:
|
|
534
|
+
session = get_or_load_session(session_name)
|
|
535
|
+
except Exception as exc:
|
|
536
|
+
return f"Error: could not load session '{session_name}': {exc}"
|
|
537
|
+
|
|
538
|
+
from fable_engine.adjudicator import AdjudicatorConfig, adjudicate_session
|
|
539
|
+
config = AdjudicatorConfig.from_env()
|
|
540
|
+
if not config.enabled:
|
|
541
|
+
return (
|
|
542
|
+
"AI Evidence Adjudicator is disabled. The host must set "
|
|
543
|
+
"FABLE_ADJUDICATOR_ENABLED=1 and FABLE_ADJUDICATOR_API_KEY "
|
|
544
|
+
"(optional: FABLE_ADJUDICATOR_STYLE, FABLE_ADJUDICATOR_MODEL, "
|
|
545
|
+
"FABLE_ADJUDICATOR_MODE=advisory|enforcing). No evidence was sent anywhere."
|
|
546
|
+
)
|
|
547
|
+
receipt = adjudicate_session(session, config=config)
|
|
548
|
+
if receipt is None:
|
|
549
|
+
return "AI Evidence Adjudicator is disabled; no review performed."
|
|
550
|
+
session.proof_receipts.append(receipt)
|
|
551
|
+
try:
|
|
552
|
+
session.save()
|
|
553
|
+
except Exception:
|
|
554
|
+
pass
|
|
555
|
+
|
|
556
|
+
verdict = str(receipt.get("verdict", "uncertain")).upper()
|
|
557
|
+
badge = {"PASS": "✅ PASS", "FAIL": "❌ FAIL"}.get(verdict, "⚠️ UNCERTAIN")
|
|
558
|
+
issues = receipt.get("issues") or []
|
|
559
|
+
issues_md = "\n".join(f"- {i}" for i in issues) if issues else "- none reported"
|
|
560
|
+
blocking = "blocking (enforcing mode)" if receipt.get("mode") == "enforcing" else "advisory only"
|
|
561
|
+
return (
|
|
562
|
+
f"### 🤖 AI Evidence Adjudication\n\n"
|
|
563
|
+
f"- **Verdict**: `{badge}` ({blocking})\n"
|
|
564
|
+
f"- **Confidence**: `{receipt.get('confidence', 0.0)}`\n"
|
|
565
|
+
f"- **Model**: `{receipt.get('model')}` ({receipt.get('style')})\n"
|
|
566
|
+
f"- **Receipt ID**: `{receipt.get('receipt_id')}`\n"
|
|
567
|
+
f"- **Evidence Bundle SHA-256**: `{receipt.get('bundle_sha256')}`\n"
|
|
568
|
+
f"\n**Issues**:\n{issues_md}\n\n"
|
|
569
|
+
f"Note: an AI adjudication is a second opinion, not a guarantee. "
|
|
570
|
+
f"Mechanical gates and deterministic proof receipts remain the primary authority."
|
|
571
|
+
)
|
|
@@ -200,16 +200,25 @@ def _handle_red_team_code_review(arguments: Dict[str, Any]) -> str:
|
|
|
200
200
|
code_snippet = arguments[k]
|
|
201
201
|
break
|
|
202
202
|
|
|
203
|
+
sandbox = None
|
|
203
204
|
if code_snippet is not None and not callable(code_snippet):
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
from fable_v2.coder_fleet.sandbox_executor import load_sandboxed_target
|
|
206
|
+
entrypoint = arguments.get("entrypoint") or arguments.get("function_name") or None
|
|
207
|
+
try:
|
|
208
|
+
sandbox = load_sandboxed_target(str(code_snippet), entrypoint=entrypoint)
|
|
209
|
+
code_snippet = sandbox
|
|
210
|
+
except Exception as exc:
|
|
211
|
+
return f"Error: Sandboxed executor could not load the target source: {exc}"
|
|
208
212
|
|
|
209
213
|
custom_hypotheses = arguments.get("custom_hypotheses") or arguments.get("hypotheses")
|
|
210
214
|
output_path = arguments.get("output_path")
|
|
211
215
|
|
|
212
|
-
|
|
216
|
+
try:
|
|
217
|
+
session = get_or_load_session(session_name)
|
|
218
|
+
except Exception:
|
|
219
|
+
if sandbox is not None:
|
|
220
|
+
sandbox.close()
|
|
221
|
+
raise
|
|
213
222
|
try:
|
|
214
223
|
report = _get_swarm().run_full_review_cycle(
|
|
215
224
|
target_callable=code_snippet,
|
|
@@ -227,9 +236,13 @@ def _handle_red_team_code_review(arguments: Dict[str, Any]) -> str:
|
|
|
227
236
|
report_dict["red_team_receipt"] = session.issue_red_team_receipt(report_dict, change_id)
|
|
228
237
|
session.record_breakage_report(report_dict)
|
|
229
238
|
except (TypeError, ValueError) as exc:
|
|
239
|
+
if sandbox is not None:
|
|
240
|
+
sandbox.close()
|
|
230
241
|
return f"Error: Cannot record red-team report: {exc}"
|
|
231
242
|
session.save()
|
|
232
243
|
|
|
244
|
+
if sandbox is not None:
|
|
245
|
+
sandbox.close()
|
|
233
246
|
md_report = _get_swarm().document_breakage(report, output_path=output_path)
|
|
234
247
|
return (
|
|
235
248
|
f"{md_report}\n\n"
|
|
@@ -320,11 +333,15 @@ def _handle_verify_red_team_remediation(arguments: Dict[str, Any]) -> str:
|
|
|
320
333
|
remediated_code = arguments[k]
|
|
321
334
|
break
|
|
322
335
|
|
|
336
|
+
sandbox = None
|
|
323
337
|
if remediated_code is not None and not callable(remediated_code):
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
338
|
+
from fable_v2.coder_fleet.sandbox_executor import load_sandboxed_target
|
|
339
|
+
entrypoint = arguments.get("entrypoint") or arguments.get("function_name") or None
|
|
340
|
+
try:
|
|
341
|
+
sandbox = load_sandboxed_target(str(remediated_code), entrypoint=entrypoint)
|
|
342
|
+
remediated_code = sandbox
|
|
343
|
+
except Exception as exc:
|
|
344
|
+
return f"Error: Sandboxed executor could not load the remediated source: {exc}"
|
|
328
345
|
|
|
329
346
|
session = get_or_load_session(session_name)
|
|
330
347
|
|
|
@@ -338,6 +355,8 @@ def _handle_verify_red_team_remediation(arguments: Dict[str, Any]) -> str:
|
|
|
338
355
|
prior_report = session.breakage_reports[-1]
|
|
339
356
|
|
|
340
357
|
if not prior_report:
|
|
358
|
+
if sandbox is not None:
|
|
359
|
+
sandbox.close()
|
|
341
360
|
return "Error: No prior breakage report found to verify. Provide 'report_id' or 'prior_report'."
|
|
342
361
|
try:
|
|
343
362
|
timeout_sec = float(arguments.get("timeout_seconds", 3.0))
|
|
@@ -369,8 +388,12 @@ def _handle_verify_red_team_remediation(arguments: Dict[str, Any]) -> str:
|
|
|
369
388
|
report["red_team_receipt"] = session.issue_red_team_receipt(report, change_id)
|
|
370
389
|
session.record_breakage_report(report)
|
|
371
390
|
except (TypeError, ValueError) as exc:
|
|
391
|
+
if sandbox is not None:
|
|
392
|
+
sandbox.close()
|
|
372
393
|
return f"Error: Cannot record remediation verification: {exc}"
|
|
373
394
|
|
|
395
|
+
if sandbox is not None:
|
|
396
|
+
sandbox.close()
|
|
374
397
|
session.save()
|
|
375
398
|
broken_count = int(report.get("broken_count", 0))
|
|
376
399
|
if broken_count > 0:
|