carlos

home · docs · config

reference · config

Everything under ~/.carlos/.

carlos's state lives in a single directory. config.yaml holds prefs, providers, frames, and MCP servers; state.db holds the event log and FTS5 summaries; flat files hold the trust store, schedules, and per-frame artifacts.

Directory layout

~/.carlos/
~/.carlos/
├── config.yaml                # user prefs, provider keys, schedules, vault, frames
├── state.db                   # SQLite event log + memory FTS5
├── trusted-workspaces.json    # Phase T-2 trust store; 0600; atomic writes
├── shell-history              # Phase U history file (shared across frames)
├── daemon.sock                # UDS for daemon IPC (when enabled)
└── frames/
    └── <name>/
        ├── research/<slug>-<unix-ts>.md
        ├── usershell/<job-id>.log
        ├── worktrees/<agent-id>/
        └── digest/

File modes: 0700 directories, 0600 secret-bearing files (config.yaml, state.db, trusted-workspaces.json, artifact blobs), 0644 elsewhere. Atomic writes (temp + fsync + rename) for any file containing user state; see internal/config/config.go:Save.

config.yaml schema

Annotated example. This is the union of supported keys, not a minimal config.

~/.carlos/config.yaml
# carlos config, sample; this is the union of the supported keys
user:
  name: Boss

providers:
  anthropic:
    api_key: sk-ant-...
    default_model: claude-opus-4-7
  openai:
    api_key: sk-...
    default_model: gpt-5
  openrouter:
    api_key: sk-or-...
    default_model: anthropic/claude-sonnet-4-6
  ollama:
    base_url: http://localhost:11434
    default_model: llama3.1:8b
  gemini:
    api_key: AIza...
    default_model: gemini-2.0-flash

skills:
  convention: agents   # "agents" (default, open standard) or "claude"

vault:
  path: ~/.carlos/vault        # or an Obsidian root using <root>/carlos/

daemon:
  enabled: false
  systemd_unit_installed: false

frames:
  personal:
    glyph: "🧢"
    accent: navy
    mode: solo
    vault_subtree: personal
    cwd_hints: ["~/Code", "~/Documents"]
  work:
    glyph: "💼"
    accent: slate
    mode: tight
    provider_override:
      provider: openai
      model: gpt-5
      api_key: sk-corp-...    # shadows the shared pantry
    vault_subtree: work
    system_prompt_append: |
      You are working within the Ludus codebase ...
    capabilities:
      calendar: google

mcp_servers:
  - name: time
    command: "uvx mcp-server-time"
    frames: ["personal"]      # gated; omit to enable in every frame
  - name: github
    command: "npx -y @modelcontextprotocol/server-github"
    env:
      GITHUB_PERSONAL_ACCESS_TOKEN: ghp_...

gateway:
  enabled: false
  channels: []                # populated via `carlos gateway add`

schedules: []                 # populated via `carlos schedule add`

Frames block

Frames are the most expressive block. See the Frames concept for what each field means. Quick summary:

field type what
glyph emoji Header pill icon.
accent palette name One of rust, slate, olive, teal, plum, cream, sand, navy.
mode enum solo / tight / orchestrator.
vault_subtree path Relative to the configured vault root.
provider_override object Per-frame provider, model, key, and base URL.
system_prompt_append text Extra lines added to the system prompt.
cwd_hints array Auto-pick at fresh launch when cwd matches.
capabilities object Backend bindings (e.g. calendar: google).

MCP server block

mcp_servers entry
mcp_servers:
  - name: <short slug>
    command: "<full command line>"
    env:
      KEY: VALUE
    frames: ["<frame>", ...]   # optional gate; omit to enable everywhere

Tools register under <server>__<tool>. /mcp lists what each server contributed at boot.

Onboarding partial re-runs

carlos onboard --only <screen> reaches any of the seven user-facing screens: name, providers, models, skills, daemon, gateway, vault. --only daemon preloads current state; --only gateway auto-skips the set-later gate when an existing config is loaded.

migration safety

Legacy two-shelf layouts migrate idempotently to the frames/<name>/ layout (Phase F-17). Synthetic personal frames materialize from legacy top-level fields on first load.