~/.comis/config.yaml. Who it’s for: anyone tuning agent behavior, wiring channels, hardening the gateway, or composing layered configs across environments.
Comis uses a single config.yaml file (or multiple layered files) to configure every aspect of the system. The configuration contains 41 top-level sections with 54+ nested schemas defining agent behavior, channel adapters, security policies, gateway settings, and more. All schemas use Zod strict validation — unknown keys are rejected at startup.
Config files are specified via the COMIS_CONFIG_PATHS environment variable (colon-separated, like the shell PATH). See the Configuration Guide for a step-by-step setup walkthrough.
Config Loading
Comis loads configuration through a layered resolution process:- Defaults — Every schema field has a sensible default. An empty config file produces a valid configuration.
- YAML files — Files listed in
COMIS_CONFIG_PATHSare merged in order (later files override earlier ones). - Environment overrides — Env vars override YAML values at runtime.
Special Directives
Minimal Example
Complete Annotated Example
A realistic single-tenant deployment running one Telegram-connected research assistant with persistent memory, gateway auth, scheduled heartbeat, and approval gates for sensitive actions. Copy this as a starting point and trim anything you don’t need — defaults take care of the rest.~/.comis/config.yaml, populate ~/.comis/.env with TELEGRAM_BOT_TOKEN and COMIS_GATEWAY_TOKEN, and comis daemon start will boot a working deployment.
Quick Reference
All 42 top-level configuration sections at a glance:Core Settings
tenantId, logLevel, dataDir, agentDir
tenantId, logLevel, dataDir, agentDir
Scalar fields at the root of the configuration.
Agents
agents
agents
Multi-agent configuration map. Each key is an agent ID, and the value is a
PerAgentConfig object that extends AgentConfig with skills, scheduler, session, concurrency, and broadcast settings.Type: Record<string, PerAgentConfig>Default: { default: PerAgentConfig.parse({}) } (one default agent with all defaults)AgentConfig Fields
Multi-account example — two agents, two ChatGPT accounts:
~/.comis/config.yaml
Autonomy (agents.*.autonomy)
How much the agent may do on its own. Setprofile to pick a named posture;
omit the whole block to get standard (the zero-config default). Any explicit
field overrides the profile (progressive disclosure). See the
Autonomy page for the full model and the legible-degrade
behavior.~/.comis/config.yaml -- standard with a tighter budget
~/.comis/config.yaml -- a long-running coordinator lead
Budget (agents.*.budgets)
Circuit Breaker (agents.*.circuitBreaker)
Model Routes (agents.*.modelRoutes)
Extensible key-value map of task type to model identifier. Any string key maps to a model ID string.Operation Model Overrides (agents.*.operationModels)
Override the model and timeout for specific internal operation types. Each entry is anOperationModelEntry with optional model (string "provider:modelId") and timeout (number) fields. The key is timeout (milliseconds) — timeoutMs is rejected by the strict config parser. Omit any type to use the agent’s primary model.Model Failover (agents.*.modelFailover)
SDK Retry (agents.*.sdkRetry)
Prompt Timeout (agents.*.promptTimeout)
See Resilience for how prompt timeouts fit into the full resilience stack.
RAG (agents.*.rag)
Security: A weaker ModelProfile cannot lower this below the operator-set value.FROZEN_TRUST_PATHSandMemoryWriteValidatorremain enforced for allcapabilityClasses regardless of this setting.
Capability-gated default: ForCross-encoder rerank (agents.*.rag.rerank) — opt-in (default off)A cross-encoder re-scores the top fusion candidates with the local reranker model (seesmall/nanoagents,rag.baseFloordefaults to0.15— dropping memories with a base relevance score below 0.15 (a mitigation against low-relevance poison memories). Forfrontier/mid, the default remains0(no filter). Settingrag.baseFloor: 0explicitly is treated the same as “unset” — the capability default applies. To disable the relevance floor on a small/nano agent, setproviders.<id>.capabilityClass: "frontier"to override the capability class, or setrag.baseFloor: 0.01(any value greater than 0 is treated as explicit and wins over the capability default).
memory.rerankerModel). Disabled by default; on timeout or unavailability it falls back to the fusion-ranked order, and the reranker GGUF is never downloaded while disabled.Scoring boosts (agents.*.rag.scoring) — all
number, range 0-1Multiplicative boosts applied to the reranked-or-fused score before the trust filter.Entity associative lane (agents.*.rag.entityLane) — opt-in (default off)A one-hop entity-associative fusion lane. When disabled (the default), RRF fusion is unchanged.
Enabling the opt-in recall featuresReranking and the entity lane both ship off. The reranker model and the recall trace live under the top-level
memory and diagnostics keys (not under agents). A schema-valid block that turns them on:Bootstrap (agents.*.bootstrap)
Workspace (agents.*.workspace)
Concurrency (agents.*.concurrency)
Broadcast Groups (agents.*.broadcastGroups)
Array of broadcast group objects for simultaneous multi-channel message delivery.Elevated Reply (agents.*.elevatedReply)
Tracing (agents.*.tracing)
Gemini Cache (agents.*.geminiCache)
Per-agent configuration for Gemini explicit CachedContent caching. On by default for Gemini agents: Comis creates server-side cached content on Google AI Studio for a guaranteed discount on cached input tokens (system instruction + tools).Gemini cache TTL is hardcoded at 3600 seconds (1 hour) and is not configurable per-agent. Caches are automatically refreshed when more than 50% of the TTL has elapsed. This setting is independent of the Anthropic
cacheRetention field — they control different provider caching mechanisms.Context Guard (agents.*.contextGuard)
Context Engine (agents.*.contextEngine)
Context engine configuration. Controls the system that manages what your agent sees each turn. The default is dag (the lossless LCD engine). The pipeline value (the simpler sequential layered engine) is the first-class opt-in — setversion: "pipeline" to use it. DAG does lossless verbatim assembly (full faithful history + a verbatim fresh tail of the most recent steps + transcript repair), zoomably compresses the oldest history under a token budget, and exposes the in-session ctx_* expansion tools. See Compaction for a user-friendly explanation.Core fieldsShared fields (both modes)
Pipeline mode fields (
version: "pipeline")DAG mode fields (
version: "dag") — freshTailTurns, the leaf/condense summarization fields, and budget-bounded eviction are active (lossless verbatim assembly + threshold-triggered leaf summarization + multi-tier condensation + budget eviction); only the on-demand ctx_* recall keys (maxExpandTokens, maxRecallsPerDay, recallTimeoutMs) are reserved for the planned recall tools and not yet consumed:DAG robustness / spend / deferred-compaction fields (
version: "dag") — all active in the current release:DAG mode fields are validated by Zod even when
version is "pipeline". This means you can pre-configure DAG settings before switching modes — invalid values will be caught at startup regardless of the active mode.The DAG cross-agent isolation adds an
agent_id column to the full-text search index, created once when the database is first initialized — a fresh install needs nothing. See Compaction.Engine scope — served-window honesty and the viable floor (the recorded pipeline-parity verdict).
The turn-time pre-flight fit check, output-headroom enforcement, and the served/cap
context_exhausted provenance (the exhaustion text that names OLLAMA_CONTEXT_LENGTH /
PARAMETER num_ctx / contextEngine.budget.effectiveContextCapSmall — see the
served-window section) apply to the DEFAULT
version: "dag" engine only. The "pipeline" engine’s fit guard is its budget-aware
compaction trigger — it compacts when the estimated context exceeds 85% of the budget
window, computed against the UNCAPPED configured contextWindow (no served reconcile, no
capability-class cap) — plus reactive provider-side context_too_long classification when
the provider rejects an oversized request. (The trigger behavior is test-pinned.)
Pipeline compaction likewise summarizes only the longest oldest-first span that fits the
summarizer’s window (reserving a summarizer-sized output allowance — at most a quarter of
that window — for the summary itself) and keeps the un-summarized remainder in context
(never dropped). When even the oldest message alone exceeds that budget, that single
message is escalated through the compaction fallback ladder (worst case a bounded
count-only note), so every evaluation shrinks the backlog and the 85% trigger re-fires on
later turns until it drains.Recorded decision: the boot viable-floor WARN (the minViable equation) is deliberately
ENGINE-AGNOSTIC — it fires for dag AND pipeline agents alike, because the minViable
arithmetic (bootstrap + tool schemas + output headroom + fresh-tail reserve + safety margin
vs the effective window) holds regardless of engine. What differs per engine is which
TURN-TIME guard backs it up — dag: the pre-flight with knob-named exhaustion; pipeline: the
85% compaction trigger + reactive classification. An operator running a pipeline agent
should read the boot WARN as applying to them, while the per-turn preflight surfaces do not.Capacity Cap (agents.*.contextEngine.budget)
Prevents 256K context-window models from over-provisioning when running a small executive (e.g., qwen3.6:27b). Applied incomputeTokenBudgetForProfile before history budget computation. frontier and mid classes always receive the full contextWindow.Thinking-Effort Governor (agents.*.thinking)
Controls whether the thinking-effort governor may automatically adjust the activethinkingLevel when the remaining context window after eviction is tight.Compaction Routing (agents.*.contextEngine.compaction)
Controls how the context engine handles LLM summarization for low-capability models. Applied in both pipelinellm-compaction and DAG leaf-summarizer layers.
Security: Eviction never drops security-relevant context (sender-trust, safety reinforcement, untrusted-content markers, canary token). The security-context-pinner enforces this fail-closed.
Compact Prompt (agents.*.contextEngine.compactPrompt)
Controls the compact-secure promptMode forsmall/nano models. This mode assembles the system prompt to a bounded target while always retaining the full safety core, sender-trust, and config-secret sections.Security warning: Settingenabled=falsedoes not make the prompt smaller — it restores the full-sizefullpromptMode. The compact prompt is safe for all deployments because it retains the security core. It is not safe to useminimalpromptMode (which drops the safety block) for any security-sensitive deployment.
Relevance Policy (agents.*.contextEngine.relevance)
Controls whether within-conversation history is assembled relevance-first (the margin arbiter allocates the contended history budget across tiers by fused rank, with the fresh-tail and security-pinned floors guaranteed) or recency-first (the existing newest-kept eviction). The decision is capability-gated:small/nano models on a non-caching provider default relevance-first (reordering is free when there is no prompt cache to break); frontier/mid and any prompt-caching model default recency-first (the arbiter does not run for them, so their assembly is untouched). Precedence: explicit per-agent config > capability default > off.Capability-gated default: Thesmall/nanorelevance-first default is gated onsupportsPromptCache=false— a non-caching local model (typical Ollama) reorders history for free, while a caching model stays recency-first below the cache fence (reordering would break the prefix cache).frontier/midare byte-identical by default (the arbiter never runs for them). Thesmall/nanodefault-on flip is measurement-gated (validated by the outcome harness before being relied upon in production); the mechanism ships behind this flag. Precedence: explicit per-agent config > capability default > off.
Security: The arbiter never demotes security-relevant history (canary token, untrusted-content delimiters, safety reinforcement, sender-trust markers) — those items are unconditional floors, excluded from relevance candidacy and always kept, exactly as the recency path’s pre-flight already protects them. A content-freecontext:arbitratedevent (per-tier kept counts; the discretionary pool offered and consumed plus the unconditional floor-token weight; the kept LTM/KG ids; and arelevanceFirstboolean) fires only on the relevance-first path; it carries no message, memory, or query content.
Learning Outcome (agents.*.learningOutcome)
The Verified Learning outcome signal: a durable record of each finished trajectory’s net task-outcome (success / failure / corrected / unknown), so learning can gate on a real task-outcome instead of a text-overlap proxy. It is the signal the reflection engine and the wrongness-based forgetting both gate on. Default-OFF and gated by the master cost switch (memory.enabled — when that is false, learningOutcome is force-disabled regardless of the per-agent flag). The deterministic tool/pipeline signal is the primary source; the cost-gated LLM judge (judge.enabled, default on / opt-out) is the fallback that resolves a CONVERSATIONAL turn — one with no deterministic tool/pipeline signal, which would otherwise fuse to unknown and derive no learning. The judge runs ONE cheap-model pass ONLY when the deterministic resolve is unknown (so resolved turns skip it) and is force-disabled by the master cost switch. The capture is daemon-side and content-free — ids / closed enums / counts only, never a message body. When enabled, observations are written to the outcome_events ledger (see data-directory.mdx) and surfaced on the trajectory for comis explain (the learning obs signal) and via comis memory learning.Inbound reactions as a corroborating source. WhenlearningOutcome.enabledis on, Comis captures emoji reactions added to the agent’s own outbound messages on Discord, Slack, and Telegram and records them through thereactionsource. This is corroboration, not control: a reaction can only weight an outcome the deterministic tool/pipeline signal already resolved — it never overrides it. Three safeguards bound the signal:No reaction-specific config keys exist beyond
- Fail-closed scope. A reaction is observed only when its
message_idmaps to an agent-authored outbound trajectory. A reaction on a user’s message, or on an id the daemon never sent, is silently ignored.- Reactor trust-weighting. The confidence is scaled by the reactor’s channel-sender trust (
elevatedReply.senderTrustMap[reactorId], falling back toelevatedReply.defaultTrustLevel). An unknown / external reactor is capped near zero (~0.05) — a stranger’s 👍 barely moves the needle.- Per-sender rate limit. Reaction-spam from one reactor is throttled so it cannot flood the ledger.
reactionMap: the trust map and rate limiter are reused/daemon-constructed. Capturing reactions on the silent platforms needs operator setup (Slackreactions:readscope; Telegramallowed_updates) — see Reactions and Corrections in messaging.
Learning (agents.*.learning)
The one outcome-gated reflection engine: a single per-agent learning layer that maintains named Mental Model docs (kind: skill | profile | topic) at trust=learned via byte-stable delta-ops, plus the wrongness-based soft eviction. There are no separate per-loop blocks — skill-synthesis, profile, and topic learning all run through this one layer. One flag — enabled — gates the WHOLE layer, default-ON (opt-out) and gated by the master cost switch (memory.enabled — when that is false, the whole learning layer is force-disabled regardless of the per-agent flag). It gates on the learningOutcome signal (a real task outcome), not a text-overlap proxy. Recall ranking itself is always the fixed rag.scoring fusion (deterministic RRF + the cross-encoder reranker) — the learning layer learns docs and forgets wrong memories, but tunes no recall weight.When the reflection cron admits a doc that promotes to active and is read-only, it is surfaced to the agent: it is listed in <available_skills> (appended after platform skills so the prompt-cache prefix stays stable — see prompt cache) and materialized to a per-agent .learned-skills/<name>/SKILL.md listed by its absolute path (the same shape platform skills use, so the read tool opens it directly and skill-use attribution matches). Promotion is gated by reflect.promoteAtProofCount from attributed successful reuse; corroborated, sustained failing reuse demotes (active → stale → archived) and drops it from the surface. A learned doc is advisory (no executable column) and can never exceed learned trust (a DB CHECK makes system structurally impossible — see data-directory.mdx). Procedure docs distilled from verifiably-successful orchestrate runs (a kind: skill doc that additionally records the run’s deterministic tool footprint) surface through the same listing, but that subset is capped per agent by reflect.maxProcedureDocsSurfaced (default 10) so a burst cannot bloat every prompt — user-intent skill docs and topic docs keep a separate, uncapped path. The agent re-authors the script from the advisory guidance under its own permissioned tools; the surface adds no execution path.Reflection is fail-closed and corroboration-bounded. In the defaultsingle_ownermode reflection corroborates a topic on an explicitly-trusted owner’s repetition (≥minObservationssuccesses of the same task) and writes a low initial proof count regardless — so a single trusted DM (where distinct sessions is unreachable) can learn, while a stranger still cannot: repetition is counted only among senders the operator explicitly named, and a box with ≥2 explicitly-trusted senders auto-falls-back to the distinct-sessions gate. Indistinct_sessionsmode a topic instead needs ≥2 distinct(session, sender)observations (N near-identical successes from one sender count once). External-trust sources are excluded by the engine’s two-axis anti-poison SELECT in every mode. On asmall/nanoagent below the synthesis capability gate the reflection cron abstains (Defer ≠ Retry — a benign skip, never a failure or a retry). The whole loop is observable (counts/ids only) viacomis explain(thelearningsignal + thelearned_skill_failingverdict, plus thesingleOwnerCorroboratedfunnel count) and thecomis memory skillsadmission funnel.
Gate composition.learning.enabledis the single switch for the whole layer: the outcome-reward write (recordUsageon success /recordFailureon failure-or-corrected — thememory_usefulness.failure_countsource), the reflection cron, and the wrongness-based soft eviction (forget.*). The soft eviction composes with — does not replace — thememoryLifecyclecron (the schedule that runs the sweep) and therag.forgetrecall-score decay. Eviction is soft and reversible — a memory un-evicts on renewed usefulness, is never hard-deleted, and stays resolvable viaasOf/inspect — and emits counts-onlylearning:memory_demoted/learning:memory_evictedsignals forcomis explain/comis fleet. See thememory_usefulness.failure_count/memories.evicted_atcolumns in data-directory.mdx.
Model tieroutcomeJudge. The optional outcome judge runs on thefastmodel operation tier (outcomeJudge), like the other lightweight classification operations — a cheap model resolved by name and injected daemon-side. It is dormant whilelearningOutcome.judge.enabledisfalse. (The reflection cron itself runs on themidskillSynthesisoperation tier — an offline batch op, capability-routed like the other tiers.)
Source Gate (agents.*.sourceGate)
Goal Anchor (agents.*.goalAnchor)
Injects the current execution objective and uncompleted step checklist at the context tail every turn. Helps weak models stay on task across multi-turn executions. Default-ON for scaffolded (small/nano) tiers; off by default for frontier/mid, but injected when enabled: true is set explicitly. Precedence: explicit per-agent config > capability default > off.Capability-gated default: ForcapabilityClassin{small, nano}(e.g. any Ollama qwen3.6 deployment),goalAnchoris default-ON — noenabled: truerequired. Setagents.<id>.goalAnchor.enabled: falseexplicitly to disable it on a small/nano agent. Forfrontier/midagents, behavior is unchanged (default off). Precedence: explicit per-agent config > capability default > off.
Verification Critic (agents.*.verification)
A pre-delivery critic that checks the terminal response against the GoalAnchor checklist before delivery. Unmet requirements redirect the executor; exhausted retries deliver an honest unmet-list. Meaningful only forscaffoldLevel=max (small/nano) agents.Security: The critic treats the output-under-review as untrusted (wrapExternalContent), inherits the safety core, embeds the canary, fails closed (uncertain → not-verified, never auto-approve), and re-validates any implied tool calls through the same exec gates. Useagents.<id>.operationModels.verificationto run the critic on a cheaper or faster model.
Capability-gated default + cost-gate: ForcapabilityClassin{small, nano},verificationis default-ON — but only whenagents.<id>.operationModels.verificationresolves to a distinct cheaper model (i.e.operationModels.verification.modelis explicitly configured to a different, faster model). If no distinct critic model is configured, the default stays OFF — the critic never silently doubles local-CPU inference latency. Setagents.<id>.verification.enabled: falseexplicitly to force-off the critic on a small/nano agent even when a cheap critic is configured. Setagents.<id>.verification.enabled: trueto force-on the critic regardless of class (including frontier/mid, if a critic model is configured). Precedence: explicit per-agent config > capability default > off.
Honesty Guardrail (agents.*.honesty)
Skills (agents.*.skills)
Built-in Tools (agents.*.skills.builtinTools)
Tool Policy (agents.*.skills.toolPolicy)
Prompt Skills (agents.*.skills.promptSkills)
Runtime Eligibility (agents.*.skills.runtimeEligibility)
Content Scanning (agents.*.skills.contentScanning)
Exec Sandbox (agents.*.skills.execSandbox)
Secrets (agents.*.secrets)
Session (agents.*.session)
Optional session configuration containing reset policy, DM scope, pruning, and compaction.Reset Policy (agents.*.session.resetPolicy)DM Scope (agents.*.session.dmScope)
Pruning (agents.*.session.pruning)
Compaction (agents.*.session.compaction)
Scheduler (agents.*.scheduler)
Cron (agents.*.scheduler.cron)Setting any field here replaces the globalscheduler.cron block wholesale — unlike heartbeat below, per-agent cron fields do not merge with the global block field-by-field. An agent that overrides one cron field (e.g. maxJobs) therefore does not inherit the global scheduler.cron.wakeGate toggle; re-declare wakeGate in the agent’s block to keep it.Heartbeat (agents.*.scheduler.heartbeat)All fields are optional and inherit from the global
scheduler.heartbeat when omitted.See Agent Identity and Agent Lifecycle for how these settings affect agent behavior.
Channels
channels
channels
Channel adapter configuration. Each key is a channel platform name.Type: Matrix (channels.matrix)Matrix connects to a homeserver over the Client-Server API using either an access token or a password login, with a persisted device identity. End-to-end encryption is on by default. Trust is keyed on the full sender MXID:
ChannelConfig (strict object with per-platform entries)Base Channel Entry (shared by all channels)
Media Processing (channels.*.mediaProcessing)
Ack Reactions (channels.*.ackReaction — global schema)
Platform-Specific Fields
Slack (channels.slack)WhatsApp (channels.whatsapp)
Signal (channels.signal)
iMessage (channels.imessage)
LINE (channels.line)
IRC (channels.irc)
Microsoft Teams (channels.msteams)Teams authenticates with an app registration rather than a single bot token. Inbound activities arrive as authenticated HTTPS POSTs on the gateway, so enabling this channel also requires the gateway to be enabled (
gateway.enabled: true) — it rides the gateway’s existing host/port and TLS surface; no separate port is opened. While enabled is false no inbound route is mounted.allowFrom gates both auto-join on invite and which senders the agent responds to, while allowMode decides how an empty allowlist behaves. allowPrivateHomeserver relaxes the SSRF private-range block for a self-hosted homeserver — cloud-metadata endpoints stay blocked regardless.See the Channels section for platform-specific setup guides.
Memory & Search
memory
memory
SQLite-backed memory system configuration.
Reranker model (memory.reranker*)The cross-encoder model used when
agents.*.rag.rerank.enabled is true. The hf: URI auto-downloads on first enable; nothing is downloaded while reranking is off. This is a distinct model from the bi-encoder embedder (see the embedding accordion) — do not conflate the two.Compaction (memory.compaction)
Retention (memory.retention)
embedding
embedding
Embedding provider configuration for vector search. Supports local GGUF models via node-llama-cpp or remote OpenAI.
Local (embedding.local)
OpenAI (embedding.openai)
Cache (embedding.cache)
Batch (embedding.batch)
See Embeddings for a guide on choosing between local and remote embedding providers.
Gateway & API
gateway
gateway
Hono HTTPS server for JSON-RPC, WebSocket, and REST API access.
Running without
gateway.tls on the default loopback bind (127.0.0.1) is the normal install posture and logs no warning — a loopback listener has no off-host exposure. Binding a non-loopback host (for example 0.0.0.0) without TLS logs a boot warning; set gateway.tls (or allowInsecureHttp: true behind a TLS-terminating proxy) to clear it.TLS (gateway.tls) — optional, enables mTLS when providedTokens (gateway.tokens) — array of bearer token entries
Rate Limit (gateway.rateLimit)
WebSocket Message Rate Limit (gateway.wsMessageRateLimit)
Web Dashboard (gateway.web)
See HTTP Gateway and WebSocket for API usage details.
webhooks
webhooks
Webhook subsystem for receiving external events (GitHub, Gmail, custom services).
Webhook Mapping (webhooks.mappings[])
See Webhooks for webhook configuration patterns and payload formats.
Routing & Sessions
routing
routing
Multi-agent routing dispatch. Bindings are evaluated in order (first match wins).
Routing Binding (routing.bindings[])
See Routing for detailed routing patterns and specificity rules.
queue
queue
Command queue for session serialization and concurrency control.
Default Overflow (queue.defaultOverflow)
Per-Channel Override (queue.perChannel.)
Debounce Buffer (queue.debounce)Ingress-layer message coalescing before queue entry.
Follow-up (queue.followup)
See Queue for queue behavior and session serialization details.
Security
security
security
Security configuration for log redaction, audit logging, permissions, action confirmation, agent-to-agent messaging, and encrypted secrets.
Permission (security.permission)
Action Confirmation (security.actionConfirmation)
Agent-to-Agent (security.agentToAgent)
Delivery (security.agentToAgent.delivery)Bounds the self-healing retry on sub-agent completion delivery. See Resilience: Self-healing delivery retries.
Subagent Context (security.agentToAgent.subagentContext)Controls how sub-agent sessions receive context, condense results, and manage their lifecycle. All fields have sensible defaults — you only need to configure values you want to change. See Subagent Context Lifecycle for a full explanation.
Storage Mode (security.storage)
Three modes are supported:
storage: "encrypted" (default — secure-by-default) — AES-256-GCM-encrypted rows in
~/.comis/secrets.db (SQLite). Requires SECRETS_MASTER_KEY to be set (generated automatically
on first boot). Defends against disk/backup theft at the cost of making SECRETS_MASTER_KEY
the crown jewel.storage: "file" — plaintext opt-in bargain — structured JSON at ~/.comis/secrets.json,
~/.comis/auth-profiles.json, and ~/.comis/mcp-tokens/ with mode 0600 (user-only read) in a
0700 directory. Defends against other local users reading secrets; does not defend against
root, disk/backup theft, or process-memory inspection. No SECRETS_MASTER_KEY required.
Hot-reload: comis auth login writes are picked up without a daemon restart.storage: "env" (security.storage: env) — read-only posture — snapshots .env/process.env into the
SecretManager at boot and scrubs sensitive names from process.env. Runtime writes
(env.set, secrets.set, comis auth login) are rejected with an actionable error. Use
for read-only deployments where credentials are injected via environment variables.Mode mismatch detection: If you switch modes while credentials remain in the inactive
backend, the daemon emits a boot WARN naming the stranded store and the manual migration step.
Cross-mode migration tooling is planned for a future release.
~/.comis/config.yaml
See Security for a comprehensive overview of the security model.
approvals
approvals
Action approval workflow. Rules are evaluated in order (first match wins).Approval Rule (approvals.rules[])
Batch approval caching (
batchApprovalTtlMs) allows sequential identical tool calls to auto-approve within the TTL window, reducing approval fatigue during batch operations. The cache persists across daemon restarts.See Approvals for approval workflow configuration patterns.
Daemon & Scheduler
daemon
daemon
scheduler
scheduler
Proactive automation configuration for cron scheduling, heartbeat monitoring, quiet hours, execution safety, and task extraction.Cron (scheduler.cron)
Heartbeat (scheduler.heartbeat)
Quiet Hours (scheduler.quietHours)
Execution (scheduler.execution)
Tasks (scheduler.tasks)
See Scheduler for scheduling configuration and Monitoring for heartbeat setup.
monitoring
monitoring
System health monitoring with sub-monitors for disk, resources, systemd, security updates, and git repos.Disk (monitoring.disk)
Resources (monitoring.resources)
Systemd (monitoring.systemd)
Security Updates (monitoring.securityUpdates)
Git (monitoring.git)
See Monitoring for monitoring setup and alert configuration.
Integrations
integrations
integrations
External service integrations for search, MCP servers, media processing, and auto-reply rules.Brave Search (integrations.braveSearch)Video Generation (integrations.media.videoGeneration)Controls the Vision (integrations.media.vision)Vision Scope Rule (integrations.media.vision.scopeRules[])
MCP (integrations.mcp)
MCP Server Entry (integrations.mcp.servers[])
Media (integrations.media) — contains nested sub-schemas for all media processing:Transcription (integrations.media.transcription)
Local STT (integrations.media.transcription.local) — keyless
TTS (integrations.media.tts)
TTS Output Formats (integrations.media.tts.outputFormats)
ElevenLabs Settings (integrations.media.tts.elevenlabsSettings) — optional
Image Analysis (integrations.media.imageAnalysis)
Image Generation (integrations.media.imageGeneration)Controls the
image_generate tool. By default (provider: auto) image generation follows the agent’s main provider and reuses its credentials — no image-specific key is needed when the main provider can generate images (e.g. an OpenRouter agent uses its OPENROUTER_API_KEY). When the main provider cannot generate images (e.g. Anthropic), the tool returns an honest “unavailable” with a hint to set provider explicitly — it never silently routes to a different paid provider.In the common
auto case, four follow-main image paths are wired, each reusing the agent main provider’s own credentials:- OpenAI (key-auth) — a key-auth
openaimain (withOPENAI_API_KEY) generates via the OpenAI Images API, defaultgpt-image-1. Pin explicitly withprovider: openai. - Google Gemini (key-auth) — a
google(orgoogle-vertex) main (withGOOGLE_API_KEY) generates via Gemini (generateContent), defaultgemini-2.5-flash-image. Pin explicitly withprovider: google. (The key isGOOGLE_API_KEY— the same key the completion path and vision use, notGEMINI_API_KEY.) - OpenRouter — a main on the OpenRouter proxy, or explicit
provider: openrouter+OPENROUTER_API_KEY. - Codex (ChatGPT-login) — when the main provider is
openai-codex(or you setprovider: openai-codex),image_generatereuses the agent’s ChatGPT/Codex OAuth credentials — there is no image-specific API key to set; the OAuth bearer is resolved per call and refreshes automatically (bootstrapped fromOAUTH_OPENAI_CODEXorcomis auth login --provider openai-codex). If the agent is not logged in, the tool returns an honest “unavailable” with acomis auth login --provider openai-codexhint. The Codex request’s top-level model must be a current codex chat model (the hostedimage_generationtool picks the actual image model server-side): the request uses yourmodeloverride when set, otherwise the agent’s own chat model when the main provider isopenai-codex, otherwise the built-in codex chat default — so pinningprovider: openai-codexon a non-codex main (e.g. an Anthropic agent) works out of the box and never sends the foreign main model to the ChatGPT backend.
image_generate tool params ride these paths: model (override the provider’s default image model — rejected with a hint listing the valid models if it is not valid for the active provider) and reference_image (a workspace file path, URL, or data-URI for edit/img2img — path-traversal- and SSRF-guarded). An image-incapable main (e.g. Anthropic) with no explicit provider stays honest-”unavailable” rather than silently routing to a paid provider.A Codex main provider’s image request identifies itself to the ChatGPT backend as the official Codex client (
originator: codex_cli_rs, a Codex-shaped User-Agent, and a ChatGPT-Account-ID decoded from your token) — a first-party-client compatibility shim using your own OAuth credentials against the same endpoint the official Codex CLI uses (so Cloudflare does not 403 non-residential IPs). It is authorized reuse of your own credentials, not detection evasion.video_generate tool. By default (provider: auto) video generation follows the agent’s main provider and reuses its credentials, mirroring image generation: a google main resolves to Google Veo and an xai main resolves to xAI Grok Imagine, each with the key the agent already uses (GOOGLE_API_KEY / XAI_API_KEY). Where the main provider has no video API (e.g. openai, anthropic), the tool returns an honest “unavailable” with a hint to set provider (e.g. fal + FAL_KEY) — it never silently routes to a different paid provider.All three backends are wired: under
provider: auto a google main renders via Veo and an xai main via Grok Imagine, each reusing the main provider’s credentials; the explicit fal path renders via the FAL queue API and needs FAL_KEY.Vision provider precedence (
image_analyze). Resolution order, highest first:- Explicit
defaultProvider— when set (non-empty), the vision registry serves that provider; this wins over everything. - Follow the agent’s main provider (the default when
defaultProvideris unset) — when the agent’s main model accepts image input (Claude / GPT-4o / Gemini and other vision-capable models),image_analyzeroutes through that main model, reusing the agent’s existing credentials. No new vision config key and no separate vision API key are required for this — it is automatic. - The vision registry chain (
providers, defaultopenai -> anthropic -> google, first with a configured key) — when the main model is not vision-capable, or as the fallback if a main-vision attempt fails at runtime. - Honest “unavailable” — when no tier can serve, with an error kind and a hint naming the knob to set.
describe_video (raw video) is Gemini-only and does not follow the main provider — it routes straight to the registry’s Google provider (no frame extraction this release). The existing providers / defaultProvider / scopeRules keys are unchanged; the follow-main behavior adds no new vision config key.Link Understanding (integrations.media.linkUnderstanding)
Media Infrastructure (integrations.media.infrastructure)
Document Extraction (integrations.media.documentExtraction)
Media Persistence (integrations.media.persistence)
Auto-Reply (integrations.autoReply)
Auto-Reply Rule (integrations.autoReply.rules[])
browser
browser
Browser automation via Chrome DevTools Protocol (CDP).
Viewport (browser.viewport)
See Browser for browser tool usage and configuration.
plugins
plugins
Plugin system configuration.
Plugin Entry (plugins.plugins.)
See Plugins for the plugin system and hook reference.
tooling
The tool-first capability layer. Operator-only — agents cannot self-configure capability routing or detour policy. The entiretooling tree is added to IMMUTABLE_CONFIG_PREFIXES and rejected by config.patch from agent-callable surfaces.
Top-level fields:
capabilityClusters— cluster definitions and builtin tool→cluster assignments. Operator-defined clusters merge key-by-key with the three reserved IDs (external-integrations,prompt-skills,other-tools); operator values win per key.mcp.capabilityHints— operator hints for connected MCP servers (record keyed by server name; each entry is{ cluster, description, replacesPackages }).skills.capabilityHints— operator hints for prompt skills (record keyed by skill name or skill key; each entry is{ cluster, description?, replacesPackages }).capabilityIndex.enabled— boolean toggle for the per-turn## Capabilitiesblock (defaulttrue).installDetours.mode—"observe"/"advise"/"soft-stop"(default"advise"). Controls how the install-detour validator acts when an exec command wouldpip install/npm installa package that overlaps with an already-connected MCP server or skill.
capabilityClusters.builtinAssignments[*], mcp.capabilityHints[*].cluster, or skills.capabilityHints[*].cluster) emit a Pino WARN at daemon startup with errorKind: "config", an operator-actionable hint, and the offending { configPath, unresolvedClusterId } payload — the daemon does NOT crash; unresolved cluster references fall back to external-integrations (for MCP hints) or prompt-skills (for skill hints). Check pm2 logs comis or journalctl -u comis after restart to surface typos.
orchestration
Small-model DAG-authoring gates. These flags help a weaker model author multi-agent execution graphs that a frontier model would write correctly on its own — by repairing a schema-invalid graph to its intended canonical template, synthesizing a graph from a one-line intent, and grammar-constraining the tool schema for local providers. Operator-only — theorchestration tree is not agent-configurable.
orchestration.authoring fields:
Governance is preserved regardless of these flags: a repaired or synthesized graph runs the same validation, denylist, and child⊆parent sandbox checks as a hand-authored graph — the producer/synthesizer return a graph and never execute one directly. See Execution Graphs: Small-model authoring for the behavior and Event Bus for the
graph:repaired and graph:synthesized_from_intent audit events.
Streaming & Messaging
streaming
streaming
Block-based response delivery across all channels.
Per-Channel Override (streaming.perChannel.)
Each per-channel entry also includes nested
deliveryTiming and coalescer overrides with the same schema as the top-level versions.See Delivery for block streaming behavior and platform-specific delivery.
autoReplyEngine
autoReplyEngine
Controls whether the agent pipeline activates for inbound messages. Separate from the pattern-based auto-reply rules in
integrations.autoReply.sendPolicy
sendPolicy
Outbound message gating rules. Rules evaluated in order; first match wins.
Send Policy Rule (sendPolicy.rules[])
envelope
envelope
Message envelope enrichment for inbound messages before they reach the LLM.
messages
messages
Messaging UX configuration for outbound message formatting.
models
models
Model catalog and alias configuration for model discovery and friendly names.
Model Alias (models.aliases[])
providers
providers
LLM provider configuration. API keys are referenced by SecretManager key name, never stored in plaintext.ModelCost (providers.entries..models[].cost)
Provider Entry (providers.entries.)
ProviderCapabilities (providers.entries..capabilities)
Capability-gated defaults: The reliability scaffold (GoalAnchor, relevance floor, cost-gated critic) is default-ON forUserModel (providers.entries..models[])small/nanoagents — no per-agent opt-in required. Two capacity defaults also apply tosmall/nano:bootstrap.maxCharsdrops to3_500chars per file, and the active-tool ceiling is set to 24 tools (overflow tools stay reachable viadiscover_tools). Additionally: a total bootstrap budget (5,000 chars sum-cap for small/nano), capability-gated graph concurrency (small/nano→2, frontier/mid→4), and a bootstrap-budget warn threshold based on the real context denominator.frontier/midbehavior is unaffected by all of these. The security guarantee holds: a weaker model class cannot lower the platform’s security posture; the scaffolding defaults reinforce it.
ModelCompatConfig (providers.entries..models[].comisCompat)
GBNF auto-detection: providers with
type: "ollama" default their models to the gbnf
profile automatically. An explicit toolSchemaProfile value always wins for gbnf (set
"default" to opt a model out while debugging) — unlike xai, whose auto-detected flags are
non-negotiable API requirements and override user config.Explicit opt-in: LM Studio, llama-server (llama.cpp), and vLLM endpoints have no provider
type that auto-enables the profile (only type: "ollama" does) — they opt in per model via
comisCompat.toolSchemaProfile: "gbnf" (zero new config keys; this is the existing comisCompat
surface).Reactive repair: if a provider still rejects a schema at grammar-compile time, Comis
classifies the 400 (tool_schema_unsupported), strips pattern/format from the offending
tools, and retries exactly once per session before failing honestly; comis explain names the
offending tool. A once-per-boot INFO line summarizes which tools were transformed (names and
keyword counts only — never schema bodies).For the served-context-window side of local-provider setup, see
Local model context window.Recommended Secure qwen3.6 Configuration
The followingconfig.yaml snippet shows the recommended settings for a secure, scaffolded qwen3.6 local deployment. All security-relevant keys are shown with their recommended values.
Capability-gated capacity defaults
These defaults fire only forcapabilityClass in {small, nano} (e.g., any Ollama qwen3.6 deployment). Without them, a live measurement of a qwen3.6 deployment showed ~32K input tokens per turn — 98 active tool schemas and a 14.4K-char bootstrap file drove a 495% bootstrap warning. The capacity defaults below address this without changing frontier/mid behavior: a per-file bootstrap cap, an active-tool ceiling, a total bootstrap budget, capability-gated graph concurrency, and a bootstrap-budget warn threshold based on the real prompt denominator.
bootstrap.maxChars capability default
ForcapabilityClass in {small, nano}, bootstrap.maxChars defaults to 3_500 chars per file (down from the schema baseline of 20_000). For frontier/mid, the value is unchanged (20_000 per file).
Key properties:
- Per-file limit. Each workspace file is truncated individually. At
3_500chars, AGENTS.md (the largest file) is preserved head 70% + tail 20%; smaller identity files (SOUL/IDENTITY/USER/ROLE/TOOLS/HEARTBEAT/BOOT) fit entirely within the limit. - Precedence: explicit
agents.<id>.bootstrap.maxChars> capability default (3_500for small/nano) >20_000(frontier/mid baseline). - Sentinel:
20_000is treated as “unset”. Settingbootstrap.maxChars: 20000explicitly has the same effect as omitting the key — the capability default of3_500applies for small/nano. This is because20_000is the schema default, so the runtime cannot distinguish “operator chose 20_000” from “no override”. To force the20_000limit on a small/nano agent, setagents.<id>.capabilityClassOverride: frontierinstead.
Active-tool ceiling
ForcapabilityClass: small, at most 24 tool schemas are active in each prompt request. The cold long-tail (tools not in the core set and not recently used) is deferred.
No capability is removed. All deferred tools remain fully callable via the
discover_tools mechanism. The model can search for and invoke any deferred tool in the same turn. This ceiling is a prompt-size control, not a security control — it does not restrict which tools the agent is authorized to use.capabilityClass: small. Key properties:
- CORE_TOOLS are never deferred. The following tools are always kept active regardless of the ceiling:
read,edit,write,grep,find,ls,apply_patch,exec,process,message,memory_search,memory_store,memory_get,web_search,web_fetch. - Recently-used tools are never deferred. Any tool the agent invoked in recent turns is preserved in the active set.
nanoclass is not affected. Nano already uses aggressive CORE_TOOLS-only deferral; the 24-tool ceiling does not change its behavior.frontier/midclasses are not affected. No ceiling applies — behavior is unchanged.- Savings: 15 CORE_TOOLS + 9 discretionary slots at 24 active tools vs. the previous 40 saves approximately 750–1,250 tokens per turn (~300 chars per tool schema average).
Total bootstrap budget
ForcapabilityClass in {small, nano}, the total bootstrap budget caps the sum of all bootstrap file content at 5,000 chars, applied as a second pass after the per-file 3_500-char cap.
Key properties:
- Sum-cap, not per-file. If all workspace files together would exceed 5,000 chars after per-file truncation, each file is proportionally scaled down to fit the total budget.
- Per-file floor. Each file retains at least 300 chars, regardless of how many files compete for the budget. No file is silenced entirely.
- Proportional truncation. Each file’s allocation is
(file_chars / total_chars) * totalMaxChars, floored at 300. Content is taken from the beginning of the file (direct slice — not head+tail; the per-file pass already applied head+tail truncation). frontier/midunaffected. No total cap is applied; behavior is unchanged.- Config override. Explicit
agents.<id>.bootstrap.maxCharsalways takes precedence over both the per-file and total-budget capability defaults.
Capability-gated graph concurrency
ForcapabilityClass in {small, nano}, the graph coordinator’s maxConcurrency defaults to 2 (down from 4). For frontier/mid, the default remains 4.
Why lower concurrency for small/nano? Local inference on Ollama (or any local GPU-bound runtime) serializes model loads in practice. With 4 concurrent sub-agents, all four issue simultaneous inference requests; the GPU queues them, producing peak saturation that can cause 50–80% of sub-agents to time out on longer prompts. Lowering the default to 2 staggers the load while keeping two in-flight at all times.
To override the default for your deployment:
promptTimeoutMs is a stall budget: the deadline resets on stream activity (text/thinking deltas, throttled ~1/s) and tool completions, so it only needs to cover the longest SILENT gap — in practice the prefill before the first token, which on a loaded local GPU (e.g., qwen3.6 with multiple concurrent agents) can exceed the 180,000 ms default. Once the model streams, activity keeps the turn alive; the makespan ceiling (promptTimeoutMs × stallCeilingMultiplier, default ×10) still bounds the total turn even while streaming. For local deployments, raise the stall budget to cover slow prefill:
models.failoverModel pointing to a lighter local model (e.g., a faster quantized variant) that can handle sub-agent calls when the primary model is loaded. This provides graceful degradation rather than timeout cascades.
Bootstrap-budget warn threshold
TheBootstrap content exceeds budget threshold WARN fires when bootstrap files exceed 40% of the estimated total prompt (system prompt chars + tool schema definition chars).
The denominator is systemPromptChars + toolDefOverheadChars (the same formula used by executor-tool-assembly.ts for the context-budget breakdown) — deliberately not the system prompt alone, which would make the warning fire on virtually every small-model turn with a normal workspace. With a compact-secure system prompt (~2,800 chars) and 24 active tool schemas (~12,000 chars overhead), the denominator is ~14,800 chars. With the total bootstrap budget of 5,000 chars, the ratio is ~34% — below the 40% threshold, so no warning fires under normal conditions.
When does the warn still fire? If an operator adds large custom workspace files that push the total bootstrap above 5,920 chars (40% of ~14,800), the warn fires correctly — signaling that bootstrap content is crowding out the system prompt and tool schemas in a meaningful way.
Summary
All capability defaults follow the same precedence: explicit per-agent config > capability default. The capacity defaults are additive: all behaviors activate together for
small/nano agents with no per-agent config required.
Relationship to the reliability defaults: The GoalAnchor,rag.baseFloor, and verification critic defaults follow the same precedence model — explicit per-agent config > capability default > off. The capacity defaults (bootstrap budget, tool ceiling, graph concurrency) are additive: all default-on behaviors activate together forsmall/nanoagents with no per-agent config required.
General vs. Coding-Tuned Model Guidance
For agent reliability, prefer general-purpose qwen3.6 variants over coding-tuned models:- General models (e.g.,
qwen3.6:35b,qwen3.6:27b) are the right choice for agentic tasks. They handle multi-turn conversations, multi-constraint instructions, and tool use reliably. - Coding-tuned models can exhibit goal fixation — continuing to pursue a sub-task at the expense of the original objective. The Comis scaffold (GoalAnchor, verification critic, compact-secure prompt) is designed to detect and correct this behavior, but general models avoid the problem in the first place. This guidance originated from a live incident in which a coding-tuned model fixated on a game-building sub-task; general-purpose qwen3.6 reproduces this scenario far less.
- The Comis scaffold is designed for general models. It is not a substitute for choosing the right model class.
Local model context window
For Ollama providers, the served context window (num_ctx) may differ from the configured
contextWindow. By default, Comis probes GET /api/ps and POST /api/show at daemon boot
and reconciles:
context_length values are floored to
integers, and implausibly small ones (below 512 tokens — e.g. a typo’d Modelfile
PARAMETER num_ctx) are rejected as bogus, falling back to the configured window via the
probe’s normal fail-open path.
Changing the served window: The probe is read-only; it discovers what Ollama has loaded.
To serve a larger context (up to the model’s native maximum), set it on the Ollama side:
- Environment variable:
OLLAMA_CONTEXT_LENGTH=65536(before starting Ollama) - Modelfile parameter:
PARAMETER num_ctx 65536 - Ollama.app: Settings → Models → Context Length
num_ctx increases GPU memory usage proportionally
(the KV-cache scales linearly with context length). A 35B model at 256K context can OOM
or cause heavy memory thrashing on consumer hardware. Raise num_ctx only as far as
your VRAM allows; start conservatively (e.g., 32768 or 65536) and measure.
To suppress the boot probe for a provider (e.g., Ollama is offline at daemon start):
contextWindow, Comis logs exactly one WARN per provider per boot —
"Ollama served context window below configured" — naming both numbers and the probed model
(the probe checks ONE model per provider: defaultModel, else the first models[] entry —
per-model probing is a known limitation). The hint names the fixes:
OLLAMA_CONTEXT_LENGTH=131072 ollama serve (substituting your configured window), or Modelfile
PARAMETER num_ctx 131072 (see the VRAM caveat above), and the opt-out
(providers.entries.<id>.capabilities.probeServedWindow: false). Healthy boots stay silent:
served at or above configured, equal windows, non-Ollama providers, and providers the probe
skipped all log nothing.
Exhaustion provenance — the served bind names its knobs: When a turn exhausts a
served-bound window, the context_exhausted error text carries the suffix
(model contextWindow 131072 but Ollama serves only 8192 — fix: OLLAMA_CONTEXT_LENGTH=131072 ollama serve, or Modelfile 'PARAMETER num_ctx 131072')
— both Ollama knobs plus the TRUE configured window. In logs and comis explain,
rawContextWindowTokens reports the configured window with windowCapSource: "served"
(never the served value masquerading as the model’s declared window).
When both the served window and a capability-class cap clamp, the message names the full chain:
(model contextWindow 131072, Ollama serves 50000, capped to 32000 by contextEngine.budget.effectiveContextCapSmall — raise it (0 = uncapped) or reduce active tool schemas).
The cap wording is branched by the lever that actually binds: the
contextEngine.budget.effectiveContextCapSmall/Nano form above appears only when the budget-side
cap genuinely clamped (raising that key works); when the window was instead capped upstream by an
operator providers.entries.<id>.capabilities.capabilityClass pin (the executor’s per-class
default — small 32000 / nano 16000 — which never reads the budget keys), the suffix reads
capped to 32000 by providers.entries.<id>.capabilities.capabilityClass — pin a higher class (or remove the pin) or reduce active tool schemas
and windowCapSource reports "capabilityClass" — on that branch raising
contextEngine.budget.effectiveContextCapSmall (or setting it to 0) changes nothing, so the
error and comis explain name the pin instead of that dead knob.
The reconcile line — "Context window reconciled (served or capability cap bound)", with
source / effectiveWindow / configured / served / capabilityCap fields — logs at INFO
once per session (the first reconciled turn; a session reset grants a fresh INFO) and at
DEBUG per turn. A session whose configured window simply wins logs no reconcile line at any
level (nothing was reconciled). The served window is provider-scoped: it clamps only
executions that resolve to the provider it was probed from — a per-execution model override to
another provider (a graph node’s model: anthropic:... on an Ollama-primary agent, a subagent
spawn) keeps that model’s full window and never gets "Ollama serves only N" attribution.
Boot viable floor (minViable): At boot, per agent, Comis computes
minViable = bootstrapTotalTokens + toolSchemaTokens + outputHeadroomFloor + freshTailReserve + safetyMargin
— each term single-sourced from its turn-time preflight home (the scaffold bootstrap budget,
the tool-schema overhead estimate, the output headroom at the post-downshift minimum thinking
level, the per-class preamble reserve, and the token-budget safety margin) — and WARNs when the
effective window cannot fit even that floor:
"Boot viable-floor check: effective window below minViable — agent will degrade on real turns (WARN-only, boot continues)".
The hint spells the full equation with every term’s value, e.g.
minViable = bootstrapTotalTokens(1429) + toolSchemaTokens(9714) + outputHeadroomFloor(1792) + freshTailReserve(2000) + safetyMargin(2048) = 16983 exceeds effectiveWindow 8192 [source: served],
followed by the knob for the binding window source — served: the two Ollama knobs above;
capability: pin a higher class (or remove the pin) via
providers.entries.<id>.capabilities.capabilityClass (the contextEngine.budget.* caps cannot
raise this bind); configured: providers.entries.<id>.models[].contextWindow. When tool schemas
dominate the
floor, the hint adds the active-tool-ceiling lever: pin capabilityClass (the small class
defers to a 24-tool active ceiling via discover_tools) or disable unused MCP servers /
builtin tool groups. WARN-only: Comis never refuses to boot below the floor (the adapt-down
posture) — and because the boot floor and the turn-time preflight share one source module and
one tool corpus (the boot toolSchemaTokens term measures the same converted tool
definitions — lean descriptions plus guidelines — the turn actually ships, not the raw factory
descriptions), the same numbers re-appear in any later turn-time context_exhausted for that
agent.
The boot viable-floor WARN is engine-AGNOSTIC — it fires for "dag" and "pipeline" agents
alike (the minViable arithmetic holds regardless of engine); the per-turn preflight surfaces
are dag-only — see the engine-scope note in the
Context Engine section. Fleet-wide, under-served
providers surface as the config_posture:served_below_configured finding in
comis fleet and the obs.fleet.health RPC (see the
JSON-RPC reference).
UX Features
lifecycleReactions
lifecycleReactions
Processing phase emoji reactions. When enabled, the agent reacts to messages with emoji reflecting current phase (thinking, tool use, generating, done, error).
Timing (lifecycleReactions.timing)
Per-Channel (lifecycleReactions.perChannel.)
responsePrefix
responsePrefix
Response prefix/suffix template injected into agent replies.
deliveryTiming
deliveryTiming
Inter-block delivery pacing to simulate natural typing rhythm.
coalescer
coalescer
Block coalescer that accumulates small streaming blocks before delivery.
senderTrustDisplay
senderTrustDisplay
Controls how sender identity is surfaced to the LLM in the message envelope.
documentation
documentation
Documentation links injected into the system prompt so the agent can reference them.
telegramFileRefGuard
telegramFileRefGuard
Detects hallucinated file paths in responses destined for Telegram (where file:// links are meaningless).
deliveryQueue
deliveryQueue
Crash-safe outbound delivery queue. Messages are persisted to SQLite before delivery attempts, surviving daemon restarts.
deliveryMirror
deliveryMirror
Session delivery mirroring for deduplication. Records delivered messages so they can be injected into agent context, preventing repeated deliveries.
observability
observability
Observability persistence layer. Stores channel health snapshots, execution metrics, and system telemetry in SQLite for historical analysis and dashboards.
The spend kill-switch is configurable in
config.yaml only — there is no environment-variable form. See Observability → Spend Governance for the runtime behaviour (cooperative abort, three-state pricing, the events, and the pricing_gap fleet finding).Diagnostics
diagnostics.recallTrace
diagnostics.recallTrace
Per-recall ranking trace written as bounded JSONL for “why did recall pick X?” debugging. Opt-in (default off) — unlike its
cacheTrace sibling (which defaults true), the recall trace is only captured during a focused debug session.Credential Broker Bindings (executor.broker)
The
executor.broker block is wired into the daemon (AppConfigSchema → setupBroker): adding it to config.yaml starts the broker at boot — a TCP listener plus a 0600 unix socket at ~/.comis/broker.sock.~/.comis/config.yaml
HostRule fields (hostRules[*]):
For full configuration details and examples, see Credential Broker →.
Related
Environment Variables
Environment variable reference
Hot Reload
Configuration hot reload behavior
Secret Manager
Encrypted secret storage and $ substitution
Configuration Guide
Step-by-step configuration walkthrough
