How it works — three layers
The skill and profile ship with Comis; your only job is the sandbox — one allowlist entry per
CLI, plus installing and authenticating the CLI on the host. The profile is read-side only: it
never widens the jail or the launch — that stays your allowlist entry.
Prerequisites (once, per host)
1
Install the CLI as the service user
Install Claude Code / Codex for the user the daemon runs as (the standard install puts the binary at
~/.local/bin/claude / ~/.local/bin/codex).2
Authenticate it OUTSIDE the jail
Run
claude / codex login as the service user once so credentials are written to ~/.claude /
~/.codex. The driver never logs a CLI in — an unauthenticated CLI escalates to you. Under
filesystem: home those dirs are bound read-write, so the CLI refreshes its own token across drives.3
Accept the first-run gates once
Launch the CLI once by hand and clear its startup gates — Claude Code’s “trust this folder” prompt
and, under
--permission-mode bypassPermissions, the “Bypass Permissions” warning (whose default
highlight is “No, exit”, so a reflexive Enter quits). Once accepted, the state is recorded in
~/.claude.json (bound RW), so later drives open straight to the prompt.Claude Code
filesystem: home— Claude Code is home-installed (~/.local/bin/claude→~/.local/share/...), whichfilesystem: workspacecannot exec; and it writes~/.claude(session state + OAuth refresh), which a read-onlycredentialPathsbind would block.argsPrefixpins--permission-mode bypassPermissions— the agent drives an allowlisted command, so pinning the permission mode in the operator entry means the agent can never select a weaker/different mode. The jail (uid/network/~/.comismask) is the real boundary, not Claude’s own permission prompts.uid: daemon— Claude’s creds under~/.claudeare owned by the daemon user; running as that uid lets it read/refresh them.
terminal_session_create({ allowId: "claude", command: "claude", project: "<short-kebab-name>" })
(the argsPrefix is prepended automatically), then drives the session per the bundled skill. The
project opens a persistent, retrievable folder ~/.comis/workspace/projects/<name> — see
Per-project folders.
The claude-code profile makes the perception clean:
- Render — strips Claude’s dim autocomplete “ghost-text” from the captured screen, so the driving
model never mistakes a suggestion (e.g.
commit this) for queued input. - Perception — Claude’s spinner reads
working; a/model-style picker readsawaiting-input(notstuck). - Dialogs — the “trust this folder” gate is answered with the safe keystroke under
autoAnswer: safe-only; any destructive/approval prompt always escalates.
Claude Code’s Bash tool inside the jail. Claude wraps each Bash-tool command in a second bubblewrap
that remounts
$HOME read-only — which would break its per-command state dir. The driver handles this
automatically (a writable tmpfs carve-out at ~/.claude/session-env); no configuration needed. Details:
Nested sandboxes.OpenAI Codex
--dangerously-bypass-approvals-and-sandbox— Codex would otherwise start its own nested sandbox (landlock/seccomp) and per-command approval prompts. Nested inside this driver’s bwrap jail, Codex’s sandbox fails to initialize (bwrap: loopback … not permitted/seccomp/landlock … not supported). The flag disables Codex’s redundant layer — Comis’s jail is the sandbox. Without it, a driven Codex session dies at startup.filesystem: home— same as Claude: a home-installed binary plus a writable cred/state dir (~/.codex).autoAnswer: safe-only— Codex’s run-command approval overlay is declareddestructivein the codex profile, so it always escalates to you and is never auto-answered.
terminal_session_create({ allowId: "codex", command: "codex", project: "<name>" }).
Use Codex when you specifically want it; otherwise the agent prefers Claude Code for general coding.
The codex profile — perception only (Codex’s Working (Ns) line reads working; the /model
picker reads awaiting-input); the run-command approval is the escalate-always dialog above. Codex has
no /context command (its /status is the usage view), and the skill exits with /quit.
The bundled skills
The agent’s “how to drive it” knowledge ships as two markdown skills, seeded on boot to~/.comis/skills/claude-code/ and ~/.comis/skills/codex/ (re-seeded when the bundled version changes).
The agent auto-discovers them by description (progressive disclosure) and loads the right one for the
task — no per-agent skill config is required. Each teaches:
- Launch + named project folders — always pass
project: "<name>"for retrievable, parallel-safe work. - In-session slash commands — the ones a developer uses:
/compact(free context on a long build),/model(a picker — navigate with arrows/number + Enter),/status,/diff,/clear(⚠️ wipes), etc. - Completion detection + verification — read the screen, require a stable idle prompt, then verify the tests actually passed (never assume success).
- Ghost-text rule — in a driven session the agent is the sole input source, so any text it didn’t type is the CLI’s autocomplete suggestion — ignore it, never act on it.
Related
Autonomous Builds
Hand the agent a design doc → it drives Claude Code through GSD to build it, phase by phase
Terminal Driver
The full driver reference — tools, sandbox scope, durability, platform profiles
Tool Policy
Control which tools each agent can use
