carlos

home · docs · frames + modes

concepts · frames

Frames are the envelope.

Sessions run inside a frame. Personal plus N user-defined (work, research, side projects, anything). Each frame carries its own provider, vault subtree, MCP gating, glyph, accent, and orchestrator mode.

What's in a frame

A frame is a named bundle of context that scopes every session opened against it. The full set of per-frame properties:

On-disk layout

Every frame gets its own subtree under ~/.carlos/frames/<name>/. Research notes, shell logs, worktrees, and digests all live frame-local. The F-17 migration moves legacy paths idempotently on first boot of a newer build.

~/.carlos/
frames/
  personal/
    research/
      deep-dive-1717948800.md
      routing-sketch-1717952400.md
    usershell/
      8f3a-2026-06-10T09:14:22Z.log
    worktrees/
      a1b2c3/
    digest/
  work/
    research/
      incident-2026-05-1717862400.md
    usershell/
    worktrees/
    digest/
# slug format: <slug>-<unix-ts>.md
# usershell logs are keyed by job id
# F-17 migrated legacy ~/.carlos/research, etc., into frame-local subtrees

Cross-frame rules

Reading across frames is friction-free. Writing across frames is not. Every cross-frame write is intercepted ahead of the layered permission chain and surfaces a distinct audit reason so the trail stays legible after the fact.

action behavior audit reason
read notes_get / notes_search against another frame's subtree auto-approve. ReasonBuiltinAllow
write (approved) The F-12 detector intercepts write / edit ahead of the chain and prompts the user. ReasonCrossFrameAllow
write (declined) Same detector path, user said no. The chain never runs. ReasonCrossFrameDeny

The notes_write tool is hard-scoped to the active frame's vault_subtree. Cross-vault or cross-subtree writes never go through notes_write; they route through the generic write tool with full prompting.

Modes

Three orchestrator modes per frame. The mode shapes the system prompt and gates the supervisor's spawn cap.

mode spawn cap shape
solo 0 Single-agent only. No delegation.
tight 1 At most one delegated sub-agent at a time.
orchestrator 5 Up to five parallel children.

NewPersonal defaults to orchestrator (was solo through v0.7.5). The solo default refused every Spawn, which left the chat-side /agents surface empty and the agent delegation tool unreachable from a fresh install; flipping to orchestrator matches the pre-modes behavior and lets sub-agents work out of the box. /mode solo brings the strict default back any time.

Mode shows up in two places: the supervisor's SpawnCapFor enforces 0 / 1 / 5 in-flight children, and the system prompt's Frame block tells the model how to behave under that cap (do the work yourself / one focused task at a time / delegate by default for anything beyond a single-line edit). The two layers are coupled but distinct: solo refuses every spawn even if the model asked; orchestrator never pauses for per-turn confirmation.

Spawn enforcement returns mode-specific error variants: ErrSpawnRefusedSolo when a child is requested under solo, and ErrSpawnBusyTight when a tight frame already has one in flight.

delegation as design choice

DeepMind arXiv:2512.08296 finds that multi-agent coordination nets negative once single-agent baselines exceed roughly 45% on a task class. Sequential and decision-dense work (coding, writing) degrades 39 to 70% under MAS. carlos surfaces the trade-off through mode selection rather than a per-turn overlay: pick solo for strict single-agent semantics, tight for sequential delegation, orchestrator when the parallel-fan-out shape pays.

Switching frames

Switching is first-class. The takeover switcher, slash commands, and the mode flip all rebuild the active session in place.

Live mid-session swap rebuilds dispatch, sysprompt, and chatglue.Loop atomically. The transcript stays. In-process FrameUI refresh updates glyph, accent, mode, and capabilities immediately, without dropping a frame.

Sub-agent split

When sub-agents are live and chat width is at least 120 columns, the transcript splits horizontally with a right-side children panel: state, last event, elapsed, tokens, spend. Below 120, a dim fallback line appears above the footer instead. A 250 ms tick keeps the panel current while it is up.

Why a frame, not a project

A frame is not a project. It is the answer to "what should carlos consider in scope right now?" Two frames can share a working directory but write to different vault subtrees, prompt the user differently on cross-frame writes, and even use different providers. The provider_override field lets the work frame put OpenAI on a corporate billing key while personal stays on Anthropic, without touching the shared pantry.

Quick-glance properties

Provider + billing

Per-frame provider_override shadows the shared pantry with its own API key and base URL. Work pays from one budget; personal pays from another.

Vault subtree

One vault_subtree per frame. notes_write is hard-scoped to it. notes_get across subtrees is free.

MCP gating

The top-level mcp_servers: list is global; each entry's frames: field restricts that server to a subset.

cwd_hints

Path hints picked up at fresh launch, so opening carlos from ~/code/work-repo auto-selects the work frame.

Orchestrator mode

solo / tight / orchestrator. Sets the supervisor's spawn cap and reshapes the system prompt.

system_prompt_append

Extra system-prompt lines per frame. Pin house style, role rules, or escalation hints without forking the base prompt.

Related

keep reading

Permissions model covers the three-layer approval chain that the cross-frame detector sits in front of. Sub-agent supervision details the spawn caps each mode enforces. The config reference documents every per-frame field; slash commands covers /frame, /mode, and /whoami.