Operating agent sessions¶
In short
- Each agent's command line is verified against one CLI build: Codex 0.162.1, Gemini CLI 0.62.0, Claude Code 2.1.270. Cursor runs through its SDK and is not pinned.
- Preflight checks every agent a profile uses before each session starts. A different build is a warning, not a refusal.
- After upgrading a CLI, run the recovery drills below with a real login.
- On a shared server, mind what each agent can read: see Security notes.
The CLIs and their pinned versions¶
Each adapter's command line is verified against one CLI build:
| CLI | Pinned | Pin variable | Login |
|---|---|---|---|
| Claude Code | 2.1.270 | PARLEML_AGENTS_CLAUDE_PINNED_VERSION |
claude, then /login (subscription), or ANTHROPIC_API_KEY |
| Codex | 0.162.1 | PARLEML_AGENTS_CODEX_PINNED_VERSION |
codex login (ChatGPT plan), or OPENAI_API_KEY |
| Gemini CLI | 0.62.0 | PARLEML_AGENTS_GEMINI_PINNED_VERSION |
gemini → Sign in with Google, or GEMINI_API_KEY |
| Cursor | SDK (not pinned) | — | CURSOR_API_KEY |
See Credentials & logins for every variable each CLI accepts.
Preflight (before every session start; Settings → Profiles → a profile's
Run preflight) checks each CLI the profile uses: installed, signed in, and
the pinned build. A different build is reported as a warning, not refused:
the flags may have moved. Settings → Agents shows installed against
pinned for each CLI. On a server, uv run python
scripts/check_agent_clis.py prints the same and exits 1 on a mismatch
(--json for scripts; a missing CLI is reported, not failed).
Upgrading a CLI. Install the new build beside the old one, point the
PARLEML_AGENTS_<CLI>_BINARY variable at it on a staging server, run
preflight and the recovery drills below with a real login, then set the
…_PINNED_VERSION variable (or raise the default in
parleml_agents/config.py). When the vendor changes the wording of a limit
or login message, record it for the failure classifier
(parleml_agents/parleml_agents/failures.py, fixtures in
parleml_agents/tests/fixtures/hosts/<cli>/).
The credentialed checks in parleml_agents/tests/test_live_hosts.py run a
real CLI: pytest -m live_claude (or live_codex, live_gemini) from
parleml_agents/.
Recovery drills (after upgrading a CLI)¶
- Stop and resume. Start
ml-investigate, stop it mid-turn, resume: the conversation continues and nothing is repeated. - Kill the process. Kill the CLI process: the session shows a lost process; Resume continues it.
- Restart the backend while a decision is open: the question is still there after the restart, and answering then resuming continues the agent.
- Provider limit. Replay the recorded limit message (or wait for a real one): the banner says "Paused · provider limit" with the reset time; turn on Resume automatically and check it resumes after the reset.
- Login expired. Log the CLI out: the banner names the login command.
- Queue. Queue a message during a job wait: the agent reads it with the wait's result, before the job finishes.
Running without a CLI¶
Details: scripted sessions for tests
PARLEML_AGENTS_HOST_ADAPTER=fake with PARLEML_AGENTS_FAKE_SCENARIO=decide
(or slow) runs scripted sessions that stream, ask a decision, start a step,
write a report and finish, through the real session tools.
scripts/agents_e2e_backend.sh starts a backend this way on a throwaway data
root for the browser tests in apps/web/e2e-agents.
When the runtime is not running¶
Details: a server without the runtime
The runtime starts inside the backend (app.main.create_app mounts it). A
server built without it answers 503 "The agent runtime is not running on
this server." on the ParleML routes that need it
(/api/workspaces/{id}/agent-profile, …/documents/publish,
/api/provenance/{actor}) rather than failing. A second backend process on
the same data root fails to start because the first holds
runs/.runtime.lock.
Security notes¶
- People drive sessions; tokens do not. The session routes accept a
signed-in person only; API tokens are refused. Settings (all but Access) is for
administrators (
PARLEML_AGENTS_ADMIN_ENABLED=falsecloses the agent runtime's admin routes). - Agent administration runs programs on the server. A
stdiotool server is a command the server spawns, so an agent administrator has shell-level reach: give the ParleML administrator role accordingly. With sign-in off (PARLEML_AUTH_REQUIRED=false), the anonymous caller is an agent administrator only for a request from the server's own machine (loopback address,HostandOrigin); a request from another host, a container's published port or another site's page gets403. - Per-attempt tokens. Each step attempt gets its own ParleML token for
the person who started the session, scoped by the skill's
parleml-scope(analyst,compute, orbuilderbound to the workspace), expiring with the attempt's wall clock and revoked when it ends. An agent can never do more than that person. What a token creates names its session and step (provenance), even after the token is revoked. - Tokens go only to ParleML. A ParleML token is minted only for a
connection whose URL is this backend's own
/mcp; a connection pointed elsewhere gets none and fails preflight. -
Confinement. Each session has its own work directory and only the granted MCP servers. What its file tools can reach depends on the CLI:
CLI Reads Writes Claude Code Its work directory, the operator uploads, the profile's reference paths and the skill packs — each granted as a path-scoped rule ( Read(//<dir>/**)); every other path, another session's work directory and the run records included, is refused.Its work directory only ( Edit(//<work dir>/**)); every read-only directory also carries a scoped edit deny.Gemini CLI Its work directory and --include-directories: the reference paths and the skill's folder (a per-attempt copy when it may write).Wherever it reads, so it refuses reference paths when it may write. Codex Anything the server's account can read: its sandbox ( -s workspace-write) narrows writes, not reads, and it reads through its shell.Its work directory. Cursor Not narrowed by the runtime (SDK local agent, sandbox off). Not narrowed. Claude Code and Gemini CLI get file tools but no shell or web tools (
PARLEML_AGENTS_BUILTIN_TOOLS), and the briefing tells them so; Codex keeps its shell with web search and native subagents off. Where sessions of different people share one server, run them on Claude Code or Gemini CLI, or give each person's sessions their own server account: Codex and Cursor sessions can read every session's files the account can. An installation that grants Claude Code a shell (Bash) grants it the same reach. The Files tab, the reader and Publish refuse paths outside the work directory, links, host settings folders (.claude,.cursor,.git) and environment files (.env,.envrc,.env.*). - No secrets in packs or runs. Connection secrets arevault://references resolved at use; plugin manifests read the MCP URL and token from the environment; imported packs are stored inert until adopted, after a risk preview. Pack hooks run with the backend user's rights (Host-native rules & hooks). - Messages are data. A queued message is delivered as the person's words, attributed to them, never as a system instruction.
Next¶
- Credentials & logins: how each agent signs in.
- Security model: the business MCP's trust boundary.