TL-Agent: Receipt-gated control plane for AI agents
An engineering guide to what TL-Agent is, how it works, and the two ways to deploy it — standard local bundle and air-gapped USB mode. Written so anyone building AI agents can understand why this matters and how to use it.
Contents
- What is TL-Agent — and what it is not
- The problem it solves
- The core principle: NO VALID RECEIPT → NO ACTION
- Two usage modes
- The gate algorithm (6 steps, fail-closed)
- Bundle structure
- Receipt types
- The 10 invariants
- How to use it: from bundle to running agent
- Honest framing: what TL-Agent does not do
1. What is TL-Agent — and what it is not
TL-Agent is a control plane and tamper-evident history for AI agents, built on notarial receipts from the TimeLayer network. In plain language: before your agent can do anything — read a file, call an API, send a message — it must hold a receipt that it cannot have issued itself. If there is no valid receipt, the action does not run. Period.
The word "notarial" here is precise. A receipt is not a log entry your server wrote. It is a cryptographic attestation signed by a quorum of independent operators over the TimeLayer network — operators who each hold independent private keys — no single operator can fabricate a receipt, and the receipt verifies offline on its own, without trusting our infrastructure.
TL-Agent has two layers that are always kept strictly separate:
cert.tlcert+bundle.tlbundle— the notarial receipt itself, a pair of files issued by the network: the signed certificate and the gate bundle the verifier checks together. Never modified, never rewritten. This is the source of truth.envelope.json— the agent's wrapper: action_id, scope, allowed next actions, topology reference. It points to the receipt files. It does not replace them.
Together they form a Receipt Action Unit — one permitted action, cryptographically bound.
What TL-Agent is NOT
Not a memory system — receipts carry no content and do no semantic recall (that is provenance, not knowledge). Not a sandbox that physically stops malicious code — it gates a cooperative agent that uses the SDK honestly. Not a replacement for debug logs — those stay ephemeral developer tools; TL-Agent covers significant actions, not every function call.
2. The problem it solves
You are building an AI agent that does real things in the world: reads files, calls APIs, posts data, makes decisions. You face three problems that don't go away no matter how carefully you write your code:
Without TL-Agent
The agent can "authorize" its own action — by passing a flag it set itself. The same code that decides what to do also decides whether it's allowed.
Action history lives in your server's log. You control the log. A third party cannot independently verify it — they have to take your word.
There is no machine-verifiable boundary between "what the agent is allowed to do" and "what it claims to have done."
With TL-Agent
Permissions are notarial receipts. The agent did not issue them — the network did, before the session started. An agent cannot authorize itself (INV-01).
History is receipts. Neither the agent nor you can rewrite them. A third party with the open-source verifier can check any receipt offline with no connection to your servers.
The gate is a 6-step fail-closed algorithm. Any gap — missing receipt, invalid signature, wrong transition — stops the agent and waits for human review.
3. The core principle
NO VALID RECEIPT → NO ACTION
Every action in the agent's topology must have a receipt before it can run. Not a flag. Not a log entry. A receipt from the network that the agent cannot have fabricated. This single rule, applied without exception, is what separates TL-Agent from every self-policing approach.
4. Two usage modes
TL-Agent has a default mode that works on any machine, and an optional air-gapped mode for environments where physical isolation of permissions matters.
Mode 1 — Local bundle
The bundle (permissions + topology + receipts) lives as a folder on the host machine. The agent loads it at startup, runs all gate checks locally, and never makes network calls during execution.
- Works on any machine with the
tl-agentbinary - All verification is offline (no internet during gate checks)
- Bundle is created once via the Agent Builder in the cabinet
- You keep a copy of the bundle outside the agent's environment (INV-08)
Mode 2 — Air-gapped USB
For industries where you need physical isolation of permissions: legal, medical, financial audit, classified workflows. Two strictly separate media:
- Read-only removable drive — holds the permission bundle (
cert.tlcert+bundle.tlbundle, topology, policies). The agent mounts it, reads, verifies, acts. Never writes here. - Separate append-only drive — receives raw results (what was done + hash). Attestation of results happens outside the agent environment, so the agent cannot fabricate a result receipt.
Why two separate media in air-gapped mode
If permissions and results share one writable location, the agent could overwrite its own permissions or inject a fake result. Splitting into read-only permissions and append-only results eliminates that — it enforces INV-01 (agent cannot issue receipts) and INV-02 (agent cannot modify the bundle) at the hardware level.
Honest limits of air-gapped mode
Air-gap protects against the agent, not against a compromised host OS. A compromised operating system can intercept reads from the drive at the moment they happen. Hardware write-protect on the USB is real protection; software "read-only" a privileged agent can bypass. Also: you can verify receipts and read permissions offline, but issuing a new notarized receipt (the network signature) still requires a moment of connectivity with the quorum.
5. The gate algorithm — 6 steps, fail-closed
Every time the agent wants to perform an action, it calls bundle.check_action(action_id). The SDK runs this sequence — fail-closed at every step:
Any check that fails → immediate STOP. The stop reason is returned to the caller. The stop policy requires human review before the agent proceeds. There is no "soft fail" or "warn and continue."
match bundle.check_action("action_read_files") { CheckResult::Allow(receipt) => { // receipt is the notarial proof — run the action } CheckResult::Stop { reason, message, .. } => { // reason: NO_RECEIPT | REVOKED | TOPOLOGY_DENIED // | TLSIG_INVALID | TRANSITION_DENIED // stop and surface to the human — do not continue silently } }
Exit codes for the CLI: 0 = ALLOW, 1 = STOP. This makes it trivial to wire into any shell script or CI pipeline.
6. Bundle structure
A bundle is a directory. You create it once via the Agent Builder and hand it to the agent. The agent reads it; it never writes to it.
agent-bundle/ manifest.json ← bundle ID, owner, receipt count, flags topology.json ← allowed transitions between actions (the graph) policies/ agent_policy.json ← what the agent may not do tool_policy.json ← which tools are permitted stop_policy.json ← when the agent must halt receipts/ <action_id>/ envelope.json ← action metadata + allowed_next_actions cert.tlcert ← notarial certificate — NEVER modified bundle.tlbundle ← gate bundle, verified with the cert — NEVER modified
Key rule: cert.tlcert and bundle.tlbundle are never touched after they are placed here. envelope.json only references them — it does not replace them. The two verify together offline with no roster or external lookup. manifest.json explicitly declares "agent_can_write": false and "agent_can_issue_receipts": false.
What topology.json defines
Topology is the graph of what actions are allowed and how they may follow each other. If your agent tries to jump from action_read_files to action_send_email but the topology only allows action_summarize next — that is a STOP. The agent cannot reorder its own workflow.
7. Receipt types
Each action in the bundle has a receipt with a type that describes its role in the workflow:
| Type | Purpose |
|---|---|
| permission_receipt | Authorization to perform an action — required for every action (INV-03) |
| identity_receipt | Who created the task (establishes the human principal) |
| task_receipt | Binds the task definition — what the agent is doing and why |
| scope_receipt | Defines boundaries: which paths, read-only vs read-write, network access |
| tool_receipt | Authorizes a specific tool for use |
| execution_receipt | Records that an action was executed (with result hash) |
| result_receipt | Attests the result of an action |
| validation_receipt | Confirms the result passed validation (required when stop_policy demands it) |
| stop_receipt | Authorizes a stop command |
| revoke_receipt | Revokes a previously issued permission |
| final_receipt | Marks the end state of the workflow |
8. The 10 invariants
These are the rules that cannot be broken. If a feature violates any of them, the feature is wrong — not the invariant. The invariants are the product.
| ID | Rule |
|---|---|
| INV-01 | The agent does not issue valid receipts itself — they come from the network |
| INV-02 | The agent does not modify the user's bundle |
| INV-03 | Every action requires a permission_receipt |
| INV-04 | Every transition is validated against topology.json |
| INV-05 | Any conflict → STOP (no soft-fail, no warn-and-continue) |
| INV-06 | The model's text output is not proof of anything |
| INV-07 | PASS is impossible without a validation_receipt when required by policy |
| INV-08 | The user stores the bundle outside the agent's environment (offline copy) |
| INV-09 | The receipt (cert.tlcert + bundle.tlbundle) is never modified after issuance |
| INV-10 | envelope.json only references the receipt files — it does not replace them |
9. How to use it: from bundle to running agent
Step 1 — Build your bundle in the Agent Builder
Go to cabinet.timelayer-os.com/agent. Define your actions and topology visually. Each action gets a receipt notarized by the network. Download the ZIP. Unpack it — that is your bundle.
Step 2 — Gate-check before every action
# In a shell script or CI pipeline: tl-agent check ./agent-bundle action_read_files # exit 0 = ALLOW, exit 1 = STOP # See what actions are allowed next: tl-agent next ./agent-bundle action_read_files # Audit the entire bundle: tl-agent audit ./agent-bundle
Step 3 — In a Rust agent
let bundle = AgentBundle::load("./agent-bundle")?; loop { let action = agent.decide_next_action(); match bundle.check_action(&action) { CheckResult::Allow(receipt) => { agent.run_action(&action, &receipt); bundle.record_execution(&action, &result_hash)?; } CheckResult::Stop { reason, .. } => { // surface reason to the human — do not loop break; } } }
Step 4 (air-gapped) — USB mount instead of local folder
Mount the read-only USB drive at startup. Pass its mount point as the bundle path. Point results to a separate append-only drive. Everything else is identical — the SDK does not know or care whether the bundle is a folder on disk or a mounted drive.
# Mount the read-only permissions drive mount -o ro /dev/sdb1 /mnt/permits # Run the agent with the mounted bundle tl-agent check /mnt/permits/agent-bundle action_read_files
10. Honest framing: what TL-Agent does not do
- Not memory. Receipts carry no content. They do not store what the agent said or found. They record what was permitted and what was executed (provenance), not what the agent knows (recall).
- Not a sandbox against a hostile host. If the operating system is compromised, a sufficiently privileged process can intercept or spoof reads from the bundle. TL-Agent gates a cooperative agent. Air-gapped mode narrows but does not eliminate this surface.
- Not a replacement for observability. Debug logs, traces, and metrics remain your developer tools. TL-Agent covers significant externally-verifiable actions — not every internal function call.
- Attestation requires connectivity. Verifying existing receipts is fully offline. Issuing a new receipt — getting the network's quorum signature — requires a moment of connectivity. Plan your workflow accordingly.
- Not a guarantee of agent correctness. An agent with a valid receipt can still produce a wrong result. TL-Agent proves what was permitted and what was attempted — the human reading the audit trail still judges whether the result was good.
The one-line summary
TL-Agent gives the agent permissions it cannot issue itself, and history it cannot rewrite — under the rule NO VALID RECEIPT → NO ACTION. It is not memory, not a sandbox from the host, not observability. It is a tamper-evident control plane for a cooperative agent.
TimeLayer