TypeClawTypeClaw
Reference

typeclaw.json

Top-level config schema and reload behavior

JSON Schema–validated. typeclaw init scaffolds a $schema pointer at ./node_modules/typeclaw/typeclaw.schema.json so editors get autocomplete.

Top-level fields

FieldTypeReloadConcept
modelsRecord<string, ref | ref[]>livemodel profile → ref or fallback chain
portnumberrestart-requiredpreferred host port; CLI falls back to ephemeral on conflict
mountsMount[]restart-requiredhost directories exposed inside the container
pluginsstring[]restart-requiredplugin module specifiers
aliasstring[]liveadditional names the agent answers to in channels
channelsRecord<adapter, AdapterConfig>liveper-adapter config
portForward{ allow, deny? }restart-requiredauto port-forward allow/deny lists; default { allow: '*' }
networkNetworkPolicyrestart-requiredegress filtering
sandboxSandboxPolicyrestart-requiredper-tool bwrap sandbox options
tunnelsTunnel[]restart-requiredpublic URLs (see /concepts/architecture)
rolesRecord<name, Role>match live, permissions restart-requiredpermission roles (see /concepts/permissions-model)
docker.fileDockerFileOptionsrebuild via startDockerfile feature toggles + append lines
docker.runArgs.appendstring[]rebuild via startextra docker run flags
git.ignore.appendstring[]rebuild via startextra .gitignore lines

Plugin-owned config blocks live at the top level under their plugin name and are validated by the plugin's own configSchema.

models

{
  "models": {
    "default": "openai/gpt-5.4-nano",
    "fast": "openai/gpt-5.4-mini",
    "deep": ["anthropic/claude-opus-4-8", "fireworks/accounts/fireworks/routers/kimi-k2p6-turbo"],
    "vision": "openai/gpt-5.4"
  }
}

default is required. Other profile names are conventional but not enforced. Each value is either a single <provider>/<model> ref or a non-empty array forming a fallback chain: on failure, the runtime disposes the failed session and replays the prompt against the next ref.

Provider-family defaults override the SDK's reasoning level at session creation: OpenAI-family refs (openai/*, openai-codex/*) pin thinkingLevel: 'low' because GPT-5.x at the SDK default of medium pads reasoning tokens on routine tool-driven turns with no observable quality delta. Anthropic, GLM, and Kimi refs keep the SDK default.

network

{
  "network": {
    "blockInternal": true,
    "autoAllowResolvers": true,
    "allow": []
  }
}
FieldDefaultEffect
blockInternaltrueDROP traffic to RFC1918, link-local (incl. cloud IMDS at 169.254.169.254), CGNAT, multicast/reserved, and IPv6 ULA/link-local/multicast. Loopback always allowed
autoAllowResolverstrueNarrowly carve out port 53 to nameservers in /etc/resolv.conf so VPC-internal DNS keeps working
allow[]Explicit IPv4 CIDRs that punch through wholesale

sandbox

{
  "sandbox": {
    "realProc": false,
    "writablePaths": [".metabase-cli", "workspace/cache"],
    "symlinks": [{ "from": "~/.metabase-cli", "to": "workspace/.metabase-cli" }]
  }
}
FieldDefaultEffect
realProcfalseOpt into the stricter real-proc /proc strategy: mount a fresh, PID-namespace-scoped /proc in the per-tool sandbox for full PID isolation. Needs CAP_SYS_ADMIN, so setting true grants the container that cap. Not required for external package CLIs (bunx, bun add <pkg>, bun run <pkg-bin>) — the default proc-bind strategy already gives them a working /proc with no cap by --ro-binding the container's real procfs under a child user namespace that blocks /proc/<agent>/environ leaks. On runtimes where the real-proc mount is a no-op (OrbStack, rootless Docker, gVisor, Docker Desktop ECI, AppArmor hosts) the sandbox auto-falls-back to proc-bind regardless. See /internals/sandbox
writablePaths[]Extra agent-root-relative directories made writable inside the per-tool bwrap sandbox, on top of the built-in zones (workspace/, public/, mounts/, .git). Use it when a low-trust role runs a CLI that insists on writing a fixed config dir under the agent folder. Entries must be relative (absolute paths rejected), contain no .. or null bytes, exist as a real directory (not a file or symlink), resolve inside the agent folder, and not land on a security-sensitive root (.git, .env, secrets.json, sessions, memory, .typeclaw, node_modules). Invalid or non-existent entries are silently skipped, never fatal. Only affects sandboxed (low-trust) roles; trusted/owner already run unsandboxed
symlinks[]Array of { from, to } that creates a symlink and makes its target writable in one entry. from is the symlink location — an absolute container path (e.g. /root/.foo) or a ~/-prefixed path — and to is an agent-root-relative directory automatically added to writablePaths. The symlink is created at the real container $HOME for unsandboxed (trusted/owner) bash via the entrypoint, and inside the jail at the sandbox $HOME (/tmp) for low-trust bash. The entrypoint refuses to overwrite an existing non-symlink. from may not be /, point under /agent, or target the kernel/virtual roots /proc, /sys, /dev, /run. See /internals/sandbox

mounts

{
  "mounts": [
    {
      "name": "downloads",
      "path": "~/Downloads",
      "readOnly": true,
      "description": "files to inspect"
    }
  ]
}

Each mount maps a host directory to /agent/mounts/<name> inside the container. path accepts absolute paths, relative paths resolved from the agent folder, and ~/~/.... readOnly defaults to false; use true for reference data the agent should inspect but not edit. Mount changes are restart-required because Docker bind mounts are fixed when the container starts.

The CLI can manage this block:

typeclaw mount add downloads ~/Downloads --read-only
typeclaw mount list
typeclaw mount remove downloads

docker.file

ToggleDefaultEffect
ghtrueinstall GitHub CLI
pythontrueinstall Python 3 + uv
tmuxtrueinstall tmux
ffmpegfalseinstall ffmpeg
cjkFonts'auto'install fonts-noto-cjk so Chromium renders CJK glyphs; 'auto' installs only when the host locale is CJK (ja/ko/zh)
cloudflaredfalseinstall cloudflared for cloudflare-quick tunnels (tunnel add / channel add github flip this on automatically)
xvfbtrueinstall Xvfb for headed Chrome
claudeCodefalseinstall Anthropic's Claude Code CLI
codexClifalseinstall OpenAI's Codex CLI (@openai/codex via npm)
append[]extra Dockerfile lines appended verbatim

Boolean toggles can also take a version string ("gh": "2.40.0") to pin via apt-get install pkg=<version>. claudeCode and codexCli are boolean-only. cjkFonts accepts true/false/'auto': 'auto' (the default) resolves at typeclaw start from the host locale, while an explicit boolean forces the decision.

Hot reload

typeclaw reload

Re-reads typeclaw.json and applies hot-reloadable fields. Boot-only fields (port, mounts, plugins, portForward, network, tunnels) are captured once at container start; reload reports which changes require a restart.

Auto-migration

One migration step still runs on load: if typeclaw.json contains a channels.github.eventAllowlist that was seeded by typeclaw init, it is dropped and the file is rewritten with a descriptive commit subject. All other legacy shapes (dockerfile, gitignore, model, channels.<adapter>.allow[]) are no longer migrated — use the current field names directly.

On this page