One file controls what an agent can read, write and reach.
Enforced at the kernel. Auditable by design.
What is hlyn?
An AI agent is a program that reads files, runs commands and uses the internet for you. If it is tricked, it can do all of that against you. hlyn puts a fence around the agent: you list the folders, programs and websites it may use, and the operating system blocks everything else. When something is blocked, hlyn tells you what and how to allow it.
How it works
Any web page or document an agent reads can hide an instruction, and catching every trick isn't realistic. So hlyn assumes one will work and limits what the agent can do. The operating system enforces the limits (Landlock and seccomp on Linux, Seatbelt on macOS), and the agent has no switch to turn them off.
What you control
| You control | In plain words | Flag |
|---|---|---|
| Files | Which folders the agent can read and write. Your keys and other projects stay closed. | --read --write |
| Programs | Which programs it may start. No surprise curl or bash. |
--exec |
| Network | Off by default. Allow named websites, or a port. DNS tricks, raw IP addresses and UDP are blocked. | --net |
| Secrets | API keys and tokens are removed from its environment unless you pass one on purpose. | --env |
| Other agents | One agent can't signal, connect to or share memory with another on the same machine. | built in |
| Dangerous kernel calls | io_uring, ptrace, mount and similar are always refused (Linux). |
built in |
| Warnings | Tells you before the run if the agent could read a secret and reach the internet, or plant a file that runs later. | built in |
| Audit trail | A JSON log of what was locked and what was refused. --json on every command. |
--log |
Quick start
1. Check the machine
hlyn probe
2. Wrap any command (any language)
hlyn run -p coder -- python agent.py # a preset: this folder, any program
hlyn run --read ./src --net 443 --env OPENAI_API_KEY -- ./my-agent
hlyn run -f policy.toml -- ./my-agent # rules kept in a file
3. Or lock a Python program from inside
import hlyn
hlyn.on(read=["./data"], write=["./out"], net=["api.openai.com"]) # from here on, locked
text = hlyn.run(lambda: summarise("/tmp/upload.txt"), read=["/tmp/upload.txt"]) # lock one risky step
4. Claude Code, confined to your project
hlyn claude
It shows a table of what Claude Code will get, asks y or n, and at the end lists what was refused, which plugin or MCP server asked, and the one command to allow what you trust.
Presets: strict (nothing), data, coder, web, debug. Run hlyn presets.
Where it runs
| Linux | macOS | |
|---|---|---|
| Needs | Kernel 6.12+ with Landlock, libseccomp | Any current macOS |
| CPUs | x86_64, aarch64 | Apple silicon, Intel |
| Files, programs, ports, websites, isolation between agents | ✅ | ✅ |
| Dangerous kernel calls blocked | ✅ | not applicable |
hlyn claude |
✅ | ✅ (keychain sign-in) |
Python 3.10+. Zero runtime dependencies. Not supported: Windows, Alpine (musl). Works inside Docker. Details and requirements.
Evidence
Numbers we measured, and where. Nothing here is estimated.
| Claim | Measured |
|---|---|
| Automated tests | 1,327 pass on macOS, 1,498 on Linux, 0 failing |
| Tests can fail | Bugs were planted on purpose and caught |
| Fuzzing of the website filter's parsers | 238 million inputs, nothing found |
| Race harness against the Linux gate | 10 million attempts under plain, ASan and TSan builds, none won |
| Packet capture during bypass attempts | No packet reached an unlisted destination |
| Start-up | hlyn run 92 ms against 202 ms for docker run --rm alpine true (median, Apple M1). A warm docker exec is faster, so the fair line is "faster than starting a container". On GitHub's x86_64 runner: 74 ms against 707 ms. |
| CI | Every push runs the suite on Linux x86_64 (kernel 6.17) |
Honest limits
An environment that oversells itself is worse than none. The three that matter most:
- Data can still go to a website you allowed. hlyn stops the agent reaching other sites, not sending something to a listed one. The rule that matters most: don't let the agent read what it shouldn't send.
- A granted folder is a granted folder. If the agent can write somewhere that something else later runs (a git hook, a scheduled job), that is running code outside hlyn. hlyn names these before the run.
- A kernel bug or a hostile tenant is outside what any process-level boundary covers. For tenants who may attack each other, add a microVM.
The full threat model: what it stops, and what it does not
This is the threat model, in the same words as SECURITY.md.
It stops, for code running inside the environment, including code that deliberately races threads:
- Opening a TCP connection to any host and port not on the list, whether through the proxy, directly, by IP address, or by exploiting a shared port. On Linux the kernel never runs such a connect.
- Reaching private, loopback, link-local or cloud-metadata addresses through a public name, whether by DNS rebinding or by a name that resolves privately.
- UDP of any kind (DNS, QUIC, anything tunnelled over it), raw IP, SCTP, packet sockets, and every socket family other than unix, TCP and route netlink.
- DNS lookups, whether over UDP, over TCP, through the resolver daemons or D-Bus, or through DoH to hosts not on the list, whatever folders are granted. See residual 3 below.
- Unix datagram sockets, which can name any socket file in
sendmsg: none can be made while the network is limited on Linux before 7.1; from 7.1 the kernel checks each one's path. - Reaching a container runtime's socket (
docker.sockand the like), whatever folders are granted. See residual 3 below. - Connections opened before the seal: the sealed child closes them, or
hlyn.on()refuses. - Tricks with how names and addresses are written: case, trailing dots, Unicode confusables, octal, hex or decimal IPv4, IPv4-mapped IPv6, zone IDs, NUL bytes, CRLF.
- A mismatch between the CONNECT target and the TLS SNI.
- Using another environment's proxy, killing or tracing hlyn's own helpers, or answering its own connection checks.
- On macOS, system services that resolve names or fetch URLs on the agent's behalf (
com.apple.dnssd.service,trustd): refused (5.4).
What naming hosts does not stop
- Sending data to an allowed host. A gist on
github.com, an object in a bucket under*.s3.amazonaws.com, or a prompt sent toapi.openai.comall look like normal traffic. This is the third leg of the lethal trifecta (private data, untrusted content, a way out). Host allowlisting narrows that way out; it can't close it for a host the agent needs. The mitigation is still hlyn's first rule: don't let the agent read what it shouldn't send. The secret warning stays on. This point is inferred from how network filtering works; the research found no direct citation for it. - Domain fronting, shared TLS endpoints, HTTP/2 connection coalescing, and ECH on connections that are already open. Without looking inside TLS, the proxy sees the SNI but not the HTTP
Host. A 2024 study found fronting still works on 22 of 30 CDNs, Akamai and Fastly among them. Claude Code's own documentation carries the same warning. - Unix sockets in three corners. On Linux 7.1 and newer with the network off or limited to ports, no gate runs, and Landlock allows every socket file inside a write-granted folder: a refused socket (a resolver's, D-Bus,
docker.sock) that sits in one is reachable.hlyn showwarns when a grant holds one. And before 7.1, a unix datagram socket handed to the agent by a process outside (SCM_RIGHTS, over a socket the policy already lets it reach) can send to any socket file by name. And before 7.1 with the network limited to ports, where hlyn's gate can't take a copy of a program's socket (a stockdocker runrefusespidfd_getfd;hlyn probesays so), it lets each TCPconnect()run for Landlock to check its port, and a program that races its own threads can have such a call reach a socket file instead (found by reading the kernel's source, not measured). Everything else is checked without a race. Every unixconnect()andsendto()naming a path: the gate connects the socket file it checked itself (0 races won in 10 million tries, against 611-781 in 3,000 before). Every otherconnect()while the gate checks socket files: the gate answers it without letting it run. Unix datagram sockets, whosesendmsgcan name any socket file where no filter can read it: while the network is limited on Linux before 7.1 none can be made, andhlyn.on()refuses to seal while one is open (5.3). From 7.1 the kernel checks each datagram's path against the write grants (built, not yet run on a 7.1 kernel). TCP is unaffected. - Other programs on the same Mac. On macOS,
localhost:Palso matches the machine's own network addresses. A process outside the environment that listens on P at the Mac's LAN address could receive agent traffic. - Behind a corporate proxy. The address checks are skipped when chaining to a corporate proxy (5.5).
- Kernel bugs, side channels, and denial of service against the machine. These are the same as for the rest of hlyn. For tenants who may be hostile to each other, use a microVM outer boundary; nono and Sandlock both say the same.
- Services you allow on this machine. An address or
localhost:PORTentry makes that service part of the boundary. A local HTTP or SOCKS proxy, Tor (9050), Docker's API (2375, 2376), the Kubernetes API (6443) or a kubelet (10250) each give full onward reach. hlyn warns when an entry names one of those ports:hlyn: localhost:2375 is Docker's API port. An agent that reaches it controls this machine. Remove --net localhost:2375 unless you mean it. - Other processes on the machine. Processes outside the environment can connect to the proxy's port like any local port, and can write a PROXY header themselves. They reach only the allowlist, which they could reach anyway. Blocks they cause show up in this run's report.
- Mach services on the macOS allowlist. Each one is measured before it goes on the list (5.4), but a service that acts for its caller in a way no test covers would be a route out. The list starts empty and stays short.
Documentation
Reference: every flag, the policy format, the Python API, the log and the FAQ.
Security
Found a way out? Email founders@hlynai.com. SECURITY.md says what to include.
Develop
pip install -e '.[dev]' && python -m pytest # macOS or Linux
tools/linuxtest.sh # Linux suite in Docker
License
Apache-2.0. See LICENSE.
Metadata
Release files for hlyn 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hlyn-0.4.0.tar.gz | 458.7 kB | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hlyn-0.4.0-py3-none-manylinux_2_28_x86_64.whl | Python 3 | none | Linux glibc 2.28+ x86-64 | Details |
| hlyn-0.4.0-py3-none-manylinux_2_28_aarch64.whl | Python 3 | none | Linux glibc 2.28+ ARM64 | Details |
| hlyn-0.4.0-py3-none-macosx_11_0_universal2.whl | Python 3 | none | macOS 11.0+ universal2 (ARM64, x86-64) | Details |
Total release size: 1.5 MB
Release files / hlyn-0.4.0.tar.gz
| Download URL | hlyn-0.4.0.tar.gz |
|---|---|
| Size | 458.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
00bd4f925d6ee95c6c7dc521976f24e054646d4bb572fa13250b96929f999da3
|
|
BLAKE2b-256 checksum How to use checksums |
3b72ba91eaf71af16d98eb0968e45e5b8c2b4af6041d89dc390581b27335fc69
|
| 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 Oct 2, 2026.
Transparency logRelease files / hlyn-0.4.0-py3-none-manylinux_2_28_x86_64.whl
| Download URL | hlyn-0.4.0-py3-none-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 409.9 kB |
| Tags | Linux glibc 2.28+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
83c7741b9af642ab47fdcdd3e43b9b785cdbaba3a589b278e37051ec9351b3c5
|
|
BLAKE2b-256 checksum How to use checksums |
106de759a65929855649fd93ce120ebc5b9604bb317810f9ecab28f90d0d6c0a
|
| 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 Oct 2, 2026.
Transparency logRelease files / hlyn-0.4.0-py3-none-manylinux_2_28_aarch64.whl
| Download URL | hlyn-0.4.0-py3-none-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 404.0 kB |
| Tags | Linux glibc 2.28+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
5a58443b3f49d8b6e3bc0d500a5bfcdc5356abfa2f4552e3283b2eaf42c03602
|
|
BLAKE2b-256 checksum How to use checksums |
880939bb0360b312bb607eb769b200cc8341e8188d3169884dfc1bab716d0d99
|
| 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 Oct 2, 2026.
Transparency logRelease files / hlyn-0.4.0-py3-none-macosx_11_0_universal2.whl
| Download URL | hlyn-0.4.0-py3-none-macosx_11_0_universal2.whl |
|---|---|
| Size | 235.9 kB |
| Tags | Python 3 macOS 11.0+ universal2 (ARM64, x86-64) |
|
SHA-256 checksum How to use checksums |
521f34e98e8c21c8e3eb4414187a5afd4da2e8ac8be58a943a93662911b0b373
|
|
BLAKE2b-256 checksum How to use checksums |
298c7d1b4a53f3dee4ee75a3ac61b2c7f3aabcf7970bc7957341df5773d07d18
|
| 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 Oct 2, 2026.
Transparency log