Production & headless agents
Getting a deployed agent — a LangChain worker in Docker, a CrewAI job on Kubernetes, an SDK agent in CI — governed and reporting to the console. This is the path for machines with no human at the keyboard and no git repo, which is where the laptop instructions quietly stop working.
Read Connect to the platform for the identity model, and your framework's page (e.g. LangChain) for the code-level wrap.
The short version
FROM python:3.12-slim
RUN pip install "prismor[langchain]"
# Identity: a deviceless agent key, minted in the console.
ENV PRISMOR_AGENT_KEY=prism_agent_...
ENV PRISMOR_AGENT_LABEL=checkout-worker
# Required for a repo-less workload — see "Workspace scope" below.
ENV PRISMOR_WORKSPACE_SCOPE=managed
# Prismor needs a writable home for the policy cache, spool and heartbeat.
ENV PRISMOR_HOME=/var/lib/prismor
VOLUME /var/lib/prismor
COPY worker.py .
CMD ["python", "worker.py"]
# worker.py
from prismor.langchain import guard_tools
tools = guard_tools([run_shell, fetch_url]) # every call policy-checked
Then verify from inside the container:
prismor doctor
Every check must be ✓. The four that decide whether anything reaches the
console are enrollment, workspace scope, telemetry sink and
remote policy.
1. Identity: mint an agent key
A deployed workload has no browser, so prismor login does not apply. Two
options:
Agent key (recommended). Console → Connections → SDK & deployed agents
(or Admin → Devices) → Mint agent key. Copy it immediately — it is shown
once. Set it as PRISMOR_AGENT_KEY. The key is read from the environment and
never written to disk, so it survives a read-only root filesystem.
PRISMOR_AGENT_KEY=prism_agent_xxxxxxxx
PRISMOR_AGENT_LABEL=checkout-worker # optional, names it in the fleet
PRISMOR_API_BASE=https://www.prismor.dev # optional, for self-hosted
Enrollment token. Mint a token in the console and run
prismor enroll <token> at container start. This writes
$PRISMOR_HOME/identity.json, so the home must be writable and persistent, and
the token is single-use — a restarting container will fail the second time.
Prefer the agent key.
Every event from an agent key is attributed to the admin who minted it, since the underlying service identity needs an owner. Mint one key per workload and label it, so the fleet view stays readable.
2. Workspace scope: the setting that decides if anything is reported
This is the most common reason a correctly-installed agent shows up empty.
Scope is normally inferred from the workspace's git remote: a repo matching
one of your org's claimed patterns is managed, anything else is the
developer's personal space. Scope gates the org policy overlay — and that
overlay is what carries the telemetry sink. A container has no git remote,
so if your org has claimed any repo patterns, a deployed workspace falls through
to local and reports nothing at all.
Set it explicitly:
PRISMOR_WORKSPACE_SCOPE=managed
Requires prismor >= 1.37.0. On earlier versions, run
prismor workspace managed at container start instead (needs a writable
$PRISMOR_HOME and the same working directory every run).
An org-claimed repo pattern always wins over this variable, so a deployment can
never use it to opt company code out of governance. Use personal to
deliberately keep a workload's traffic out of the org.
3. A writable PRISMOR_HOME
Prismor keeps the verified policy cache, its signature, the telemetry spool, the
heartbeat counter and the agent register under $PRISMOR_HOME (default
~/.prismor). Every write is best-effort: on a read-only filesystem they fail
silently, and the result is a re-pull of the policy on every process, a
heartbeat that never accumulates, and spooled events lost on restart.
If you harden the container with --read-only (see
Docker & containers), mount a writable volume and point
PRISMOR_HOME at it:
docker run --read-only \
-v prismor-state:/var/lib/prismor \
-e PRISMOR_HOME=/var/lib/prismor \
-e PRISMOR_AGENT_KEY=prism_agent_... \
-e PRISMOR_WORKSPACE_SCOPE=managed \
your-agent:latest
4. Verify it end to end
prismor doctor
doctor makes one authenticated call to the control plane, so it fails on a
revoked or mistyped key rather than reporting "enrolled" from a local file.
What to look for:
| Check | Healthy | If it fails |
|---|---|---|
enrollment | verified with the control plane — org … | Key is wrong, revoked, or points at another org |
workspace scope | managed (env_override) | Nothing will be reported — set PRISMOR_WORKSPACE_SCOPE=managed |
telemetry sink | authenticated to https://… | Cannot deliver; check egress and the key |
remote policy | v<N>, Ed25519 signature verified | Policy has not been pulled yet — it lands on the first tool call |
capture | FULL or redacted | See below |
prismor enroll-status gives the same identity summary in short form, including
a verified: line.
In the console, the workload appears under Connections → SDK & deployed agents with a last-seen time. If it says never seen, the container has not completed a single authenticated call yet.
Requires prismor >= 1.37.0 for the authenticated checks; on earlier versions
doctor reports reachability only and cannot detect a bad key.
5. What actually gets logged
Two things to calibrate before you judge the console empty.
Findings, not every call. The runtime uploads events for calls that produce
a finding — blocked, warned, or would-block. A benign git status emits
nothing. A well-behaved agent therefore produces a per-minute activity count and
little else, which reads like a broken install but is not one. To confirm the
pipeline, run something that trips a rule:
prismor check "rm -rf / --no-preserve-root"
Redacted by default. Uploaded events carry severity, category, rule id, tool name, session, subject and an evidence hash — not your content. An org admin can opt into full capture (Admin → Org Settings), after which flagged events also carry the scrubbed evidence. This is org-wide and server-enforced: the ingest route stores no detail while it is off, whatever the client sends.
Retention is per-org (Org Settings → telemetry retention, default 90 days, clamped 7–365).
6. Policy, IAM and approvals in production
- Mode. Once a machine is enrolled, the org's signed policy is
authoritative: a locally-passed
mode="observe"no longer suppresses a block. Dry-run a fleet from the console (org or per-agent), not from a keyword argument. See frameworks overview. - Per-user attribution. Wrap request handling in
use_subject("user:alice")so multi-tenant traffic is attributable and per-user IAM applies. - Approvals. A
step_uprule holds a call for a human. Headless agents post the request to the control plane and wait — set a wait budget withPRISMOR_APPROVAL_TIMEOUTand make sure a route or webhook is configured, or the call fails closed after the timeout. See Human-in-the-loop approvals.
Checklist
- Agent key minted and set as
PRISMOR_AGENT_KEY -
PRISMOR_WORKSPACE_SCOPE=managed(repo-less workloads) -
PRISMOR_HOMEwritable and persistent across restarts - Tools wrapped (
guard_tools(...)or your framework's equivalent) -
prismor doctorall✓from inside the container - A deliberate violation appears in the console
- Full capture and retention set to your policy
- An approval route or webhook exists if any rule uses
step_up