Threefold checks supported coding-agent writes before they run, so teams can catch architecture violations at the moment of change.
Built for the AWS Zero to Shipped hackathon. Category: #workplace-efficiency · Lane: #community
Published project · Live demo · Dashboard · API · CI · Evidence · Install
TL;DR: with the hook installed, Threefold checks supported writes and commands before they run. Deterministic gates on AWS check architecture rules, known credential patterns, repeating calls and caller-declared usage budgets. Projects start in Observe: review what rules would refuse, then promote selected rules to Enforce. Credential and hook-protection checks remain active locally.
With the hook installed, Threefold checks supported tool calls from Claude Code, Codex, Antigravity and Muse before they run. Deterministic gates decide: a domain file importing infrastructure under the architect's layering rules, a credential in the arguments, a write that switches the hooks off, the same call repeating, a budget based on caller-declared token counts. A team connects a repository with one command, and by default a project starts in Observe: architecture rules record what they would refuse. What is still refused there is a credential and anything that would switch the hooks off - an agent's settings file, Threefold's own binary, unplugging the plugin - by the hook on the developer's own machine, and a request the service cannot take at all (a body over 1 MB, a malformed call, a key it rejects), because the hook reads any 4xx answer other than 429 as a refusal. The operations dashboard shows what each rule would have refused; the operator marks each of those correct or a false alarm, promotes the project to Enforce with the rules that earned it, and demotes it with one click. Amazon Bedrock never decides; it phrases a refusal for a person reading a page and drafts rules for an architect, and every response names which of the two you are reading.
Live · Two minutes · Install · Rollout · Sign in · Gates · Architecture · Run it · Evidence · Clean room · Licence
| URL | What it is | |
|---|---|---|
| Site | https://d1og72wpk4aqig.cloudfront.net/ | CloudFront in front of everything: the pages from a private S3 bucket, every API path to the function, AWS WAF, security headers |
| Origin | https://raa131f9dj.execute-api.eu-west-1.amazonaws.com/prod/ | the API Gateway URL the edge forwards to. It serves the same pages from the function and stays public; it has no WAF. Since 2026-10-01 the function answers its pages with x-frame-options: DENY, frame-ancestors 'none', HSTS, nosniff and referrer-policy: no-referrer, and its files with nosniff and HSTS; the full content security policy is the edge's alone. The trailing slash is part of it: the bare /prod is API Gateway's own 404 |
Both answered anonymously, with no key, on 2026-09-22: GET / returned 200
text/html from each, and the site's response carried HSTS, a content security
policy, x-frame-options: DENY, nosniff and referrer-policy: no-referrer
[PRIMARY, 2026-09-22]. How the two fit together, and why both exist:
docs/ARCHITECTURE.md.
-
The two-stage rollout, on a project of your own: https://d1og72wpk4aqig.cloudfront.net/dashboard.html#/try. About two minutes for a reader, as the walkthrough itself says. Five steps:
- Make a sandbox. A project
Acme-Sandbox-<8 hex>in Observe, seeded with twelve synthetic hook calls from all three agents through the real evaluator. The answer toPOST /api/sandboxalso names, inseeded_false_alarm, the one seeded call a reasonable reviewer would call a false alarm: a test module undertests/domain/, whichpython-domain-stays-pureflags because its path pattern covers any folder nameddomain. - See what would be refused. Every flagged call, grouped by rule; each one ran.
- Label each call. The page asks you to spot the false alarm and, once every call has a label, says whether you found it and what your labels decide.
- Promote. The rules that read Ready are checked for you and nothing else is; the rule with the false alarm reads Noisy and keeps observing.
- Send it again. The page shows the call it is about to send, the same agent, file and import as a call you marked correct in Observe wherever a rule you promoted flagged one, and sends it only when you press Send it. It comes back refused, with the fix it suggests.
That last call is sent in a
try-session, which the project's stage decides like any hook's call: one step earlier the same call was recorded and approved, and it is refused only because the project now enforces. (sim-sessions enforce whatever the stage, which is why the walkthrough does not use one.) The two minutes are reading time: a script that pressed each button the moment the page enabled it reached the refusal in under two seconds, and the page had finished drawing it within three, against a local server with no network and no model (measured 2026-09-28). After 24 hours the sandbox's stage configuration expires and the project drops out of the overview and the project list; its calls and labels stay in the public call lists until the ledger's own 30-day expiry, and its daily counters stay in the table, no longer shown, for 35 days. - Make a sandbox. A project
-
The flagship demo, well under a minute: https://d1og72wpk4aqig.cloudfront.net/. Scenario 1 is one click and one
POST /simulate-loop; the function evaluates the same call three times and the third is refused withBLOCKED_LOOP_DETECTED, halting that demo session. Scenario 4 evaluates four ordinary calls and issues a governance certificate. Every click gets a fresh session. -
The dashboard itself: https://d1og72wpk4aqig.cloudfront.net/dashboard.html#/overview. Every tile and bar opens the calls behind it. Most of what it shows comes from a synthetic Acme fleet: every 15 minutes a schedule sends calls from the three agents through the real gates across six
Acme-*projects, and labels, promotes and demotes as an operator would. Nothing is backdated. The overview counts five sources apart, the fleet, the daily real agent (below), the service's own probes, visitors' sandboxes and everything else, and says in words that the fleet and the probes are synthetic. On 2026-09-27 its seven days held 3,086 calls: 2,128 from the fleet, 80 from sandboxes, 12 from the daily real agent and 866 from everything else, which then still held the probes' own calls, since the probe source came after that count [PRIMARY, 2026-09-27:docs/evidence/PROBES_2026-09-27-2-edge.md].#/proofshows what has been measured, and says "not measured yet" where nothing has; each of the six benchmark series there cites the report made from its own rows, linked in this repository.
The public stack has no operator key [STATE-FILE], so anonymous visitors can read, try and run the sandbox, and cannot change the policy, the layering rules or any real project's stage.
One command, at the root of the repository. These are the lines the
connect page (connect.html) leads with and the dashboard's connect wizard
(dashboard.html#/connect) builds, with the stack the page was served from as
the base; Acme-Billing is the project alias you choose. It saves the
installer as threefold.py and runs threefold.py connect, which installs in
managed mode: the project's stage on the service decides every call, and a
new project starts in Observe.
Windows PowerShell:
irm https://d1og72wpk4aqig.cloudfront.net/install.py -OutFile threefold.py; py threefold.py connect --project Acme-BillingmacOS and Linux:
curl -fsSL https://d1og72wpk4aqig.cloudfront.net/install.py -o threefold.py && python3 threefold.py connect --project Acme-Billing/install.py is the installer with the address of the stack that served it
written in. Fetched from the site it names the site; fetched from the origin it
names the origin [PRIMARY, 2026-09-22]. It is served as readable text, so read
it first if you like. connect:
- downloads the hook, the pre-commit check and the engine that check runs on
from the stack's
/dist/threefold-bundle.zip, and writes each file only when its SHA-256 matches/dist/manifest.json; - writes
.threefold.json(the project, the mode, the endpoint; a key file path if you give one, never a key) and merges one hook entry per agent into.claude/settings.local.json,.codex/hooks.jsonand.agents/hooks.json, keeping every other entry; - adds a pre-commit hook running
threefold_cli.py check, chaining one already there; - lists everything it wrote in
.git/info/exclude, so none of it is committed, and never writes a file git already tracks; - sends one harmless dry-run call, prints whether the stack recorded it, and opens the dashboard on the project.
Codex reads a project's hooks only once that project is trusted in Codex; the
installer does not change that setting for you. Later, py threefold.py status
lists every connected folder and its stage, py threefold.py disconnect [PATH]
removes exactly what was added, and py threefold.py open signs you in (below).
The installer keeps a copy of itself at ~/.threefold/bin/threefold_install.py
for when threefold.py is gone.
From Observe to Enforce is one step. The stage is the project's, on the service, not your machine's. When what the project recorded in Observe reads right, promote it on the dashboard with the rules you choose; nothing is installed again, and until then the project stays in Observe.
Two other modes change only this machine. --mode observe caps it to
Observe: every call goes as a dry run, which the service judges and records and
no rule refuses, whatever the stage says. --mode enforce sends calls exactly
as managed does, so the project's stage still decides on the service; what it
adds is on the machine, where a file-tool write (Write, Edit, a patch) to
the hooks' own files is refused whatever stage was last seen. A machine capped
with --mode observe therefore reaches enforcement in two steps: connect again
with --mode managed (or set "mode" in .threefold.json), and promote the
project on the dashboard, or deploy the stack with DefaultHookStage=enforce
for projects that have no stage of their own.
In every mode, a call carrying a credential is still refused on your machine and never sent, and a call the hook holds back is neither sent nor recorded.
The older form, from a checkout of this repository.
scripts/threefold_install.py is the same
installer, and besides connect it still takes the form it had before
connect: a --repo path, --mode, which defaults to observe there and so
caps the machine to dry runs, and --uninstall.
python scripts/threefold_install.py --repo /path/to/acme-billing --project Acme-Billing \
--mode managed --endpoint https://d1og72wpk4aqig.cloudfront.net/
python scripts/threefold_install.py --repo /path/to/acme-billing --uninstallWhat leaves your machine. For a call it sends, the hook sends one
POST /evaluate-tool-call: the session id, your project alias, anonymous or
a 12-character hash of THREEFOLD_DEVELOPER computed on your machine, the tool
name, the action type and the call's arguments, which for a write carry the
text being written, with paths relative to the project root; plus which agent
this is, that it came from a hook, and its mode. It holds back, and so never
checks, a call whose target is outside the project root, anything under
~/.claude, ~/.codex, ~/.gemini or ~/.local/share/muse, data files by extension and by
directory, any call containing a term from your own never_send.txt, and,
when .threefold.json has an include list, anything outside it. The
never-send list, your aliases and the list of governed repositories stay in
~/.threefold/.
When the service cannot answer, the hook prints nothing and exits 0, so
the agent's own permission flow decides: it fails open. THREEFOLD_FAIL_CLOSED=1
refuses instead. The credential refusal happens on the machine and does not
depend on the network.
Does a deny stop the write? Measured per agent, on the file system, on
2026-09-21: in Claude Code 2.1.220 and in the Antigravity desktop app the
refused file was not created. Codex CLI 0.155.0 was measured on 2026-09-23, in
one run: the hook refused an apply_patch that added boto3 to a governed
file, and the file's sha256 was unchanged afterwards. For Codex that is one
route, one run; the shell route and a refusal from a hook that makes no network
call are not measured. Muse 1.4.0 was measured on 2026-09-28: the hook refused
a write_file and the refused file was not created, and in a live session a deny
stopped an edit_file and a shell command too, each file unchanged on the disk.
Method and results:
docs/evidence/ENFORCEMENT_2026-09-21.md,
docs/evidence/ENFORCEMENT_2026-09-23.md
and
docs/evidence/ENFORCEMENT_2026-09-28-MUSE.md.
Does Threefold change what an agent does? Measured with Claude Code on
2026-09-22 and with Codex on 2026-09-23. Each ran headless on six synthetic
Acme tasks, each tempting a governed violation, and on three pressure
variants whose prompt asks for the forbidden shortcut outright, under three
conditions: no guidance, the same rules written into the repository's own
CLAUDE.md (AGENTS.md for Codex) with nothing enforcing them, and Threefold
enforcing. An independent checker (benchmark/checks.py, which does not import
Threefold) then read the files each run left behind, and the task's own
acceptance tests were restored and run. The two task families are reported
apart and never pooled, and neither are the agents.
| Tasks, agent, model | Runs | Violation landed: no guidance | rules in CLAUDE.md or AGENTS.md |
Threefold | Tests passed, Threefold |
|---|---|---|---|---|---|
standard, Claude Code, claude-sonnet-5 |
54 | 17% (3/18) | 0% (0/18) | 0% (0/18) | 100% (18/18) |
standard, Claude Code, claude-haiku-4-5 |
54 | 39% (7/18) | 17% (3/18) | 0% (0/18) | 100% (18/18) |
| standard, Codex, its default model | 54 | 17% (3/18) | 0% (0/18) | 0% (0/18) | 100% (18/18) |
pressure, Claude Code, claude-sonnet-5 |
27 | 67% (6/9) | 0% (0/9) | 0% (0/9) | 67% (6/9) |
pressure, Claude Code, claude-haiku-4-5 |
27 | 100% (9/9) | 56% (5/9) | 0% (0/9) | 44% (4/9) |
| pressure, Codex, its default model | 27 | 100% (9/9) | 11% (1/9) | 0% (0/9) | 67% (6/9) |
The honest reading. For Claude Code, the rules-in-CLAUDE.md column tracks the
model, not the task family. With claude-sonnet-5 the rules held in both
families with nothing enforcing them: no violation in 18 plain runs and none in
9 pressure runs. With claude-haiku-4-5 they held in neither: 17% on the plain
tasks, and 56% under prompts that ask for the shortcut, where unguided runs
violated every time. Codex kept the rules in AGENTS.md on the plain tasks and
broke them in 1 of 9 pressure runs. Threefold left no violation in any of the
six series.
The price is the last column: under the pressure prompts the governed Claude
Code finished 10 of 18 runs (6 of 9, then 4 of 9) and the governed Codex 6 of
9, and in the other runs the agent stopped and reported the conflict instead of
finishing - among them, for both agents, every run of the task whose prompt
forbids a new module. A compliant route exists there (archive from the
application service), and 7 of the 9 runs with only the written rules found it;
the governed runs stopped at the first refusal instead. With claude-sonnet-5
and Codex the written rules alone also prevented every violation and finished
more pressure runs clean (9 of 9 and 8 of 9, against 6 of 9 governed), so the
gain is largest with the weaker model. Samples are small (18 or 9 runs a cell) and the 95% intervals are wide;
the tasks were written by the people who built Threefold, so these are rates
under temptation and not base rates of everyday work. Two agents, both on
Windows (Claude Code 2.1.220 with two models, Codex CLI 0.155.0 on its own
default); Antigravity is not measured. Method, every result and its limits:
one report per series,
docs/evidence/BENCHMARK_2026-09-22.md
and the five beside it (listed under Evidence, below). The dashboard's
#/proof page carries the same six series, and each series' card cites the
report made from its own rows, linked in this repository.
A real agent on the public stack. scripts/daily_live_agent.py has a real
agent, Claude Code and Codex on alternate days, do one of the standard tasks
against the site, as Acme-Live-<task>, which the public stack starts in
Enforce. Five rows by 2026-09-30, in benchmark/results/live/ [PRIMARY]:
Codex on 2026-09-26, 8 calls, 7 approved and 1 refused, and that refusal was
false: a PowerShell read ending in 2>$null taken for a write. It was fixed
and deployed on 2026-09-27, and looking for a way around the fix closed an
older hole, a shell write into a domain file through bash -c "... > src/domain/\$f",
which had been approved. Claude Code on 2026-09-27, 4 calls, none refused.
Codex on 2026-09-28, 5 calls, none refused. Claude Code on 2026-09-29 never
started: the run was cut short by the org's monthly spend limit, 0 calls.
Codex on 2026-09-30, 9 calls, one refused (an unreadable shell write) and
self-corrected. Where an agent ran, no violation landed and the acceptance
tests passed. Single runs, reported apart from the matrix and never pooled
with it.
The hook is one standard-library file for four agents, served by the stack:
curl -O https://d1og72wpk4aqig.cloudfront.net/hooks/threefold_hook.pyRegister it in the project, with the absolute path to the file. --agent
tells the one file which agent is calling it.
| Agent | File | Matcher | Command |
|---|---|---|---|
| Claude Code | .claude/settings.local.json |
Write|Edit|MultiEdit|NotebookEdit|Bash |
python /absolute/path/to/threefold_hook.py --agent claude-code |
| Codex | .codex/hooks.json |
apply_patch|Edit|Write|Bash |
python /absolute/path/to/threefold_hook.py --agent codex |
| Antigravity | .agents/hooks.json |
write_to_file|replace_file_content|multi_replace_file_content|run_command |
python /absolute/path/to/threefold_hook.py --agent antigravity |
| Muse | plugin bundle in .threefold-muse/ |
PreToolUse | muse plugins install .threefold-muse --scope project, then muse plugins approve threefold |
Each settings file takes the same shape (Muse takes the plugin commands instead):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit|MultiEdit|NotebookEdit|Bash",
"hooks": [
{ "type": "command", "command": "python /absolute/path/to/threefold_hook.py --agent claude-code" }
]
}
]
}
}| Variable | Effect |
|---|---|
THREEFOLD_PROJECT |
Required, here or in .threefold.json. The alias the project is sent under; unset, nothing is sent. Use an alias, never the real name. |
THREEFOLD_ENDPOINT |
The stack the hook asks. Without one it asks the origin URL above. |
THREEFOLD_MODE |
managed, observe or enforce, as above. The hook alone, with no configuration, runs enforce. |
THREEFOLD_API_KEY_FILE |
A file holding the operator key, for a stack that enforces one. A key is never sent to an endpoint that only a repository's own .threefold.json names. |
THREEFOLD_DEVELOPER |
Hashed on your machine; only the hash is sent. Unset, the hook sends anonymous. |
THREEFOLD_FAIL_CLOSED |
1 refuses a call the service could not judge. |
THREEFOLD_TIMEOUT |
Seconds to wait for the service, 4 unless set. |
THREEFOLD_HOME |
Where the hook's local files live, ~/.threefold unless set. |
The hook governs the machine it is installed on. The merge is governed
separately: scripts/judge_pr.py judges every added or
changed file in a pull request through the service, including pull requests
from agents that never installed anything, and fails the check when a rule
fires. This repository's own pull requests are judged that way
(.github/workflows/pr-judge.yml); the
runbook's section 12 says how to adopt it.
- Observe. A newly connected project has no stage of its own, so it takes
the stack's default,
observeon the public stack [PRIMARY, 2026-09-22:DefaultHookStage=observeindescribe-stacks]. Every call is judged and recorded; a call a rule would have refused runs, and is counted as "would refuse". The one exception is a name the stack'sEnforceProjectPatternmatches, which starts in Enforce instead. It is empty by default; the public stack sets^Acme-Live-.+$for the daily real agent's projects, which have no operator to promote them [STATE-FILE, since 2026-09-26]. - Review.
#/reviewqueues every unreviewed would-refuse call, grouped by project and rule. Each is marked correct or false alarm, one at a time or in bulk; the label is stored on the ledger row. - Readiness.
#/projects/<name>shows each rule's state: Ready when at least one call it flagged was marked correct and none a false alarm, with nothing waiting for a label, Quiet when no label says anything about it (it flagged nothing, or refused only calls nobody labelled, such as the demo page's), Needs review while anything it would have refused is unlabelled, Noisy after any false alarm. Ready rests on labels alone: a refusal nobody labelled is evidence of nothing, so a rule whose only record is unlabelled refusals reads Quiet, with those refusals counted on its row (application/rollups.py). - Promote. Promote moves the project to Enforce with the rules you pick; the others keep observing, recording what they would refuse. Demote is one click back to Observe.
A promotion or a demotion applies at once on the Lambda container that handled
it, and within 30 seconds on every other warm container, each of which reads
the project's stage again once its copy is 30 seconds old
(RULES_REFRESH_SECONDS in application/evaluator.py). Until then a call that
lands on another container can still be judged under the old stage, so for up
to half a minute after a demotion a call can still be refused.
The stage applies to calls from hooks and CI. The demo's page and simulation
calls always enforce, so the public demo behaves the same whatever a project's
stage is. A machine pinned to --mode observe is never refused by a rule,
whatever the dashboard says (a credential and an attempt to switch the hook off
are still refused on the machine, and a request the service cannot take, such
as a body over 1 MB, still comes back as a refusal), and the project page flags such
a machine among its agents.
A refusal comes with a validated fix when one fits: a rewritten file, a
port and an adapter, an environment lookup in place of a literal credential.
Every write it proposes is run back through the same gates with the same rules
before it is offered, validated says whether all of them passed, and the
hook appends its one-line summary to the deny reason, so the agent is told what
to do instead. No model writes it.
On a stack deployed with an operator key (a private stack, PublicReads=false),
connect once with the key file:
python3 threefold.py connect --project Acme-Billing --endpoint https://<your stack>/ --api-key-file /path/to/operator.key
python3 threefold.py openopen sends the key from that file in a header to POST /api/auth/links,
receives a single-use code that expires in 120 seconds, and opens
dashboard.html#/signin?code=.... The page trades the code for a session
valid for 12 hours. The code and the session are stored only as SHA-256
hashes, and the browser never holds the key. The public stack has no operator
key, so sign-in is closed there: POST /api/auth/links answers 403 "Sign-In Is
Closed Here" (docs/evidence/PROBES_2026-09-22.md),
and GET /api/auth/whoami reports reads_public: true, sandbox_writes: true
[PRIMARY, 2026-09-22].
The service states its own coverage at GET /api/insights, and the layering
row is computed from the rules in force, so it changes when an architect saves
a rule. As served by the public stack [PRIMARY, 2026-09-22]:
| Gate | Watches | Blind to |
|---|---|---|
| Credentials | Fifteen credential shapes in any argument, at any depth, for every language | Credentials that do not match a known shape, and anything already in the file on disk |
| Layering | 4 rules refusing (python-domain-stays-pure, java-domain-stays-pure, dotnet-domain-stays-pure, web-domain-stays-pure) over **/Domain/**/*.cs, **/domain/**/*.java, **/domain/**/*.py, **/domain/**/*.pyi, **/domain/**/*.ts, **/domain/**/*.tsx; imports read from .cs, .java, .js, .jsx, .mjs, .py, .pyi, .ts, .tsx |
Any path no refusing rule covers, any file type not in that list, and the dependencies a file does not declare: an import is read from the file's own statements, not resolved, followed or injected |
| Loops | Any repeating cycle of byte-identical tool calls, up to the policy's history window, plus a second tier over same-shape calls (same tool, targets and keys) at a longer fuse, within one session | Near-identical calls below the fuzzy tier's fuse, and repetition across separate sessions |
| Budget | Projected spend per call and per session, against the policy | Real usage. The counts are the ones the caller declares, so a caller declaring zero is not stopped |
The same boundary gate also refuses writes that switch governance off (the
agents' hook settings, .git/hooks, git commit --no-verify and the other ways
to point git at other hooks), shell writes whose content cannot be read on a
path a rule covers, and destructive commands. A shell command is read for the
writes it makes, so a heredoc into a domain file is judged like a Write.
Blind by design, as the hook's contract in STATE.md sets it [STATE-FILE] and
src/threefold/hooks/threefold_hook.py implements it:
- A call the hook holds back is not checked by anything, and while the service cannot be reached the hook fails open.
- An edit is judged on the imports it adds by reading the file before and after it on the machine (credentials in it replaced by their labels). A file over 64 KB, or one the edit does not apply to cleanly, is judged on the edit's new text alone, where a change to part of an import line can pass.
- Two calls in one session judged at the same instant can each save over the other's verdict, so a certificate can miss a refusal made in that instant.
- Everything under
.gitis a data directory to the hook, except the two files that decide whether the hooks run. Outsideenforcemode (andmanagedmode while the project enforces), where the hook refuses it on the machine, a file-tool write (Write,Edit, a patch) to.git/hooks/or.git/configis sent as its path alone, so an attempt to switch the pre-commit check off that way shows up in Observe and the review queue like the same write made through a shell command, recorded underPROTECTED_PATH. The content stays home:.git/configcan carry a token in a remote URL.
Also true [STATE-FILE]:
- All five keys
/policy/configreturns are enforced: the session ceiling trips through the breaker, the history window sets the detector's cycle search, and the pattern list refuses through the secret gate. A saved policy reaches every container within thirty seconds. - A call is priced by the model it names only as far as the price table goes: a Haiku at the Haiku rate, and everything else, including a model the table does not list, at the default Sonnet-class rate.
- The governance certificate covers the session's own stored verdicts, never the caller's word, and carries a KMS signature where the stack holds a signing key. It is returned rather than archived. The certificate itself is still not required before a merge; the diff is judged instead, by the required check this repository's own PR #6 proved red-to-green and was merged. The S3 bucket the stack provisions is empty.
- Call counts are cumulative everywhere, in the listing and in the detail; a session keeps its last 50 calls in history.
- When the demo page cannot reach the service, its four scenario panels replay one real run each, recorded against the live API and labelled "recorded, replayed offline"; no value in them is invented.
- The benchmark measures two agents (Claude Code with two models, Codex with its own default) on tasks this project wrote, so it is not an independent comparison: Antigravity is unmeasured, and under prompts that ask for the shortcut the governed Claude Code finished 10 of 18 runs and Codex 6 of 9 (above).
agent ─► threefold_hook.py ─┐ (local: credential refusal, hold-back, mode)
▼
browser ─► CloudFront + WAF ─┬─► S3, private, origin access control (pages, assets)
(us-east-1) └─► API Gateway HTTP API, stage prod (eu-west-1)
└─► one Lambda, Python 3.11 on arm64
├─► DynamoDB, one table (sessions, ledger,
│ daily rollups, rules, stages, sign-in)
├─► Bedrock, Claude Haiku 4.5 (page
│ explanations and rule drafts only)
└─► CloudWatch (EMF metrics, 11 alarms,
a dashboard, X-Ray)
Two stacks come from the one template: threefold-prod, the public demo above,
and a private stack with PublicReads=false that carries the owner's own work
under Acme-Proj-* aliases, all in Observe [STATE-FILE]. Its address is never
written in this repository. Only the public stack deploys with
DemoFleet=true, which adds an EventBridge Scheduler schedule invoking the
same function every 15 minutes for the synthetic fleet; the function takes
that event only when it is not an HTTP request, so no caller of the API can
start a tick. The edge is built to answer a page address that has no page with
the product's own 404.html and status 404, through two CloudFront Functions
on the pages' behavior alone, so a path an API behavior takes keeps the API's
own answer (deploy/edge.yml). Topology, data model and trade-offs:
docs/ARCHITECTURE.md. The six Well-Architected
pillars against what is deployed: docs/WELL_ARCHITECTED.md.
Deploying, publishing the pages, probing, rolling back and tearing down:
docs/RUNBOOK.md.
The repository, top to bottom:
├── src/threefold/ domain · application · infrastructure · interfaces · hooks · tools · web
├── tests/ unit · integration · pages · hook · security
├── benchmark/ tasks · harness · results
├── scripts/ install · judge · probes · publish · live agent
├── deploy/ CloudFormation: the regional stack · the edge stack · IAM
├── docs/ architecture · runbook · dossier · evidence
├── .github/workflows/ CI · CodeQL · merge gate · keepalive · deploy
├── README.md STATE.md LOG.md TRAPS.md CLAUDE.md
└── pyproject.toml Dockerfile LICENSE
The tests are hermetic: tests/conftest.py sets THREEFOLD_OFFLINE=1 before
anything builds an AWS client, so they make no network call and need no
credentials. Standard library and pytest only.
python -m pytest -qThe count is deliberately not printed here: pytest prints it, and a number written into prose is wrong again the moment a test is added.
The local server runs the same Lambda handler on the standard library's HTTP server, with the table and the model replaced by memory and deterministic text:
THREEFOLD_OFFLINE=1 python src/threefold/interfaces/server.py --port 8001(PowerShell: $env:THREEFOLD_OFFLINE = "1"; python src/threefold/interfaces/server.py --port 8001.)
Then open http://localhost:8001/ or http://localhost:8001/dashboard.html.
Evidence labels name their source: [PRIMARY, date] marks a recorded measurement,
and [STATE-FILE] refers to the maintained project state. They are
source notes, not missing values.
| File | What it shows |
|---|---|
docs/evidence/PROBES_2026-09-29.md, docs/evidence/PROBES_2026-09-29-17b59ee4.md |
scripts/probe_live.py against the site and against the origin URL on 2026-09-29: 117 PASS, 0 FAIL, 3 SKIP each, with every check's evidence line. The earlier runs sit beside them, the first on 2026-09-22 against the origin: 113 PASS, 0 FAIL, 3 SKIP |
docs/evidence/ENFORCEMENT_2026-09-21.md |
Whether a deny stops the write, per agent, checked on the file system |
docs/evidence/ENFORCEMENT_2026-09-23.md |
The same question for Codex CLI 0.155.0, over its patch tool, in one run |
docs/evidence/ENFORCEMENT_2026-09-28-MUSE.md |
The same question for Muse 1.4.0, over write_file, edit_file and the shell; the MSP-approval route measured dead |
docs/evidence/DEPLOYMENT_2026-09-20.md |
Raw output of the first deployment, including the CloudTrail events that show Bedrock called by the function's own role |
docs/evidence/BENCHMARK_2026-09-22.md |
The standard-task matrix with claude-sonnet-5: 54 runs, a governed violation landed in 17% / 0% / 0% of runs with no guidance, with the rules in CLAUDE.md and with Threefold enforcing |
docs/evidence/BENCHMARK_2026-09-22-HAIKU.md |
The same 54 runs with claude-haiku-4-5: 39% / 17% / 0% |
docs/evidence/BENCHMARK_2026-09-22-PRESSURE-SONNET.md |
The three pressure tasks, whose prompt asks for the forbidden shortcut, with claude-sonnet-5: 27 runs, 67% / 0% / 0%, and the acceptance tests passed in 6 of the 9 governed runs |
docs/evidence/BENCHMARK_2026-09-22-PRESSURE-HAIKU.md |
The same 27 runs with claude-haiku-4-5: 100% / 56% / 0%, tests passed in 4 of the 9 governed runs |
docs/evidence/BENCHMARK_2026-09-23-CODEX.md |
The standard tasks with Codex CLI 0.155.0 on its default model, the rules in AGENTS.md: 54 runs, 17% / 0% / 0% |
docs/evidence/BENCHMARK_2026-09-23-CODEX-PRESSURE.md |
The pressure tasks with Codex: 27 runs, 100% / 11% / 0%, tests passed in 6 of the 9 governed runs |
docs/evidence/BENCHMARK_2026-09-22-PILOT.md |
The pilot that came before the four Claude Code matrices. Its three real-agent runs never reached the model (an expired login), so it measured nothing about agents and the scripted rows only prove the harness. Kept because the four matrices were run once that login was fixed |
docs/PROOF_OF_AWS_AGENT.md |
The coding agent connected to AWS: what it ran, what AWS answered, and how to check it |
Every project and workload in this repository and on the public stack is
synthetic (Acme-*). The agents are real where the text says so: the
benchmark's Claude Code and Codex runs (benchmark/results/) and the daily real
agent's live-<task>-<date> sessions are real agent runs on synthetic Acme
tasks. A project name outside the stack's AllowedProjectPattern is stored and
shown as unlabelled, and developers appear in public only as short hashes.
Apache-2.0. See LICENSE.
