A fresh sandbox for every run
A new container or microVM: non-root, no capabilities, its own network, gone when the run ends.
A ticket asks for a docs update, an agent writes it, a pull request comes out. Watch where each guard sits on the way. Everything inside the dashed line runs on your servers.
Only your trigger rules start work, with limits on floods. Tinfirm polls your trackers, so it needs no inbound port, and marks outside text as data for the agent.
The walkthrough follows one job. Here are the guards it passes, side by side, and each is explained further down.
A new container or microVM: non-root, no capabilities, its own network, gone when the run ends.
Tools run on Tinfirm's server, git goes through a fetch-only proxy, and model calls carry a dummy key.
Each tool reads or writes, writes ask a person by default, and settings can only narrow that.
Time, tool calls, loops and silence are capped, and any credential in the output stops the run.
The runner host pushes the agent's branch with a lease check, after scanning the commits. A person merges.
Row-level security is forced in PostgreSQL on every company table, and tested.
Append only, verified every day, exported for checks on your own machine.
Runner hosts connect out, trackers are polled, and the model gateway has no ingress.
Every run starts in a new container, or a new microVM, on one of your runner hosts. The agent works there on a fresh copy of the repositories it may use, and the sandbox is gone when the run ends.
Tinfirm's server runs the tools that reach your systems, the runner host pushes and fetches git, and the host's model proxy carries the model calls. The agent gets results, not keys.
Runner hosts connect out to Tinfirm, Tinfirm polls your trackers, and your model gateway stays inside the deployment. Every connection, and which way it goes:
People sign in through your identity provider, and every request is checked against their role, their company and, for an AI client, the scopes a person granted.
Every action that changes something is written to an audit log in which each entry carries the hash of the one before. Change or remove an entry and the chain no longer adds up.
Everything Tinfirm stores lives in your PostgreSQL. The company's Owner sets how long each kind of data is kept; open conversations and legal holds are never purged.
The server's base images are pinned by digest and the CI actions by commit, with lockfiles committed and updates proposed weekly. The runner's tools are pinned and checked against their checksums, with auto-update off.
Static analysis, secret scanning and dependency CVE checks run on every pull request, on every push to the main branch, before every release and once a week.
The server runs as a non-root user on a read-only root filesystem with every capability dropped and seccomp on. A network policy admits only your ingress, and the management port is never exposed.
The bundled LiteLLM has no ingress and its admin UI is off; on Kubernetes only the server's pods may reach it. Runner hosts never reach it: the server relays their model traffic.
Every product has edges. These are Tinfirm's today, from its threat model, so you can weigh them before you decide, not after.
Something we missed? Ask us.
On your own servers. There is no Tinfirm cloud.
You run the app, its PostgreSQL database and the runner hosts. Runner hosts connect out to Tinfirm, and Tinfirm polls your trackers, so neither needs an inbound port. The model provider you pick sees the prompts you send it.
Not your system keys. They stay with Tinfirm and the runner host.
Inside the sandbox the agent has a dummy model key and a token that works for one run only. Tool calls run in Tinfirm with the connection's credentials, the git proxy can only fetch, and output with a credential in it stops the run. One exception: when a person brings their own Claude or ChatGPT subscription, that login runs inside their own sandbox, on their own runner host.
In an encrypted vault, and no API ever hands one back.
Each secret is sealed with AES-256-GCM under its own fresh key. The master keys live outside the database, and you can rewrap and rotate them. Every use of a secret is logged.
It reads the ticket as data, and it has little to give away.
Text from outside is marked as data before the agent sees it. That lowers the risk; no one can promise to prevent prompt injection. So the guards above still hold: no system keys to leak, tools only as far as you allowed them, no force push, and a person merges.
No. The database itself keeps them apart.
PostgreSQL row-level security is forced, not left to the app, and isolation tests check it. A person's own work uses their own account, with no fallback to a shared one, and read-only accounts cannot write.
No. Its own writes never start new work.
A comment or label Tinfirm writes back to your tracker is recognised as its own, so it cannot set off another run. Floods of outside events are limited too.