Where Logs Go
Comis writes logs to two places simultaneously:- Log file:
~/.comis/logs/daemon.log— A structured JSON file that is automatically rotated when it gets too large (10 MB by default). The daemon keeps up to 5 rotated copies before deleting the oldest. - Console output: The same log data is also written to standard output. This is
what you see when using
pm2 logsorjournalctl.
Logs are in JSON format for machine readability. Each log line is a JSON object
with fields like
level, msg, module, and timestamps. You typically view them
through pm2 or journalctl, which display them line by line.Log Levels
Comis uses Pino’s standard log levels plus a customaudit level. From most
severe to least:
The
silent value exists at the logger API layer to suppress output, but the
daemon.logLevels configuration only accepts trace, debug, info, warn,
error, and fatal. To quiet a noisy module, raise its level (for example,
set it to error) rather than relying on silent.Viewing Logs
- pm2
- systemd
- Log file
View the last 50 lines (snapshot):Follow logs in real time (press Ctrl+C to stop):pm2 keeps its own log files at
~/.pm2/logs/. The --lines flag shows recent
lines from those files, and omitting --nostream follows them live.Changing Log Levels
Per-Module Overrides
Comis is organized into modules (daemon, agent, channels, scheduler, etc.), and you can set a different log level for each one. This is useful when you want to debug a specific part of the system without being overwhelmed by output from everything else. Add alogLevels section under daemon in your configuration:
agent module logs everything including DEBUG messages, while the
channels module only logs warnings and errors.
Runtime Level Changes
You can change log levels without restarting the daemon by using thedaemon.setLogLevel RPC command. This is useful for temporarily enabling DEBUG
logging to investigate an issue, then switching back to INFO when you are done.
Error Classification
Every ERROR and WARN log entry includes two mandatory fields that help you quickly understand and act on problems:hint— A human-readable string explaining what to do about the errorerrorKind— A classification tag from a fixed set of 9 categories
ErrorKind Values
Memory and Recall Signals
Thememory module (set its level under daemon.logLevels.memory, shown above)
emits two families of structured signal: step-tagged write/curation logs and
graceful-degradation WARNs.
Step-tagged write and curation logs
Memory writes and the background curation jobs carry astep tag plus a
durationMs timing field, so you can filter the memory pipeline by stage:
memory:entities_linked and memory:consolidated events — see
Observability → Memory & Recall Diagnostics.
Graceful-degradation WARNs (no silent degradation)
Recall degrades gracefully, and every degradation path logs a WARN carrying the mandatoryerrorKind + hint pair (see Error Classification
above) — recall never drops to a cheaper path silently:
As with all Comis logs, these never log secrets, message bodies, or absolute
paths — the per-recall ranking detail lives only in the opt-in, full-sanitized
recall-trace artifact,
never in
daemon.log.
Field Dictionary
Every log entry is a JSON object. Beyond the standard Pino fields (level, time,
msg, pid, hostname), Comis uses 48 canonical fields organized by category.
These are the fields you will see when reading JSON log output.
Core Identity
Timing
Operation
Error
Token and Cost
Pipeline
WebSocket
Message
Agent Execution
System
Truncation Flags
Security
Comis automatically redacts sensitive information from log output. API keys, tokens, passwords, and other credentials are replaced with[REDACTED] before being written
to the log file or console.
The redaction engine covers all credential field name patterns across multiple nesting depths (top-level
through 3 levels of nesting):
Nested paths are also redacted:
config.telegram.botToken, *.*.apiKey, etc.,
up to 4 levels deep (*.*.*.*).
You do not need to worry about sensitive data in logs. Comis automatically detects
and hides API keys, tokens, and passwords using a compiled redaction engine. The
redaction rules are compiled once at startup for zero runtime overhead.
Log Rotation
Comis automatically rotates all observability log streams to bound disk usage.observability.logRotation — Cross-Stream Policy
A single policy governs five log streams under ~/.comis/logs/:
daemon.log— daemon-wide structured JSON logcache-trace.jsonl— per-turn cache observability (cache hits, misses, tokens)config-audit.jsonl— config-write audit trail (all writes to config.yaml)session-index.YYYY-MM-DD.jsonl— append-only session index (date-rolled, one file per UTC day)*.trajectory.jsonl— per-session trajectory recordings (one file per agent session)
observability.logRotation in your config.yaml:
How to Verify
Inspect the resolved policy, including any operator overrides, with:Storage Budget
Worst-case storage: 5 streams × 5 files × 50 MB = 1.25 GB. WithcompressAged: true (the default), gzipped JSON text compresses approximately 5×, so realistic steady-state is ~300 MB.
Increase maxFiles or maxAgeDays if you need more history; reduce them on tight disks.
Per-Stream Behavior
daemon.log — pino-roll handles size-based rotation in a worker thread; rotated files become daemon.1.log, daemon.2.log, etc. The daemon-startup sweep gzips any uncompressed rotated files and removes those beyond maxFiles or older than maxAgeDays.
cache-trace.jsonl — a per-file cap (50 MB) prevents a single cache-trace file from growing unbounded. The startup sweep prunes accumulated history against maxFiles and maxAgeDays.
config-audit.jsonl — a small (10 MB) rename-shift rotation runs on every append, keeping the active file write-friendly. The startup sweep gzips the resulting rotated copies and prunes them by count and age.
session-index.YYYY-MM-DD.jsonl — a new file starts each UTC day (date-roll). Old dated files are pruned by the startup sweep against maxFiles and maxAgeDays. Only today’s dated file is treated as the active base and is never pruned.
*.trajectory.jsonl — one file per agent session, with a 10 MB soft cap and a 50 MB hard cap applied in-session. Accumulated session files across past sessions are pruned by the startup sweep against maxFiles and maxAgeDays.
Per-File daemon.logging Keys
The daemon.logging.maxSize and daemon.logging.maxFiles keys (documented below) apply to daemon.log specifically. When both key families are set, observability.logRotation takes precedence for the cross-stream sweep, and daemon.logging.maxSize retains its role as the pino-roll size threshold when observability.logRotation.maxSizeBytes is unset.
Prefer
observability.logRotation for a unified, consistent rotation policy
across all five log streams. The daemon.logging keys govern only daemon.log.daemon.logging Configuration
You can customize per-file daemon-log rotation with these keys:
With the cross-stream policy active (the default),
observability.logRotation
controls the 50 MB roll threshold and the 5-file / 30-day retention for all streams.
The daemon.logging.maxSize value still reaches pino-roll as the size threshold if
you have not set observability.logRotation.maxSizeBytes.Trace Files
In addition to the main log file, Comis can write per-agent JSONL trace files that capture detailed execution data. These are useful for debugging specific agent conversations.Daemon
How the daemon starts, runs, and shuts down.
Monitoring
Health checks that watch your system’s vital signs.
Observability
Token tracking, cost estimation, and performance data.
Troubleshooting
Common problems and how to solve them.
