Open source · Python, standard library only · enforced by the Linux kernel

Give every process an AI agent starts
a policy the kernel enforces.

SHarness runs an agent's tools as small processes, each under a Process Behaviour Policy: what it may read, write, run and connect to, named by one hash the person supplies. A tricked agent cannot widen it, because the kernel was told before the process started. Today that is a CLI you can run on Linux, a kernel that boots in your browser to prove it, and a design for the launcher that binds the agent itself.

Try it in your browser → Start in 60 seconds Read the design →
status: experiments sharness-ai v0.2.0 is on PyPI (29 Oct 2026). Two doors, sharness.fs and sharness.net, run as MVPs, with the launcher's first slice (a Setting, except for the one shell it starts); no other component is built; every measured figure carries its date. What exists today →

The one idea

A policy you can hash, a kernel that enforces it on the process, and a launcher above the agent that starts only what the hash names. The first two run today; the third is the design.

Animated: a Process Behaviour Policy is written, hashed to one SHA-256 name, and handed to the kernel before the agent's tool starts; the tool's reads and workspace writes are allowed, its connect to port 80 and its 200 MiB allocation are refused.
1Write what one process may doFiles it may read, write and run; ports it may connect to; how much memory and how many processes. A few lines of JSON. Nothing else is allowed.
2Hash it: that is its nameCanonical JSON, SHA-256. The person supplies the hash from outside the agent, so a prompt-injected agent cannot widen the policy without changing the name.
3The kernel enforces itLandlock rules per path and port, a network namespace, rlimits and cgroups, applied before execve. The process and everything it starts can only lose rights.
4The caveat, every timeApplied by a process to its own child it is a Boundary for the child and only a Setting for the process. The launcher above the agent, which makes it a Boundary for the agent too, is the design.

See it hold

sharness-ai hello is the acceptance test: six probes under a deny-all policy, each expected to be allowed or refused. This is the run, replayed.

Animated terminal: sharness-ai hello runs six probes; read allowed; writes to /tmp and the workspace refused; a TCP connect refused; a 400 MiB allocation refused under a 128 MiB cap; a wrong hash runs nothing; result 6 of 6 held; then the caveat.
6 of 6

held in five places: a cloud session, your browser, headless Chromium, Node and a chroot on the host kernel

3 kernels

the host's, an emulated one in a browser tab, and an emulated one in Node: the same files, the same result

7 policies

from a hello world to the sgit CLI, each hashing to the same value in Python, in the browser and in the Linux guest

243 tests

on Python 3.11, 3.12 and 3.13, on every push to the CLI's dev; 0.6 s for the whole hello run on real hardware

Measured 24 to 29 October 2026, as of 29 Oct 2026, with method on Evidence §9. Your machine is the next row: report what hello said there.

Start in 60 seconds

Three ways in. None needs a component that does not exist yet; each runs the experiments that do.

In your browser · nothing to install

The playground

Two terminals in one tab. Pyodide: Python in WebAssembly, where pip install sharness-ai gives you policy hash, check and translate. Linux: Alpine with a Landlock kernel, where every sharness-ai run is enforced. One policy, hashed three ways.

$ pip install sharness-ai
sharness:/work# sharness-ai hello
result      6/6 held
Open the playground →   Or just watch the kernel boot →
On Linux · 5.13 or later

In a terminal

Standard library only, so the install is one line. probe prints what a process here can do before any policy; hello checks that a policy holds; run puts any command under one; shell opens a shell whose only way out is the hosts you name (as root, under a fresh user made for it).

$ pip install sharness-ai
$ sharness-ai probe
$ sharness-ai hello
$ sharness-ai run --policy p2-tool-server.json -- my-tool
$ sharness-ai shell --sites pypi.org
# v0.2.0 on PyPI; the latest: pip install git+https://github.com/SHarness-AI/SHarness-AI__CLI@dev
The CLI →   Every command with its output →
In a Claude Code session

A skill that runs the experiments

The CLI repository carries a skill that installs the package, runs probe and hello inside the session under the design's safety rules, and reports in the site's status words. It also says, every time, that a policy the session applies to its child does not bind the session.

> run the sharness hello
sharness-ai hello … result 6/6 held
caveat: a Boundary for the child, a Setting for this session
The skill →   What Claude Code's sandbox gives, and what this adds →

A real Linux kernel, in your browser tab

The claim "the kernel enforces it" should not need you to trust a screenshot. So the kernel boots in the tab: Alpine Linux with Landlock, under an x86 emulator in WebAssembly, running the same package and the same policies. Nothing installed, no account, 25 MB of static files.

Animated: a browser window opens sharness.ai, v86 starts, Linux 6.18 boots and prints landlock: Up and running, sharness-ai hello holds 6 of 6 at 28.5 seconds, and the example policies refuse a write, a port and an allocation. Beside it: 28.5 s, 3 kernels, 25 MB.
→Watch itThe scripted run: probe, hello, run under the example policies, on the serial console. Boot it →
→Type into itThe same guest with a shell on its serial line, next to Pyodide. The playground →
→Read how, and what it does not showThe research, the build, what held where, what did not work at first. Linux in a tab → · the write-up →

Who it is for

Three people, one policy format. The policy is the centre; every enforcer, ours included, is a target for it.

You run coding agents

Put the agent's tools under a policy today

A Claude Code session, an orchestrator, a script that calls tools: start each tool with sharness-ai run --policy … and the kernel holds it to the file, port and memory limits you wrote. P1 and P2 are the profiles to start from. The caveat applies: the agent's own process is bound only by a launcher above it.

The example policies →
You ship a tool or an MCP server

Ship the policy with the tool

Write the policy your tool needs, hash it, and publish both. Whoever runs your tool runs it under that hash, and sees exactly what you asked for: a read-only workspace, one port, a memory cap. A tool that needs less is easier to trust.

Process Behaviour Policies →
You run a platform

One policy, every enforcer

sharness-ai policy translate writes the same policy as a bubblewrap command, a docker run, a Claude Code sandbox setting or a Kubernetes Pod and NetworkPolicy, and lists what each of those cannot enforce. The enforceability matrix is that list, row by row.

The enforceability matrix →

Help us measure it

A claim that the kernel enforces a policy is only as good as the kernels it was checked on. So far that is one cloud session, one browser and one emulator. Your machine is the next row. Run the acceptance test and paste what it said:
$ pip install sharness-ai
$ sharness-ai hello --json
then open a hello report on GitHub (two fields: the JSON, and anything odd). Every report goes on the machines page with its kernel, Landlock ABI and result, including the ones that did not hold: a refusal that did not happen is the most useful thing you can send. Nothing in the JSON identifies you; probe prints the names of proxy variables, never their values.

The operating system a process sees

Bound everything a process can do and what is left is its policy: no filesystem of its own to write, no network stack, no key, no shell, no model API. In their place, five doors, each a small REST service on loopback with its own uid and policy, and the bootstrap that started them. Two run today as MVPs, sharness.fs and sharness.net, with the launcher's first slice, sharness-ai shell; the others are designed. The locks under them all run today.

Animated: the process in the middle with its kernel locks; around it the doors sharness.fs, sharness.net, sharness.llm and sharness.bash, with sharness.kms behind net and llm; the launcher below. Requests appear one at a time with their verdicts: a write allowed, a clear key refused, an allowed host served over TLS, another host refused, the model call with the key added and a result filtered, the KMS answering with a key sealed to a one-time key, and a direct connect refused by the kernel.
start here

sharness.bash: the shell, as a service

Each command in a fresh sandbox under a profile, output filtered. Where every lock is applied at once, and the first to build: once a command can only run through this door, the other doors are the only ways out.

Read →
runs as an MVP · worth it alone

sharness.net: the only network client

The TLS client, so the hostname is seen and verified; host, endpoint and id allowlists; no redirects elsewhere, no IP literals; a log of every request. It runs today as sharness-ai net serve, and sharness-ai shell makes it a shell's only way out.

Read →
secrets

sharness.kms: where a secret lives

Opens sealed things, derives what the caller needs, re-seals it to a one-time key. Never returns a clear key; frozen between calls; its page unreadable even by root.

Read →
files · runs as an MVP

sharness.fs: the only writer

Writes under the root it owns, inside the rules, and refuses anything that parses as a clear key, a private key or a token.

Read →
the model

sharness.llm: the only model client

The Messages API, unchanged, with the key out of the agent's process, the tool list pinned, and a secret filter on every tool result.

Read →
the bootstrap · first slice runs

sharness.launcher and the manifest

Refuses unless the manifest hashes to what the person supplied; one uid per component; a session CA. Who runs it decides what the locks are.

Read →

Every door speaks HTTP over loopback under mutual TLS, so any language can call it and every request has a verdict and a log line; a handshake costs about 3 ms. The components, as an operating system → · how they work together: the brief → · which layer refuses a call between two roles →

Articles

Dinis Cruz's memos in his voice, and the agents' record of what they delivered, each with the commits to check it against.

cli@sharness · 26 Oct 2026

From a sentence to the kernel

What the levels look like in a terminal: one sentence compiled to the rules the kernel holds, one hash per level, and how a person goes from simple to deep.

Read →
cli@sharness · 26 Oct 2026

The CLI is the front door

How sharness-ai should greet, guide and show: every screen ends with the next command, every refusal names who refused.

Read →
cli@sharness · 25 Oct 2026

Linux in a tab

A real kernel enforces a Process Behaviour Policy in Chrome: what is in the tab, what held where, what did not work at first, how it fits together.

Read →
Dinis Cruz · 24 Oct 2026

A secure harness for agents

Behaviour policies enforced from outside the agent, one small component at a time, starting with my own Claude sessions.

Read →
All

Every article

Newest first, with who wrote each and how; each with a markdown twin.

Open →

What this site claims, and how

The same distinction runs through every page. Every number is labelled; nothing is presented as built.

LabelMeans
MeasuredProbed or timed in a named environment on a named date, with the method on Evidence. For example: hello 6 of 6 in five places; a mutual TLS handshake between components ≈ 3.2 ms; a memfd_secret page unreadable even by root.
RunnableThe code is in the repository and its tests pass: probe, policy hash, check, translate, run, hello, doctor; contain, profile and explain (the levels); fs serve and net serve (two doors, Settings until the launcher gives each its own uid); shell (the launcher's first slice); the browser bench, the playground.
Designed / proposedHow SHarness would work: .kms, the launcher above the agent and its manifest, the KMS protocol, the policy layers, .llm, .bash, the deployment topologies.
Never claimedThat any component is a Boundary before the launcher gives it its own uid; protection against root or kernel compromise; anything about any platform's plans; that a schema bounds intent (it bounds shape).

The roadmap and open decisions → · the source documents, verbatim → · about and naming → · getting users: the review and the plan →