TimeLayer Engineering Notes TL-Agent
Engineering AI Agents Control Plane ~15 min read

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.

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.

Default

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-agent binary
  • 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)
Option

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:

1. Receipt exists?
2. Status active?
3. In topology?
4. Receipt valid?
5. Transition allowed?
ALLOW

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:

TypePurpose
permission_receiptAuthorization to perform an action — required for every action (INV-03)
identity_receiptWho created the task (establishes the human principal)
task_receiptBinds the task definition — what the agent is doing and why
scope_receiptDefines boundaries: which paths, read-only vs read-write, network access
tool_receiptAuthorizes a specific tool for use
execution_receiptRecords that an action was executed (with result hash)
result_receiptAttests the result of an action
validation_receiptConfirms the result passed validation (required when stop_policy demands it)
stop_receiptAuthorizes a stop command
revoke_receiptRevokes a previously issued permission
final_receiptMarks 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.

IDRule
INV-01The agent does not issue valid receipts itself — they come from the network
INV-02The agent does not modify the user's bundle
INV-03Every action requires a permission_receipt
INV-04Every transition is validated against topology.json
INV-05Any conflict → STOP (no soft-fail, no warn-and-continue)
INV-06The model's text output is not proof of anything
INV-07PASS is impossible without a validation_receipt when required by policy
INV-08The user stores the bundle outside the agent's environment (offline copy)
INV-09The receipt (cert.tlcert + bundle.tlbundle) is never modified after issuance
INV-10envelope.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.