Accountable Surface
Accountable Surface lets an AI agent take only the file, command, web, or browser action a person has approved. It checks the request and authorization, blocks or pauses when needed, verifies the outcome, rolls back reversible failures, and records decisions and outcomes in a journal. Persisted journals are hash-chained so later edits, deletions, or reordering are detected.
The Python core uses only the standard library. Browser automation is an optional extra.
Try it
After cloning the three repositories and installing Accountable Surface, run the complete local file-action example:
python examples/actuate_demo.py
The example refuses an unapproved write, performs an approved write, detects a wrong result, restores the previous file, and prints the journal entries.
Verified Today
The published GitHub v0.2.0 release is available from commit
b2ae9be77038753d9bdbda861e9908542883ff2c. Its release assets are:
accountable_surface-0.2.0-py3-none-any.whl(sha256:f2fb09ac66d00bb188da7fdd6fd1ba37485f5fe245c0596902adc355f6bccdfa).accountable_surface-0.2.0.tar.gz(sha256:47a126a821861ce49581b49eb67892220a61633de8b71323e41749e8fa6538c6).SHA256SUMS.txt(sha256:b7acee277353171f79865a32640bf64b48efcfbb919a4e7c2143a4a71c845855).
The release was verified from a clean isolated worktree with these checks:
python -m pytest: Python suite passed.node --test web/*.test.mjs: browser-interface tests passed.python tools/check_repo_art.py --json,python tools/check_repo_card.py, andpython tools/check_repo_flow.py: repository documentation/art gates passed.python -m build --sdist --wheel: built the local sdist and wheel.python -m twine check dist/*: passed with Twine 7.x.- A fresh virtual environment installed the wheel, checked both console scripts, and ran a private synthetic durable-authority control against a disposable authority-state database.
These checks cover the repository's deterministic local paths. They do not establish safety in every host environment or validate every third-party browser, website, or model provider.
Features
- Third-party API actuation.
ApiEffectorwrites through a service's official API under the same contract as the rest. The caller hands in an intent and a body; the host, method, route shape, and credential belong to the effector, so an agent can ask to post a comment and cannot reach an admin route or read the token back. Verification re-reads the resource, so a service that answers 201 and stores nothing is refuted rather than believed.FakeApiDrivermakes the whole path testable with no network and no credential. - Native web actuation, no browser.
WebEffectornavigates, fills fields by their visible label, and submits forms on live server-rendered pages, driven by a stdlib HTTP and HTML parser backend (HttpDriver). Origin-bounded by construction. - JS-capable browser actuation, optional.
BrowserEffectorclicks by accessible label, follows navigation, and runs JavaScript on single-page apps. Tests and offline demos use the deterministicFakeBrowserDriver; production can injectPlaywrightDriver(the[browser]extra, lazily imported, never a hard dependency). - OS command actuation.
CommandEffectorruns allowlisted commands only, as argv withshell=False, in a bounded working directory. Irreversible commands escalate to needs-human. - Filesystem actuation with rollback.
FilesystemEffectoris bounded to a root, verifies its own writes by re-perceiving, and rolls back a reversible action that fails verification. - Windows application actuation, by label not by pixel.
UiaEffectorreads a window's control tree and acts on one control by its accessible name: press a button, set a field. It is built for a single window and refuses a target naming another. A click cannot be undone, so the caller declares what should follow it (a control appears, disappears, or carries some text) and a plan without that is refused before anything is touched. Verification re-reads the window, so an application that accepts a click and does nothing with it is refuted rather than believed.FakeUiaDriverruns the whole path on any operating system, with no window open. - A ladder that says what it cost. Reaching a desktop application starts with the control tree and falls to pixels only when the cheap instrument cannot answer. The escalator asks each rung in that rung's own terms and records why it fell: the tree was clipped, the label named two controls, the window did not read. Falling does not buy an answer. When the ladder runs out you get NEEDS_HUMAN, the whole trace, and the witnessed sight the deepest rung produced, because a perceptual hash is a real receipt for an image and no answer at all about a control named
Save. - Structured perception. Organs read a target as a content-addressed structural observation with a falsifiable self-test, not a screenshot.
- Grounding. A reference cortex (
ReferenceCortex) scores reference relevance for a subject and reports "ungrounded" instead of guessing, with native arXiv lookup via the stdlib. An action can carry a justification; an ungrounded premise escalates to needs-human. - Bounded autonomy.
pursueruns a multi-step plan under one grant envelope with no per-step prompt, halting the instant a step is denied or fails verification. - Shared world server. A zero-dependency live server (stdlib
http.serverplus SSE) where proposed actions run the real loop and stream to every open browser tab, with a small web UI inweb/. Optional pilots connect a model (Claude or Ollama) to drive it. - Durable, tamper-evident memory. An append-only JSONL journal that replays across sessions, hash-chained so an edited, deleted, or reordered entry is caught on reload even though it still parses (corruption and tamper are counted separately, never conflated).
verify_journal()re-derives the chain and returns the verdict;interocept()is a content-addressed view of the surface's own conduct. - Live MCP server.
perceive,propose,actuate,session_journal, andinteroceptexposed over MCP stdio (the[server]extra).actuatereaches only the effectors the operator exposed, and nothing is exposed by default. - Interoperable MCP server (no FastMCP). A zero-third-party-dependency stdio server,
accountable_surface.interop_mcp, carries the six accountable primitives (perceive,propose/gate,actuate,journal,receipt) plus the shipped read-only verbdevice_ls, so other harnesses (Claude Code, Codex, Cursor, the Flywheel bundled lane) adopt one seam. Seedocs/interop-mcp.mdandinterop/. - Action certificates.
certifycomposes the gate, effect, and grounding verdicts into one certificate token; a denial or failed effect makes the whole action REFUTED, and an escalation yields UNVERIFIABLE, never a rounded-up pass.
The gate is default-deny: with no operator grant loaded, nothing acts. The model cannot supply its own authorization.
Install
pip install accountable-surface
Add the MCP server with pip install "accountable-surface[server]". Use a source checkout when you need current main branch features, or a GitHub release asset when you want a wheel with a published checksum.
Current PyPI release: 0.3.1, published by an OIDC trusted publisher with PEP 740 attestations, so the index records which workflow built the bytes. v0.2.0 and v0.1.0 remain older tagged GitHub packages. The package is still alpha.
Install the released wheel with the published checksum file:
& {
$ErrorActionPreference = 'Stop'
$Version = "0.2.0"
$Wheel = "accountable_surface-$Version-py3-none-any.whl"
$PinnedWheelSha256 = "f2fb09ac66d00bb188da7fdd6fd1ba37485f5fe245c0596902adc355f6bccdfa"
$Base = "https://github.com/HarperZ9/accountable-surface/releases/download/v$Version"
Invoke-WebRequest "$Base/SHA256SUMS.txt" -OutFile SHA256SUMS.txt
Invoke-WebRequest "$Base/$Wheel" -OutFile $Wheel
$WheelPattern = [regex]::Escape($Wheel)
$ChecksumRows = @(Select-String -Path SHA256SUMS.txt -Pattern "^\s*([0-9A-Fa-f]{64})\s+\*?$WheelPattern\s*$")
if ($ChecksumRows.Count -ne 1) { throw "Expected exactly one SHA256SUMS row for $Wheel; found $($ChecksumRows.Count)" }
$Expected = [regex]::Match($ChecksumRows[0].Line, "^\s*([0-9A-Fa-f]{64})\s+").Groups[1].Value.ToLowerInvariant()
if ($Expected -ne $PinnedWheelSha256) { throw "SHA256SUMS row for $Wheel did not match the pinned GitHub release hash" }
$Actual = (Get-FileHash $Wheel -Algorithm SHA256).Hash.ToLowerInvariant()
if ($Actual -ne $Expected) { throw "SHA256 mismatch for $Wheel" }
python -m pip install $Wheel
}
Current source checkout, including the durable-authority work in 0.2.0:
git clone https://github.com/HarperZ9/accountable-surface.git
git clone https://github.com/HarperZ9/coherence-membrane.git
git clone https://github.com/HarperZ9/proof-surface.git
cd accountable-surface
$env:PYTHONPATH = "src;..\coherence-membrane\src;..\proof-surface\src"
python -m pip install -e ".[test]"
Requires Python 3.10+. The package declares coherence-membrane and proof-surface as runtime dependencies, because accountable_surface imports both. mcp stays optional under the [server] extra, since only the MCP server path needs it.
Quickstart
python examples/demo.py # perceive, gate allow, gate deny, journal
python examples/actuate_demo.py # the full act-verify-rollback loop
python -m pytest # the Python test suite
demo.py prints a witnessed structural reading of a local page (title, links, sha256 digest), then a gate ALLOW for an action inside the grant, a gate DENY for one outside it, and the journal of every perception and decision.
More transcripts: web_actuate_demo.py (native web actuation against a real localhost server), spa_actuate_demo.py (the JS-capable browser path, offline), goal_demo.py (bounded autonomy), grounding_demo.py and grounded_actuate_demo.py (the reference cortex), smoke_mcp.py (a real MCP stdio round-trip).
Worked example
An operator grant is a plain JSON object. The surface acts only when the gate allows the exact plan, then verifies the effect on disk.
from accountable_surface import AccountableSurface, FilesystemEffector
grant = {
"authorization_version": "0.1",
"receipt_id": "rcpt-example",
"kind": "authorization-grant",
"principal": {"id": "operator-1", "role": "operator"},
"agent": {"id": "example-agent"},
"intent": "write the report file",
"scope": {"allowed_actions": ["fs.write"], "allowed_targets": []},
"granted_at": "2026-06-19T00:00:00+00:00",
"expires_at": "2030-01-01T00:00:00+00:00",
"revoked": False,
}
surface = AccountableSurface()
out = surface.actuate(
FilesystemEffector("/path/to/sandbox"),
target="/path/to/sandbox/report.txt",
content=b"written natively, verified by re-perceiving",
authorization=grant,
)
print(out.acted, out.decision, out.verified) # True allow True
With authorization={} the same call returns acted=False, decision="deny" and the file is never created. A faulty effector that writes the wrong bytes is caught at verification and rolled back; examples/actuate_demo.py shows both paths.
What each verdict contributes
One actuation produces up to three verdicts: what the gate decided, what the re-read found, and how well the premise was grounded. They are composed into a single certificate by a lattice meet, so a worse step can never be laundered into a better result.
Run as an MCP server
python -m pip install -e ".[server]" # adds mcp
python -m accountable_surface.server # or: accountable-surface-server
Client configuration:
{
"mcpServers": {
"accountable-surface": {
"command": "python",
"args": ["-m", "accountable_surface.server"],
"env": {
"PYTHONPATH": "C:/path/to/accountable-surface/src;C:/path/to/coherence-membrane/src;C:/path/to/proof-surface/src",
"ACCOUNTABLE_SURFACE_GRANTS": "C:/path/to/operator-grants.json",
"ACCOUNTABLE_SURFACE_JOURNAL": "C:/path/to/session-journal.jsonl",
"ACCOUNTABLE_SURFACE_AUTHORITY_STATE": "C:/path/to/authority-state.sqlite3"
}
}
}
}
Interoperable stdio server (no FastMCP)
For adoption by other harnesses, accountable_surface.interop_mcp is a stdlib-only
JSON-RPC-over-stdio server: no FastMCP, nothing to pip install for a harness to spawn
it and list tools. It carries the six accountable primitives plus the shipped
read-only verb and emits an offline-re-derivable action-receipt/v1.
python -m accountable_surface.interop_mcp # or: accountable-surface-mcp
Manifests for Claude Code, Codex, Cursor, and the Flywheel lane live in interop/;
the overview and the evidence-bound comparison over ungated computer use are in
docs/interop-mcp.md. The hard exclusions (CAPTCHA solving, anti-bot stealth /
fingerprint patching, reCAPTCHA token harvest, mass or obfuscated authenticated
outreach) are unreachable through any tool and asserted by test.
ACCOUNTABLE_SURFACE_GRANTS points to a JSON file with one authorization grant
or a list; with none loaded the gate is default-deny. Remote reads are scoped
separately from writes: allowed_actions may name fs.write, but the remote
server still refuses until allowed_reads covers the target state phases it must
read (before, backup, after, and rollback for filesystem writes).
ACCOUNTABLE_SURFACE_JOURNAL points to an append-only JSONL file; when set, the
journal replays on launch so the witnessed self-view spans sessions.
ACCOUNTABLE_SURFACE_AUTHORITY_STATE points to an optional stdlib-SQLite state file for durable revocation, atomic usage reservations, and idempotency. With it set, remote actuate requires an idempotency_key, refuses protected grant/state/journal paths even under broad filesystem grants, and keeps unresolved precommit reservations unavailable until operator recovery. See docs/durable-authority.md.
ACCOUNTABLE_SURFACE_EFFECTORS points to a JSON file naming which effectors a remote caller may reach:
{"effectors": [
{"action_kind": "fs.write", "type": "filesystem", "root": "/srv/agent-sandbox"},
{"action_kind": "api.post", "type": "api", "service": "github"}
]}
Three operator decisions guard remote actuate and all have to agree: the
registry exposes an effector, allowed_actions names the write, and
allowed_reads names the state reads needed to precondition, verify, and roll
back that write. With the variable unset, the file empty, or the action kind
missing from it, actuate refuses before it reads a grant. The file refuses
command, browser, web, and uia by name, each with the reason. Ask
doctor for the exposed set, the reach of each entry, and the entries it turned
down. MCP perceive likewise needs a web.document read grant, and full
session_journal replay needs a journal.session read grant.
Shared world server
A live surface you can watch in a browser: proposed actions run the real perceive-gate-act-verify loop and stream over SSE to every open subscriber.
python -m accountable_surface.world.server 8808
It serves the web UI from web/ and binds to localhost by default. Grants are operator-supplied at startup; the built-in fallback is an explicit sandbox-scoped demo grant, and default-deny still holds.
Layout
src/accountable_surface/surface.py:AccountableSurfacewithperceive,propose,actuate,pursue,interocept, and the durable journal.effector.py,web_effector.py,browser_effector.py,os_effector.py,api_effector.py,uia_effector.py: the six effectors and their drivers.http_driver.py: the stdlib HTTP and HTML backend behind native web actuation.playwright_driver.py: the optional JS-capable browser driver.reference.py: the grounding cortex,certify.py: action certificates,grant.py: grant helpers.server.py: the MCP server.world/: the shared world session, server, sight, and pilots.tests/: the Python test suite.examples/: eight runnable transcripts.web/: the shared world UI plus Node tests.docs/: design specs (SPEC-actuation.md,SPEC-interoception.md,SPEC-persistence.md), design notes, and docs/INTRODUCTION.md, the first-ten-minutes guide.docs/art/: the diagrams above, rendered fromaccountable-surface.art.jsonbytools/render_repo_art.pyand checked bytools/check_repo_art.py. Brand assets:.github/assets/zentropy-banner.png.
Status
Alpha, version 0.2.0. The API is settling and may change between 0.x releases. CI runs the Python suite and the Node web tests on every push and pull request, with sibling checkouts of coherence-membrane and proof-surface. Local verification:
$env:PYTHONPATH = "src;..\coherence-membrane\src;..\proof-surface\src"
python -m pytest
node --test web/*.test.mjs
Release packaging steps and hold points are in docs/RELEASE.md.
Related repos
- coherence-membrane: the perception organs and certificate types this surface composes.
- proof-surface: the pre-execution gate (allow, deny, needs-human).
- USAGE.md: the operational guide, including the browser backend.
Development disclosure
Zain Dana Harper maintains this repository. AI-assisted tools are used for parts of development and documentation. Public source, tests, and release artifacts are the evidence for what ships; AI output is not treated as proof.
Why the gate and the journal
Agent autonomy without silent authority: every action here is checked against an operator grant before it runs, verified against its intended effect after it runs, and recorded in a journal you can replay and re-check. The receipt is the floor; the features above are the point.
A journal that can be quietly rewritten records nothing worth reading. Each entry is chained to the one before it, so an edit breaks the entry's own hash and a delete or a reorder breaks the link to its neighbour. verify_journal.py re-derives the whole chain with no import from this package, which means a stranger holding only the JSONL file can check it.
License
FSL-1.1-MIT. Copyright (c) 2026 Zain Dana Harper. See LICENSE.
What this believes
This tool is one lane of a family that holds a single belief steady across every surface: knowledge open to anyone who can attain the means; acceptance decided by external checks, never reputation; every result re-runnable; honest nulls first-class; ownership earned by comprehension; learning woven into the work. The full text lives in CREDO.md. The long form of this belief: The Unbundling.
Zentropy Labs · order out of entropy. An independent lab building evidence-first tools that leave a re-checkable artifact behind. Built by Zain Dana Harper in Seattle. The full workbench is at Project Telos.
Release files for accountable-surface 0.3.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 | |
|---|---|---|---|
| accountable_surface-0.3.1.tar.gz | 441.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| accountable_surface-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 580.5 kB
Release files / accountable_surface-0.3.1.tar.gz
| Download URL | accountable_surface-0.3.1.tar.gz |
|---|---|
| Size | 441.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9e9931c3c17e2692bd6325a88d7c9b3c46276342f68b05d70bce00763701ca7c
|
|
BLAKE2b-256 checksum How to use checksums |
690a32d4da210283913e3c6caf7983cc9880299a5ec28e67a369044a852fea8b
|
| 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 23, 2026.
Transparency logRelease files / accountable_surface-0.3.1-py3-none-any.whl
| Download URL | accountable_surface-0.3.1-py3-none-any.whl |
|---|---|
| Size | 138.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
631dac3ed27fa786d1ed5601baea313ce83659d287eacb7297b130c4e10f46f7
|
|
BLAKE2b-256 checksum How to use checksums |
de8d44e3dad1cd0a3e6ab33d21f7a1be59251c18a34fb647d63dede644b9bc94
|
| 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 23, 2026.
Transparency log