Agent Workspace
Cairn ships a built-in stateful coding agent and a terminal workspace for external CLI agents. Both are accessible from the Agent view (⌘5) and integrate directly with your board tasks and notes.
Two agent modes
The Agent view supports two ways of working:
| Mode | How it works | Best for |
|---|---|---|
| Cairn Agent | Cairn's own built-in agent engine — no binary required. The agent calls tools, streams output to a chat UI, and updates your board and notes as it works. | Coding tasks scoped to your project, where you want the agent to stay in sync with your Cairn board |
| External binary | Spawn Claude Code, OpenCode, Aider, or any CLI tool in a live xterm.js terminal alongside the file tree, editor, and diff viewer. | Agents with their own TUI, or workflows that require an interactive shell |
Cairn Agent
The Cairn Agent is a stateful multi-turn coding agent built directly into the app. It uses the same AI endpoint you configure in Settings → AI — no extra setup. The agent runs a tool-call loop: it can read and write files, run shell commands, search your codebase, and read and update your Cairn board and notes. All tool activity streams to the chat as live chips.
Chat, coding sessions and automations all run on the same built-in agent engine, so approvals, subagents, compaction and session history behave the same everywhere. Every session is saved as an append-only log on disk, so you can close Cairn and resume exactly where you left off, and sessions can be popped out into their own window. History recorded by earlier versions is imported the first time you open it.
Starting a Cairn Agent session
There are two ways to start a session:
- From a task card — open the card detail panel on the Kanban board, click Spawn Agent, and choose Cairn Agent in the modal. The prompt is pre-filled from the card title and description.
- Ad-hoc — open the Agent view and click the + button in the session tab bar. Select Cairn Agent, enter a prompt and the code directory to work in, and confirm.
Before spawning, set a code directory on the project Overview page — this is the root folder the agent reads and writes. If it hasn't been set, the spawn modal will prompt you to enter one.
Tool chips
Every tool call the agent makes appears as a chip inside the message bubble. While the tool is running, the chip shows a spinner and the tool label. When it completes, the chip updates to a check or cross, and write-tool chips show an expandable output block with the result. Read-only tools (file reads, searches, list calls) suppress their output to keep the chat clean. Shell chips render the command's captured output with an exit-status pill, and connector (MCP and HTTP service) calls show the connector's logo, name and what the call did.
Chips for Cairn write tools (ensure_note, create_task, update_tasks, etc.) include a clickable reference link — clicking it navigates to the created or updated item in the Notes or Board view.
Plan mode
Type /plan to put a coding session in plan mode (and /plan off to leave it). In plan mode everything the agent can do is read-only — it investigates the code and your project, writes a plan with a task checklist, and presents it for your review with the exit_plan_mode tool. Writes and commands are blocked until you approve the plan and switch back to normal execution.
Todo list
For work with three or more steps the agent keeps a live todo list with its todo_write tool (pending, in progress, completed, cancelled, one in progress at a time). A collapsible dock above the input shows a compact [2/5 todos · current task] summary that expands to the full checklist. Todos are saved per session and restored when you resume it.
Approvals
A permission picker under the input, next to the model picker, controls how much the agent asks before acting. You can change it before the first message or between turns; it applies from the next turn.
- Ask — the agent asks before editing files, running commands (other than a short list of harmless read-only ones such as
ls,pwd,git status,git diffandgit log), deleting Cairn items, or calling external tools. Reads, and writes to your Cairn notes, tasks and board, run without asking. - Allow all — runs everything without asking, except calls to external connector tools, which still ask.
- Plan — read-only, as described above.
When approval is needed, the tool chip shows an approval card with the exact command or a preview of the change, and the session pauses until you answer. Some things always ask regardless of the picker: touching protected paths such as .env files, private keys, .npmrc, shell config, .git or CI workflow files, and a command that needs to leave the shell sandbox. If the agent issues the same tool call with identical arguments three times in a row, it pauses and asks whether to continue instead of looping. Automations keep their own approval setting — see Automations.
Shell sandbox
Shell commands, background jobs and persistent terminals run inside an OS sandbox: on macOS (seatbelt) and Linux (bubblewrap) the agent can write only inside the working directory and temp/cache folders, while reads and the network stay open so builds, git and package managers keep working. If a command genuinely needs more access, the agent can request to run it unsandboxed. That request gets its own approval card with the agent's reason, offers only Allow once or Deny, and asks every time — it can never be remembered or covered by an Always allow rule. Toggle the sandbox in Settings → AI → Coding Agents → Sandbox shell commands; it applies to new sessions. Windows has no sandbox, so commands run in PowerShell without confinement there.
Subagents & workflows
The Cairn Agent can hand work to focused child agents. subagent starts a fresh agent for a self-contained task (several can run in parallel) and returns its final report; delegate starts one that is shown the conversation so far. Delegated agents stay around as conversations — the parent can follow up with send_message, check on them with list_agents, or stop a stuck one with interrupt_agent. Subagents appear as collapsible inline blocks in the chat with their own streamed tool chips and context usage; the header has a subagent catalog where you can see each child's activity and message it yourself. Children use the parent's approval mode and ask through the parent, so you answer in one place.
For larger jobs the workflow tool runs a short JavaScript program that orchestrates many subagents (one at a time or in parallel), and ralph works on one task in repeated rounds, each in a fresh subagent, until a round reports it finished.
Goals
Give a session a standing objective with /goal (set, show, pause, resume, complete or clear), or let the agent manage it with get_goal, create_goal and update_goal. A goal chip above the input shows the objective, its phase and the round count, and expands to show the blocker if the goal is blocked.
Background jobs & persistent terminals
Long-running commands can run in the background. A jobs dock above the input shows each job's status, elapsed time and outcome with a Stop button; the agent reads output with job_output. For REPLs and long builds the agent can open persistent shells with the terminal_open, terminal_send, terminal_read, terminal_signal, terminal_close and terminal_list tools, so state survives across tool calls. Those shells appear as read-only Agent tabs in the bottom terminal so you can watch them; closing the tab only hides it.
Session reminders
Optionally (Settings → AI → Coding Agents → Session reminders, off by default, needs a restart) the agent can set session-local reminders with schedule_create, schedule_list and schedule_cancel. A small alarm pill in the chat header shows the active count. This is separate from Cairn's background Automations.
Command hooks
If you already use Claude Code or Codex hooks, Cairn can run them too. Put a claude-code.json or codex.json file in ~/.config/cairn/hooks/ and the UserPromptSubmit, PreToolUse, PostToolUse and Stop hooks in it run around the agent loop. A hook can block a prompt or tool call, ask for approval, or add context for the model. Hooks are opt-in — nothing runs unless the file exists.
Context usage ring & compaction
A small ring in the agent chat header shows how much of the model's context window the current session is using. The ring fills as the conversation grows and turns red when usage is high. The context window size is detected automatically from the models.dev catalog, or set manually in Settings → AI → Coding Agents → Context window (presets 8k, 32k, 128k and 200k tokens).
When usage reaches 80% of the space left for the conversation (the context window minus the room reserved for the reply), the agent automatically compacts the context. It summarises the older part of the conversation with a background model call and keeps the most recent messages verbatim, and old bulky tool output is pruned. The full conversation history is always preserved in the session log; only what is sent to the model is trimmed.
Type /compact in the chat input to trigger compaction on demand at any time — useful before starting a large task to free up context space.
Automatic retry
Transient API errors — rate limits, overloaded responses, and server errors — are retried automatically without ending the session. The agent retries up to five times with exponential backoff (starting at half a second and capped at ten seconds) and shows the retry in the status bar. Clicking the stop button cancels any in-progress retry immediately.
Mandatory workflow
The Cairn Agent follows a built-in project workflow on every session:
- Orient — reads the active project context and moves the linked task card to In Progress
- Document as you go — uses
ensure_noteto create or update a session note with findings and decisions (idempotent — no duplicate notes) - Capture out-of-scope tasks — anything discovered but not actioned is added as a board task for later
- Wrap up — writes a session summary note and moves the task card to Review or Done
Available tools
| Tool | What it does |
|---|---|
read, read_image | Read a file (or view an image) from the code directory |
write | Write or overwrite a file |
edit | Replace an exact string in a file (surgical, not full-file rewrite); returns a unified diff of the change |
bash | Run a shell command in the code directory (sandboxed; optionally in the background) |
grep, glob | Search file contents by regex, and list files matching a glob pattern |
lsp | Code navigation — definition, references, implementation and hover — for TypeScript/JavaScript when a language server is on your PATH |
web_fetch | Fetch a public web page as text (content is treated as untrusted; asks each time unless allowed) |
todo_write | Maintain the session todo list |
skill | Load a skill's full instructions |
subagent, delegate, send_message, list_agents, interrupt_agent | Start and manage child agents |
workflow, ralph | Orchestrate many subagents with a script, or iterate on one task in rounds |
get_goal, create_goal, update_goal | Manage the session goal |
search_sessions, read_session | Search and read earlier chats and coding sessions in this workspace |
job_output, job_kill | Read or stop background jobs |
terminal_* | Open and drive persistent shell sessions |
exit_plan_mode | Present a plan for review (plan mode) |
| Cairn workspace tools | Read and write notes, tasks, projects, Idea Flow and the knowledge graph (the same consolidated set as the MCP server), plus the codebase index tools |
| Connected tools | Any external MCP servers and HTTP services attached to the project |
All tools cap their output and append a pagination hint when truncated — the agent can use offset/limit parameters to page through large results.
Skills
Skills are reusable instruction sets — stored as SKILL.md files — that teach the Cairn Agent specialised workflows without bloating the system prompt. Metadata (name and description) is always visible to the agent; the full instructions are only loaded when the agent determines the skill is relevant to the current task.
How the agent uses skills
- At session start, Cairn scans for skill files and injects a compact
<available_skills>list into the system prompt — name and one-line description only. - When the agent recognises a skill matches the task, it calls the
skilltool with the skill name. - The full
SKILL.mdbody is injected into context. Bundled resources (docs, templates, scripts) in the skill directory are listed and accessible via thereadtool.
Where to put skill files
Cairn walks from the code directory up to the git root at session start, checking each ancestor for the following subdirectories (first match per skill name wins):
| Directory | Scope |
|---|---|
.cairn/skills/<name>/SKILL.md | Project — Cairn-native |
.opencode/skills/<name>/SKILL.md | Project — OpenCode compatible |
.cline/skills/<name>/SKILL.md | Project — Cline compatible |
.claude/skills/<name>/SKILL.md | Project — Claude Code compatible |
.agents/skills/<name>/SKILL.md | Project — agent-agnostic |
~/.config/cairn/skills/<name>/SKILL.md | Global — all projects |
~/.opencode/skills/<name>/SKILL.md | Global — OpenCode compatible |
Because Cairn walks up to the git root, skills placed at the repository root are always discovered even when the code directory is set to a subdirectory such as packages/web/.
SKILL.md format
Each skill is a directory containing a SKILL.md file with a YAML frontmatter header followed by the instruction body in plain Markdown:
---
name: git-release # required · kebab-case · matches directory name
description: "Draft release notes and bump the version." # required · shown to agent always
license: MIT # optional
compatibility: cairn # optional (cairn | opencode | cline)
metadata:
audience: maintainers # optional string map
---
## What I do
Walk through `CHANGELOG.md`, propose a semver bump, and draft
the release notes in the project's established style.
## Steps
1. Run `git log --oneline` since the last tag.
2. Group commits by type …
The directory name must match the name field and follow kebab-case (^[a-z0-9]+(-[a-z0-9]+)*$, 1–64 characters). You can co-locate supporting files alongside SKILL.md:
.cairn/skills/git-release/
SKILL.md
docs/release-checklist.md
templates/release-notes.md
scripts/bump-version.sh
The agent is shown the relative paths of files in docs/, templates/, and scripts/ subdirectories and can read them via the read tool.
Previewing discovered skills
Go to Settings → AI → Coding Agents → Skills & System Prompt to see which skills were discovered for your workspace, their file paths, and the full assembled system prompt the agent will receive. The system prompt can be copied to the clipboard from this panel.
Compatibility
Cairn uses the same SKILL.md convention as OpenCode and Cline. Skills authored for either of those agents work in Cairn without modification — same directory layout, same frontmatter schema, same skill tool invocation contract.
All file reads and writes are validated against the registered code directory. The agent cannot read, write, or list files outside that path. Shell commands run with the code directory as the working directory, inside the shell sandbox. Secret-bearing files such as .env and private keys always ask for approval; env templates like .env.example stay readable.
External agent workspace
The external agent workspace is a three-pane layout for running CLI tools in a live terminal:
- File tree — a lazy-expanding browser of your project's code directory
- Editor / Diff — a tabbed code editor and git diff viewer
- Terminal — tabbed xterm.js sessions, one per agent run
Panes resize by dragging the dividers. Sessions survive navigation — switching to Notes or Board and back does not kill a running process.
Setting up a code directory
Each project has a code directory — the root folder the file tree and agent sessions operate in. Set it from the project Overview page: click the terminal-icon row below the project header, type or paste the path, and press Enter. On macOS and Windows you can also click Browse to pick a folder.
The code directory is validated before any agent spawns. All file I/O from the agent workspace is confined to paths within registered code directories — the app will not read or write outside them.
Registering a coding agent
Go to Settings → AI → Coding Agents and click Add agent. Each agent has four fields:
| Field | Description |
|---|---|
| Name | Display name shown in the spawn modal and terminal tab |
| Binary path | Absolute path to the CLI binary (e.g. /usr/local/bin/opencode) |
| Args | Arguments passed to the binary (see Prompt delivery below) |
| Default | Pre-selected in the spawn modal |
Prompt delivery and the {prompt} placeholder
The Args field controls how the spawn-time prompt reaches the agent binary. Use the {prompt} placeholder anywhere in the args string — it is replaced with the prompt text at spawn time.
| Args value | What runs | Use case |
|---|---|---|
| (empty) | binary | Interactive TUI — no prompt injected |
{prompt} | binary 'prompt text' | OpenCode first-positional pre-fill |
--prompt {prompt} | binary --prompt 'prompt text' | OpenCode explicit flag |
--message {prompt} | binary --message 'prompt text' | Claude Code / Aider style |
--flag={prompt} | binary --flag='prompt text' | Inline flag syntax |
Prompts are delivered via exec sh -c '…' with single-quote escaping — safe for any length, newlines, colons, or special characters.
Spawning a session
There are two ways to start a session:
- From a task card — open the card detail panel on the Kanban board and click Spawn Agent. The prompt is pre-filled from the card title and description. Pick an agent, edit the prompt if needed, and confirm.
- Ad-hoc — open the Agent view and click the + button in the terminal tab bar, or click New session in the empty state. Type a prompt or leave it blank for an interactive TUI session.
On spawn, a new terminal tab opens immediately and the agent process starts. The tab shows the agent name and a live status dot — green while running, grey on exit.
Terminal
Each session runs in a full xterm.js terminal. You can type directly into the terminal to interact with the agent or send follow-up instructions. The terminal preserves full scroll history — switch tabs and back without losing output.
Closing a tab sends a kill signal to the process and removes it. The terminal font size tracks your Cairn font scale setting automatically.
File tree
The left pane shows the code directory as a lazily-expanding tree. Folders expand on click; files open in the editor. Only .git and .DS_Store are hidden, so dotfiles like .env and .gitignore can be opened and edited. The tree is scoped to the registered code directory — it cannot navigate above it. Press ⌘⇧F to activate a filename search input at the top of the file tree.
Editor
The centre pane hosts a multi-file CodeMirror 6 editor. Click any file in the tree to open it in a tab. Multiple files can be open simultaneously — switching tabs is instant with no reload, and scroll position and undo history are preserved per file.
- Syntax highlighting for TypeScript, JavaScript, Python, Rust, Go, and 15+ other languages — auto-detected from the file extension
- Dirty-state dot on the tab when a file has unsaved changes
- ⌘S / Ctrl+S to save — writes directly to disk
- Markdown files show a Preview toggle that renders the file in read mode
- Images (PNG, JPG, GIF, WebP, SVG, and more) are displayed inline rather than as text
Git diff viewer
The Diff tab in the editor pane polls git diff HEAD every 5 seconds and shows all uncommitted changes in the code directory, including untracked files.
Three view modes are available:
- Unified — standard unified diff with context, additions, and deletions
- Split — side-by-side old and new columns, paired by hunk
- Changes — unified diff with context lines hidden; only added and deleted lines
File sections are collapsible. A Copy patch button copies the raw diff to the clipboard. A manual Refresh button is available in the toolbar alongside the last-refreshed timestamp.
Keyboard shortcuts
- ⌘5 / Ctrl+5 — open Agent view
- ⌘S / Ctrl+S — save the active file in the editor
- ⌘F / Ctrl+F — find/replace panel in the editor (when editor is focused)
- ⌘⇧F / Ctrl+⇧F — toggle filename search in the file tree
All file reads and writes from the agent workspace are validated against the registered code directories. The app will refuse to read, write, or list files outside those paths. Binary paths are also validated before any process is spawned.