Skip to content

Configuration reference

PersonalClaw’s core configuration lives in one JSON file: ~/.personalclaw/config.json (the directory can be relocated with the PERSONALCLAW_HOME environment variable).

Three ways to change it:

  1. Dashboard UI — most fields have a control in Settings (the “Where to set” column below names the panel).
  2. CLIpersonalclaw config get|set <key> [value] (dot-separated keys, e.g. personalclaw config set session.timeout_secs 7200), or personalclaw config edit to open the file in $EDITOR.
  3. APIGET /api/config/personalclaw (full config), PATCH /api/config/personalclaw {path, value} (single-field, allowlisted), GET /api/config/schema (the machine-readable field registry this document is derived from).

A key like loops.max_cycles_hard_cap means {"loops": {"max_cycles_hard_cap": …}} in the file. Fields marked backend-only have no dashboard control — set them via CLI/file (most need a gateway restart). Fields with a UI panel are applied live.

Not everything is in config.json by design. Stored elsewhere:

  • Model bindings (which model serves chat/background/embedding/…): Settings → Models → ~/.personalclaw/active_models.json.
  • Search bindings: Settings → Search → ~/.personalclaw/active_search_providers.json.
  • Inbox + notification entity settings: ~/.personalclaw/entity_settings/*.json (edited via the Inbox / Notifications settings panels).
  • Per-app config: each app’s data/config.json (edited via the app’s Configure form).
  • Provider credentials: the .env credential store (written by personalclaw setup).

KeyTypeDefaultWhere to setDescription
agent.approval_modeenum: auto, interactive, trust_readsautoSettings → Agent defaultsTool approval mode. trust_reads auto-approves read-only tools and asks for everything else.
agent.providerstringnativebackend-only (restart)Default agent runtime for agents that don’t set their own: native (in-process loop, models governed by Settings → Models), acp, or acp:<cli> to pin a connected CLI runtime. Per-agent provider overrides this. File-only by design — switching it mid-flight would strand live sessions.
agent.sandboxenum: auto, offautoSettings → Agent defaultsSandbox mode for the ACP provider.
agent.yolobooleanfalseSettings → Agent defaultsSkip every tool-approval confirmation. Only use inside a sandbox or for trusted automation.
agent.acp_concurrent_sessionsbooleanfalseSettings → Agent defaultsRun multiple ACP chat sessions on ONE backend process (multiplexing) instead of one process per session — for backends that support session interleaving.
agent.bot_namestring (≤50 chars)""Settings → AccountCustom name the assistant identifies as. Sanitized at the write boundary (markdown/braces stripped). Empty = default.
agent.orchestrator_skillbooleanfalseSettings → Agent defaultsEnable agent delegation — generates and loads the orchestrator skill with the agent roster.
agent.max_subagentsinteger (0–16)3Settings → Agent defaultsMaximum concurrent subagents. 0 = auto-size from host CPU + memory.
agent.spawn_min_memory_gbnumber (0–64)4.0Settings → Agent defaultsMinimum available memory (GB) required to spawn a subagent. 0 disables the check.
agent.subagent_max_turnsinteger (1–200)100Settings → Agent defaultsDefault tool-call budget per subagent.
agent.subagent_timeout_secsinteger (60–7200)1800Settings → Agent defaultsWall-clock timeout per subagent execution.
agent.subagent_cwd_allowed_rootslist of strings["~/workspace", "~/workplace"]Settings → Agent defaultsDirectory roots under which a subagent’s cwd override is permitted (~ expands). Empty list disables cwd overrides.
agent.log_levelenum: DEBUG, INFO, WARNING, ERRORWARNINGSettings → Agent defaultsPersistent backend log level. Applied at startup; the --verbose CLI flag overrides it.
agent.soft_stop_budget_secsnumber (0.5–60)10.0Settings → Agent defaultsSeconds to wait for a cooperative cancel before hard-killing a session.

The chat model is not a config field — bind models per use case in Settings → Models, or per agent on the Agents page.

KeyTypeDefaultWhere to setDescription
session.timeout_secsinteger (0–86400)3600Settings → ChatIdle session timeout in seconds.
session.autocompact_pctnumber (5–90)90.0Settings → ChatContext usage percentage at which auto-compaction triggers.
session.pool_sizeinteger (0–10)0Settings → ChatPre-spawned ACP agent processes kept warm for instant session start. 0 disables. Only useful for ACP agents (subprocess spawn is the cost); the native runtime needs no pool.
session.pool_agentstring""Settings → ChatAgent name for warm-pool processes. Empty uses default_agent.
session.pool_ttl_secsinteger (0–7200)1800Settings → ChatMax age for pooled processes; stale ones are discarded at claim time. 0 disables.

All backend-only operator knobs; per-loop values (set in the loop creation form) override the defaults, and the hard cap binds everything.

KeyTypeDefaultWhere to setDescription
loops.max_cycles_hard_capinteger100backend-onlyAbsolute ceiling on any loop’s cycle budget, regardless of the per-loop limit. Safety brake against runaway cost.
loops.default_idle_secsinteger120backend-onlySeconds between worker cycles when a loop doesn’t specify its own idle timer.
loops.trust_ttl_secsinteger86400backend-onlyHow long a loop worker keeps auto-approved tool trust before the supervisor expires it and requires re-authorization.

Behavior toggles live in Settings → Memory; tuning constants are backend-only.

KeyTypeDefaultWhere to setDescription
memory.semantic_confidence_thresholdnumber0.8backend-onlyMinimum similarity for a semantic-memory hit to be injected.
memory.episodic_dedup_thresholdnumber0.88backend-onlyCosine similarity above which a new episodic record is treated as a duplicate and skipped.
memory.episodic_max_resultsinteger8backend-onlyEpisodic records recalled per query.
memory.episodic_max_countinteger10000backend-onlyEpisodic store size cap; oldest records are pruned past it.
memory.semantic_keyslist of strings[]backend-onlyExtra top-level semantic-record prefixes (namespaces) beyond the built-ins.
memory.l1_manifestbooleantrueSettings → MemoryInject only a small always-on manifest of your most-recalled facts; the agent pulls deeper memory on demand via the memory_recall tool. Off = inject full semantic + episodic memory every turn (legacy).
memory.active_recallbooleantrueSettings → MemoryOn an interactive turn, surface query-relevant memory just before the reply — bounded by a timeout + circuit breaker. Skipped for temporary/incognito/headless turns.
memory.proactive_commitmentsbooleanfalseSettings → MemoryLet the agent infer future check-ins from conversation and deliver ONE natural reminder per window via the heartbeat. Opt-in; high-confidence only; capped per day; one-tap dismiss.
memory.proactive_commitments_max_per_dayinteger3backend-onlyHard maximum active proactive check-ins per agent per day.
memory.active_recall_timeout_msinteger1500backend-onlyHard budget for the pre-reply recall pass; on timeout the turn proceeds without it (circuit breaker trips after repeats).
memory.auto_promote_enabledbooleantruebackend-onlyPeriodically promote repeated episodic memories into durable semantic facts (the self-learning loop) — guarded by a per-run cap + min-interval + single-flight. Off = promotion only via the Memory Studio button.
memory.auto_promote_every_ninteger10backend-onlyRun promotion after every Nth history consolidation.
memory.auto_promote_max_per_runinteger5backend-onlyCap on clusters promoted in a single autonomous run.
memory.history_idle_hoursnumber (≥0.5)3.0Settings → MemoryHours of inactivity before history consolidation.
memory.history_max_daysinteger (≥7)365Settings → MemoryMaximum days of history to retain.
memory.migratedbooleanfalsemanaged automaticallyWhether memory has been migrated to the vector store (set by personalclaw memory migrate / the API).
memory.vault_enabledbooleanfalseSettings → MemoryMirror memory to a browsable markdown vault (Obsidian-compatible: YAML frontmatter + [[wikilinks]] + graph view). Read-only — regenerated from the memory store.
memory.vault_pathstringmemory-vaultSettings → MemoryWhere the markdown vault is written. Relative paths resolve under ~/.personalclaw; absolute paths are used as-is.

Skill management (install/enable/proposals) is the Skills page; these backend-only keys tune the automatic skill machinery.

KeyTypeDefaultWhere to setDescription
skills.max_triggeredinteger (≥1)3backend-onlyMax skills surfaced per message (semantic ∪ keyword match).
skills.auto_create_from_sessionsbooleanfalsebackend-onlyAnalyze completed sessions and synthesize a reusable SKILL.md when a non-trivial procedure is detected (lands under skills/auto/).
skills.auto_refine_on_deviationbooleanfalsebackend-onlyUpdate an auto-created skill when the agent succeeds via a different tool sequence (requires auto_create_from_sessions).
skills.auto_min_tool_callsinteger (≥2)5backend-onlyMinimum tool calls for a session to qualify for skill extraction.
skills.auto_similarity_thresholdnumber (0–1)0.85backend-onlySkip creation when an existing skill’s description overlaps ≥ this fraction.
skills.progressive_disclosure_thresholdinteger8backend-onlyWhen more skills than this match a turn, inject only their index (name + description) and let the agent pull bodies on demand via skill_invoke. 0 = always inline.

The continuous self-improvement review that runs after learning-worthy turns (distinct from session-end consolidation). All backend-only.

KeyTypeDefaultWhere to setDescription
learning.enabledbooleantruebackend-onlyKill switch for the after-turn review (always skipped for incognito/temporary sessions).
learning.min_tool_callsinteger4backend-onlyA turn with at least this many tool calls qualifies even without a correction signal.
learning.correction_heuristicbooleantruebackend-onlyTreat a correcting user message (“no, actually, …”) as a first-class learning signal.
learning.surface_chipbooleantruebackend-onlyShow the quiet “Learned: …” chip in chat when something is captured.
learning.skill_ladderbooleantruebackend-onlyAllow the review to PROPOSE reusable skills — never auto-installed; proposals land in the Skill-proposals inbox for approval.
KeyTypeDefaultWhere to setDescription
workflows.enabledbooleantruebackend-onlyKill switch for SOP surfacing (auto-inject the best-matching workflow above threshold).
workflows.match_thresholdnumber (0–1)0.62backend-onlyCosine-similarity gate for a workflow match. The keyword fallback uses a fixed 0.7 word-overlap.
KeyTypeDefaultWhere to setDescription
security.denied_commandslist of regexes (≤100)[]Settings → SecurityUser-added regexes for shell commands the agent must never run, appended to the always-on built-in denylist. Matched case-insensitively against the full command string.
security.egress.allow_hostslist of strings[]Settings → SecurityHosts (bare domain covers subdomains) permitted even when they resolve to a private/LAN address — for homelab webhooks/services. Applies to all egress surfaces.
security.egress.deny_hostslist of strings[]Settings → SecurityHosts the agent must never reach, even if public. A deny always overrides an allow.
security.egress.allow_privatebooleanfalseSettings → SecurityPermit egress to private/LAN addresses globally. Only enable on a fully trusted network — it removes SSRF protection for the whole LAN.

Alert keywords, name-mention alerts, and retention live in the Inbox settings panel (entity store, not config.json). Config-side:

KeyTypeDefaultWhere to setDescription
inbox.enabledbooleanfalseInbox → Settings (“Poll sources” toggle)Gates the poll-based message sources. The UI toggle calls /api/inbox/restart after flipping so the service re-attaches.
inbox.user_idstring""channel-app setupYour user id on the connected channel — used to skip your own messages.
inbox.watched_channelslist of strings[]channel-app setupChannel ids the poll loop watches.
inbox.poll_interval_secondsinteger (min 30)60backend-onlyPoll cadence.
inbox.style_ruleslist of strings[]backend-onlyVoice/style lines injected into AI reply drafting.
inbox.test_modebooleanfalsebackend-onlyIngest your OWN messages too (demo/testing).
inbox.engagement_ranking_enabledbooleanfalseInbox → SettingsRank the inbox by how much you engage with each channel/sender (favorites, opens, replies boost; dismisses lower) on top of recency.
inbox.engagement_half_life_daysnumber (0–365)0.0Inbox → SettingsHow fast an engagement boost fades (0 = the default ~6.6 days).
KeyTypeDefaultWhere to setDescription
tools.projection_ruleslist of objects[]Settings → Tool outputUser-taught rules mapping a tool-output content marker (regex) to a builtin projection strategy, so a large output keeps its salient slice instead of a generic cut. Consulted before the heuristic sniff; a bad regex is skipped.
tools.projection_rules[].namestring""Settings → Tool outputShort label for the rule.
tools.projection_rules[].match_regexstring""Settings → Tool outputRegex matched against the start of a tool’s output.
tools.projection_rules[].strategyenum: log, diff, json, test, csvlogSettings → Tool outputThe builtin projector to apply.
KeyTypeDefaultWhere to setDescription
dashboard.urlstring""written by personalclaw setupAdvertised dashboard origin — used in links delivered to external channels and by server bind/origin checks.
dashboard.restore_sessionsbooleanfalseSettings → ChatRe-open recently active sessions on startup.
dashboard.restore_window_minutesinteger (0–1440)30Settings → ChatTime window for session restoration. 0 = restore all.
dashboard.user_namestring""Settings → AccountHow the system addresses the operator. Set during first-run onboarding; instance-level so it follows you across browsers/machines.
dashboard.merge_queued_messagesbooleanfalseSettings → ChatConcatenate follow-up messages while the agent is busy instead of queueing them separately.
dashboard.auto_tag_sessionsbooleantrueSettings → ChatWhen a chat’s title is auto-generated, also propose and assign tags in the same pass. Never touches chats you’ve tagged, or incognito/temporary chats.
dashboard.mcp_probe_timeout_secsinteger (5–120)15backend-only (PATCH-editable)Per-server timeout for MCP tool-discovery probes; the gateway’s MCP status sweep budget derives from it (+15s).
dashboard.widget_densityenum: more, lessmoreSettings → ChatHow aggressively the agent uses inline widgets.
dashboard.send_on_enterbooleantrueSettings → ChatEnter sends (Shift+Enter for newline). Off: Enter inserts a newline; Cmd/Ctrl+Enter sends.
dashboard.show_timestampsbooleanfalseSettings → ChatDisplay a timestamp on each chat message.
dashboard.show_thinking_inlinebooleanfalseSettings → ChatShow intermediate reasoning between tool calls instead of collapsing it.
dashboard.simplified_tool_namesbooleanfalseSettings → ChatInline tool pills show a simplified purpose instead of the exact command.
dashboard.confirm_close_sessionbooleanfalseSettings → ChatAsk for confirmation when closing a session from the sidebar.
dashboard.auto_open_browserbooleantruebackend-onlyOpen the dashboard in a browser on gateway start (--no-open overrides per-run).
dashboard.terminalobject{"enabled": true}enabled: backend-only; persist: Terminal pageenabled is the kill switch for the built-in terminal (PTY) feature, read raw with a 30s cache. persist (tmux-backed persistence across gateway restarts) is toggled on the Terminal page.
dashboard.dashboard_layoutobject{}Home dashboard (drag/resize widgets)The home dashboard’s customized widget layout. Empty = the curated default.
KeyTypeDefaultWhere to setDescription
hooksobject{}Triggers page / /api/hooksWebhook trigger config by hook id, plus webhook_token and auto_approve_sources. Managed via the Triggers UI; documented here because the raw shape is config-visible.
observe_max_messagesinteger200backend-onlyChannel-observation ring-buffer size (messages kept per channel for context).
observe_ttl_hoursnumber168.0backend-onlyHow long observed channel messages stay usable as context.
agentsobject{}Agents pageNamed agent definitions (see below).
default_agentstring""Settings → Agent defaultsActive agent name from the agents section (also PUT /api/config/default-agent).
memory_storesobject{}backend-onlyNamed memory store definitions; memory_stores.<name>.description is a human-readable purpose. Stores are referenced by agent profiles.
auto_updatebooleantrueSettings → UpdatesAutomatically apply core updates when a new version is found (update checks always run; this gates the unattended pull + rebuild + restart).
timezonestring"" (system)set by personalclaw setupIANA timezone (e.g. Asia/Tokyo) for schedules and the clock the LLM sees. Per-job trigger timezones override it.
snapshot_dirstring""backend-onlyWhere personalclaw snapshot writes/reads portability snapshots. Empty = ~/.personalclaw/snapshots.

Managed on the Agents page (create/edit forms); stored under agents keyed by agent name. Every field is optional — empty inherits the global default.

KeyTypeDefaultDescription
agents.*.providerstring""Runtime backend: native (in-process loop) or acp:<cli> (external CLI). Empty inherits the global agent.provider.
agents.*.provider_agentstring""ACP provider agent name (modeId for session/set_mode).
agents.*.acp_modestring""ACP permission/operating mode for adapters that expose one (e.g. default, acceptEdits, plan, bypassPermissions). Distinct from Approval Mode (the host gate).
agents.*.default_dirstring""Working directory this agent opens in. Empty inherits the workspace root. Overridable per-session.
agents.*.memory_storestring""Memory provider for this agent. Empty uses the filesystem fallback scoped by working directory.
agents.*.descriptionstring""Human-readable agent description.
agents.*.system_promptstring""System prompt injected at session start.
agents.*.voicestring""WHO the agent is — tone, opinions, persona — kept separate from the operating rules and injected high-priority so personality survives long prompts.
agents.*.modelstring""Default model for this agent. Overridable per-chat.
agents.*.approval_modestring""auto, interactive, or empty (inherit global).
agents.*.skillslist[]Skill names loaded for this agent.
agents.*.toolslist[]Allowed tool name patterns for this agent.
agents.*.triggerslist[]Referenced lifecycle-trigger IDs. A lifecycle trigger fires ONLY for agents that list it.
agents.*.sourcestringpersonalclawAgent origin: personalclaw, marketplace, or builtin.

Not config-file fields, but part of the same operator surface:

VariableEffect
PERSONALCLAW_HOMERelocate the config/state directory (default ~/.personalclaw).
PERSONALCLAW_PORTOverride the dashboard/API port (default 10000). Validated at CLI entry.
PERSONALCLAW_WORKSPACEWorkspace root for LLM working directories.
PERSONALCLAW_BIND_HOSTBind address for the gateway (e.g. 0.0.0.0 for LAN access).
PERSONALCLAW_BYPASS_LOCAL_NETWORKS1 = skip token auth for loopback/RFC1918 clients (dev convenience; public origins still need a token).
PERSONALCLAW_FIRST_PARTY_APPS_DIRPoint a packaged install at a first-party apps directory.
PERSONALCLAW_SKIP_APP_BACKENDSDon’t launch app backend subprocesses (test isolation).
  • GET /api/config/personalclaw — full config as JSON (owner-only).
  • PATCH /api/config/personalclaw {path, value} — single-field writes, allowlisted; non-editable paths return 400.
  • GET /api/config/schema — the full field registry (labels, help, types, defaults, deprecations) auto-derived from the config dataclasses. This document is generated against it.
  • personalclaw config get|set <key> [value] — CLI equivalent; set validates through the same loader.

See also: API overview · CLI reference · Getting started