Skip to main content

Guardrails & policy

The backend runs a chain of guardrails at defined points in every agent turn. They are part of the api-backend, not the runtime — so they apply no matter how the conversational loop behaves.

What guardrails do​

Budgets. Bound work per turn with model steps, wall-clock time, and parallel tool calls. A per-member daily model-token ceiling is optional; no daily ceiling applies until an operator sets a positive limit.

Citation discipline. Keep answers grounded in retrieved sources rather than in the model's recall. This is enforced, not requested.

Redaction. Remove sensitive content where configured, before it reaches a member response or a model context.

Loop control. Stop runaway cycles and out-of-scope actions.

Where they sit​

Guardrails run on the callback path — the point where the runtime asks the backend to actually do something — and again before a result is published.

That placement matters. A guardrail inside the runtime would be advice to a system that is designed to be flexible. A guardrail in the backend is a condition of execution.

The budget table​

SettingDefaultBound
AGENT_LOOP_MAX_CYCLES10General tool-bearing model rounds; staged artifact protocol calls use a separate derived ceiling while byte, sequence, ownership, and execution fences remain enforced
AGENT_LOOP_BUDGET_MS120000Maximum inactivity between healthy model or tool events
AGENT_LOOP_MAX_PARALLEL_TOOLS1Concurrent tool calls
LLM_PER_USER_DAILY_TOKENS0 (unlimited)Optional per-member daily token cap
LLM_LATENCY_BUDGET_SECONDS5.0Assist-path latency
SEARCH_BRANCH_LATENCY_BUDGET_SECONDS8.0Per retrieval branch
SANDBOX_MAX_WALL_SECONDS30Per code execution
SANDBOX_MAX_OUTPUT_BYTES1 MiBPer code execution

When an operator enables the daily cap, the token check, model call, and audit row run under one per-member database lock, so concurrent turns cannot overspend together. The lock is released after completed streams, refused task authority (503 authority_unavailable), upstream errors, and disconnections before the first streamed token. Without a daily cap, no daily-budget lock or usage lookup runs; model calls are still audited.

Hashline tags never grant write authority​

The four-hex tag in a workspace header is not authority. It resolves only inside trusted state keyed by the authenticated actor and conversation workspace. The retained full text and seen-line provenance stay outside the untrusted workspace tar. A tag from another member, workspace, expired history, or colliding content cannot widen a write.

edit_workspace enters the ordinary write guard once for the complete patch. The sandbox worker rejects absolute paths, traversal, symlinks, unauthorized tag-based path recovery, unseen anchors, ambiguous recovery, oversized files, and duplicate destinations before committing. Multi-file PUT, CUT, REM, and MV operations stage together and roll back together. The pinned Hashline helper receives bounded text and snapshot metadata but no identity envelope, bearer, object-store key, or direct filesystem access.

Artifact Hashline edits use a separate authority path rather than aliasing an artifact to a workspace file. read_artifact and edit_artifact resolve the exact artifact under the forwarded member identity, immutable version, and content tag. A foreign source is readable or remixable only when the active room projection authorizes that exact version; the completed result becomes a new actor-owned root and the creator's root remains unchanged.

The edit enters WriteToolGuard, rejects overlapping or out-of-range hunks, and relies on the artifact store's locked version check before appending one version. Streamed replacement text and hidden React/Mermaid validation frames are disposable pane projections over the committed base. They are not persisted or shared as completed artifacts when syntax, authorization, or concurrency checks fail.

Exhaustion is a policy outcome, not a crash​

When model-step budget runs out, the turn does not simply fail. The engine grants one forced-synthesis step: answer from the evidence already gathered.

The member gets a bounded, cited answer with a clear limitation instead of an error, and the run still records exactly one terminal outcome. Failing loudly at the budget edge would have been easier to implement and worse for everyone.

Conditional correction is not authorization​

An operator-authored stream-correction rule may discard a matching response before it becomes visible or durable, inject a fixed reminder, and recapture a new provider step. Rules are manifest-bound, attempt-bounded, and record only their ID.

They improve model behavior; they do not protect a resource. A model can produce wording that no pattern anticipated, and no correction rule can grant, approve, or execute a tool. The backend's snapshot validation, capability ceiling, member authorization, approval gate, and write guard remain the security controls.

Capability ceilings​

Every agent has a maximum set of tools it may use. A read-only capability ceiling can inspect tasks but cannot mutate them, regardless of what a prompt asks for.

Two ceilings must both allow a call: the agent's capability ceiling, and the member's own permissions resolved at call time. Neither is evaluated inside the model, so neither is negotiable from inside a prompt.

Prompt injection​

Connector content, uploaded documents, tool results, and remote agent responses are all untrusted text. Any of them may contain instructions aimed at the model.

Kaizen's defense is structural rather than detective. Untrusted content:

  • arrives as evidence, subject to citation discipline;
  • cannot grant a tool, widen a scope, or raise a capability ceiling;
  • cannot approve an action or alter the turn's authority bundle;
  • cannot supply an identity or a role.

A successful injection changes what the model says. It does not change what the backend permits. That is the whole design: the boundary is placed so that model compromise is contained rather than catastrophic.

Grounding​

An answer that cannot find support should say so rather than guess. Grounding instructions join the shared system-prompt composition chain, and citation discipline is checked on the backend side.

Because composition is shared, every agent gets the same grounding treatment. An individual agent definition cannot opt out of it.

Structured artifact output​

Remote tools and reviewed skills may return a versioned renderable-artifact envelope. Kaizen validates and canonicalizes it at the shared tool-result boundary before the normal owner-scoped Artifact writer runs. The envelope must retain security markings plus cluster, dataset, or job provenance; missing, oversized, non-JSON, or path-bearing download metadata fails closed.

The reserved Artifact language is not model authority. Direct create_artifact and update_artifact calls reject it. Only a validated trusted tool result or declared MCP artifact contract receives the call-scoped server attestation required by the writer, so an LLM cannot label invented provenance or markings as governed output. A vendored package's declared side outputs are rebuilt from allowlisted fields at the package boundary, which drops an envelope, a materialization key, and the reserved language, so package code cannot route its own output down the attested path either.

That attestation protects the model-to-writer boundary; it is not independent proof that a producer told the truth. For a generic MCP version 2 artifact, the administrator-approved registration of the server and tool is the trust root. Kaizen proves that the selected producer's output passed the bounded envelope contract and was written through the authorized path, not that its asserted source, provenance, or markings are factually correct. A careless or compromised producer can mint false metadata that remains schema-valid. Administrator review, controlled enablement, and prompt revocation of suspect producers are therefore part of the security boundary.

The streamed-create boundary also fails closed while that reserved pair is still possible. No incomplete create_artifact opens a durable checkpoint, even when an early language looks non-reserved: a later duplicate JSON key can replace it in permissive JSON parsers. The checkpoint adapter instead rejects duplicate keys and reads only the completed top-level object. Ordinary unique-key calls still materialize after that parse. If a turn is interrupted first, the call is terminally fenced and there is intentionally no partial checkpoint to resume; preserving one would allow later argument bytes to claim the reserved language after model-authored content was already stored. Updates keep their live checkpoint behavior because they target an already owner-resolved artifact.

An envelope carries either the exact authorized JSON result or an opaque, SHA-256-bound result reference. References are never browser-fetchable URLs. This release validates and preserves result_ref, but does not resolve it. Every referenced result remains inert: the browser labels it, displays the producer's text_fallback, and retains the opaque reference only in the JSON view and download. No backend resolver or browser fetch runs. A future reviewed server-side adapter may resolve a reference only under the current member and room authority; a missing or changed result must fail closed, and resolution must never launch a replacement remote job or infer data removed upstream. Structured portion markings remain a map through persistence and rendering. A missing markings object or upstream markings_error prevents artifact creation; no renderer may flatten, infer, or default the markings. Updates revalidate the entire envelope and reject any change to its provenance or markings, so a later payload cannot relabel itself onto a prior binding. Server-mediated fork and remix operations may copy a governed Artifact only by cloning its stored language and exact envelope bytes. The derived library root preserves the original markings and provenance, grants no new producer attestation, and remains subject to the same revision guard. Copy requests cannot provide replacement content or transformed envelope fields.

The database stores a separate server-attestation marker on every Artifact version. A check constraint rejects the reserved renderable language unless that marker is present, so model-authored staged drafts and old application replicas cannot mint governed rows by choosing the reserved kind and language pair. Trusted creation stamps the marker once; later versions, forks, and member remixes can preserve it only while copying the exact stored governed bytes. A shared-room collaborator cannot use the ordinary update path to substitute model-authored content into a governed copy.

No renderable-artifact iframe adapter or READY/DELIVER flow ships in this release. Governed artifacts use the native table or inert text fallback; the existing general-purpose Artifact frame is not a governed renderer. A future iframe adapter is admitted only with a fixed same-origin route and a fresh base64url channel carried only in the URL fragment. Uppercase READY and one-shot DELIVER messages must bind to the exact frame window, exact origin, and channel. Each side must reject mismatched source/origin/channel, replay, and unexpected schema or type literals. The parent must never use a wildcard target origin or broadcast artifact data to other frames.

Producer data never becomes HTML. The reviewed table view uses native browser text nodes, unknown renderer names show the envelope's text fallback, and the download is the inert canonical JSON envelope. A renderer name is data, not a plugin or capability grant. The member and room ACL remain authoritative; markings cannot widen them.

Member metadata routes cannot revise, rename, publish, or attach a governed Artifact to a conversation. Those operations fail with validation_failed before changing its attested bytes or title or creating a conversation or share grant. Owner resolution happens first, so a foreign governed root remains a not_found response instead of revealing its type. Ordinary Artifacts retain those operations, and an already-published governed result can still be unpublished to reduce access. A governed Artifact produced inside a shared chat may already be scoped to that room by the server-attested producer path; the member attach route cannot move an existing library result into another room.

On upgrade, migration 0116_legacy_artifact_quarantine removes false attestation from rows that predate this boundary. Every historical member_artifact version whose kind and language happen to form the reserved pair is reclassified as ordinary JSON code. Its exact content, title, identity, lineage, version history, ownership, timestamps, and publication state remain unchanged. The migration never interprets those bytes as a governed envelope, and its downgrade is intentionally a no-op: promoting arbitrary JSON back to the reserved language would fabricate attestation.

Migration 0125_renderable_artifact_attestation stamps the explicit marker on the already-quarantined trusted rows and installs the persistent check constraint without scanning the table under its brief creation lock. Migration 0126_validate_renderable_artifact_attestation validates that constraint in a separate transaction under PostgreSQL's lower validation lock. The constraint closes the rolling-upgrade window: an older replica that does not know how to stamp attestation fails closed instead of creating a reserved row after the one-time quarantine has run.

Uniformity is the point​

Streaming, journal projection, retries, timeout salvage, durability, grounding, lifecycle, policy, and error handling are implemented once in the shared pipeline.

An agent definition may declare only genuinely domain-specific persona, capability, tool-grant, and source-selection behavior. This is enforced by boundary tests that walk the source, so "every agent behaves the same way" is a structural property rather than a convention.

The practical consequence: there is no corner of the product where a guardrail is quietly weaker, and no agent that is accidentally more privileged because its feature landed on a different code path.