Skip to content

Logging

When cliq server runs, it produces structured JSON Lines logs capturing everything from high-level events (“server started”, “pipeline completed”) down to fine-grained internal traces (“signal file read”, “phase poll tick”). You control the verbosity with two knobs — one for the server shell, one for the core pipeline engine — and can override individual components when debugging a specific subsystem.


Logging is enabled automatically when cliq server start runs. With default settings, logs are written at info level:

Terminal window
cliq server start
# Logs to /var/log/cliq/server.log (or ~/.cliqrc/logs/server.log if /var/log is not writable)

To see everything:

{
"logging": {
"server_level": "trace",
"core_level": "trace"
}
}

To see only errors and warnings:

{
"logging": {
"server_level": "warn",
"core_level": "warn"
}
}

Five levels, from most severe to most verbose:

LevelNumericWhat it captures
error0Failures that prevent an operation from completing — mesh registration errors, pipeline crashes, notification delivery failures
warn1Degraded conditions — stale config detected, orphaned workspace cleanup, best-effort operations that failed silently
info2Key lifecycle events — server start/stop, task received, pipeline dispatched/completed, mesh registered, notification sent
debug3Internal decisions — A2A path delegation, workspace created/torn down, channels created, checks executed, prompts generated
trace4Every breath — individual HTTP requests, WebSocket messages, phase poll ticks, signal file reads

A configured level allows all messages at that level and above (more severe). Setting server_level: "debug" captures error, warn, info, and debug but not trace.


Logs from the cliq server fall into two categories, each with its own level control:

These handle HTTP, WebSocket, A2A protocol, mesh registration, and task execution — the “outer shell” of the server process.

ComponentWhat it covers
serverHTTP request handling, WebSocket connections, static file serving, server start/stop
a2aA2A task dispatch, capability extraction, pipeline lifecycle, status polling
meshSavant token exchange, mesh registration/deregistration
loggerLogger initialization and shutdown (meta)

Controlled by logging.server_level.

These are the internal pipeline orchestration modules — the same code that runs inside cliq run. When invoked through the server (via A2A tasks), these modules produce log entries. When invoked through the CLI directly, they are silent (the logger is not initialized).

ComponentWhat it covers
orchestratorPhase activation, gate loops, escalation decisions
pipelineTmux session management, pane launch/reuse
signalSignal file writes (done, verdict, status), signal clearing
channelChannel directory creation for inter-agent communication
workflowWorkflow YAML parsing and loading
gateDeterministic check execution, verdict parsing
notifyNotification dispatch to Slack/Jira
promptAgent prompt generation
registryInstance registration/deregistration

Controlled by logging.core_level.


Add a logging section to your ~/.cliqrc/settings.json:

{
"logging": {
"server_level": "info",
"core_level": "info",
"component_levels": {},
"dir": "",
"max_file_size_mb": 50,
"max_files": 5
}
}
FieldTypeDefaultDescription
server_levelstring"info"Log level for server components (server, a2a, mesh, logger).
core_levelstringSame as server_levelLog level for core engine components (orchestrator, pipeline, signal, etc.). When omitted, inherits from server_level.
component_levelsobject{}Per-component level overrides. Keys are component names, values are log levels. Takes precedence over both server_level and core_level.
dirstringAutoDirectory for log files. Tries /var/log/cliq/ first, falls back to ~/.cliqrc/logs/. Set explicitly to control placement.
max_file_size_mbnumber50Maximum size of server.log before rotation (in MB).
max_filesnumber5Number of rotated log files to retain. Oldest files are deleted when the limit is reached.

For each log entry, the effective level is determined by:

  1. component_levels[component] — if an override exists for this component, use it
  2. core_level — if the component is a core engine component, use core_level
  3. server_level — fallback for all other (server) components

This means you can keep the server quiet (server_level: "warn") while watching the pipeline engine in detail (core_level: "debug"), or vice versa. And if you need to debug one specific subsystem, override just that component.


The component_levels map lets you set a different log level for any individual component without affecting the rest.

Debug mesh registration without flooding other logs:

{
"logging": {
"server_level": "info",
"core_level": "info",
"component_levels": {
"mesh": "debug"
}
}
}

Trace signal file operations while keeping everything else at info:

{
"logging": {
"server_level": "info",
"core_level": "info",
"component_levels": {
"signal": "trace"
}
}
}

Full detail on gate evaluation, quiet everywhere else:

{
"logging": {
"server_level": "warn",
"core_level": "warn",
"component_levels": {
"gate": "trace"
}
}
}

Silence a noisy component:

{
"logging": {
"server_level": "debug",
"core_level": "debug",
"component_levels": {
"server": "warn"
}
}
}

Logs are written as JSON Lines — one JSON object per line. This format is human-readable with jq, machine-parseable by log aggregators (ELK, Datadog, Loki), and trivially greppable.

{
"ts": "2026-03-18T14:23:01.456Z",
"level": "info",
"component": "a2a",
"msg": "Task received",
"ctx": {
"taskId": "abc-123",
"capability": "feature_dev_js"
}
}
FieldTypeAlways presentDescription
tsstringYesISO 8601 timestamp
levelstringYesLog level (error, warn, info, debug, trace)
componentstringYesOriginating subsystem (see component tables above)
msgstringYesHuman-readable message
ctxobjectNoStructured context — only present when there is additional data

Server startup:

{"ts":"2026-03-18T14:23:00.100Z","level":"info","component":"logger","msg":"Server logger initialized","ctx":{"dir":"/var/log/cliq","server_level":"info","core_level":"info"}}
{"ts":"2026-03-18T14:23:00.200Z","level":"info","component":"a2a","msg":"A2A endpoints mounted","ctx":{"agent_card_path":"/.well-known/agent-card.json","rpc_path":"/a2a/jsonrpc","base_url":"https://cliq.example.com"}}
{"ts":"2026-03-18T14:23:00.300Z","level":"info","component":"server","msg":"HTTP server listening","ctx":{"port":4100}}
{"ts":"2026-03-18T14:23:00.400Z","level":"info","component":"server","msg":"Server started","ctx":{"port":4100,"pid":12345}}
{"ts":"2026-03-18T14:23:01.000Z","level":"info","component":"mesh","msg":"Registered with mesh","ctx":{"mesh":"savant-prod","type":"savant"}}

A2A task lifecycle:

{"ts":"2026-03-18T14:25:00.000Z","level":"info","component":"a2a","msg":"Task received","ctx":{"taskId":"abc-123","capability":"feature_dev_js"}}
{"ts":"2026-03-18T14:25:00.100Z","level":"info","component":"a2a","msg":"Task created","ctx":{"task_id":"def-456","team":"feature-dev-js","workspace":"/tmp/cliq-workspaces/def-456"}}
{"ts":"2026-03-18T14:25:00.200Z","level":"debug","component":"a2a","msg":"Workspace created","ctx":{"task_id":"def-456","workspace":"/tmp/cliq-workspaces/def-456"}}
{"ts":"2026-03-18T14:25:00.300Z","level":"info","component":"a2a","msg":"Pipeline dispatched","ctx":{"taskId":"abc-123","internal_id":"def-456","team":"feature-dev-js"}}
{"ts":"2026-03-18T14:25:30.000Z","level":"trace","component":"a2a","msg":"Phase poll","ctx":{"task_id":"def-456","running_phase":"architect"}}
{"ts":"2026-03-18T14:28:00.000Z","level":"info","component":"a2a","msg":"Pipeline finished","ctx":{"task_id":"def-456","state":"completed","pipeline_status":"COMPLETED"}}
{"ts":"2026-03-18T14:28:00.100Z","level":"info","component":"a2a","msg":"Task finished","ctx":{"taskId":"abc-123","state":"completed","message":"Pipeline completed"}}
{"ts":"2026-03-18T14:28:00.200Z","level":"debug","component":"a2a","msg":"Workspace teardown","ctx":{"task_id":"def-456","workspace":"/tmp/cliq-workspaces/def-456"}}

Gate evaluation (at debug level):

{"ts":"2026-03-18T14:26:00.000Z","level":"debug","component":"gate","msg":"Running checks","ctx":{"count":3,"cwd":"/tmp/cliq-workspaces/def-456"}}
{"ts":"2026-03-18T14:26:05.000Z","level":"debug","component":"gate","msg":"Checks completed","ctx":{"total":3,"passed":2,"failed":1}}
{"ts":"2026-03-18T14:26:10.000Z","level":"debug","component":"gate","msg":"Verdict parsed","ctx":{"outcome":"ROUTE","target":"developer"}}

The logger resolves the log directory in this order:

  1. logging.dir — if explicitly set in settings, use that directory
  2. /var/log/cliq/ — if the directory exists and is writable
  3. ~/.cliqrc/logs/ — fallback (always writable by the current user)

The active log file is always named server.log within the resolved directory.

To check where logs are being written, look at the first entry after server start — the logger component logs the resolved directory:

Terminal window
head -1 /var/log/cliq/server.log | jq .
# or
head -1 ~/.cliqrc/logs/server.log | jq .

When server.log exceeds max_file_size_mb, it is rotated:

  1. server.log.{max_files} is deleted (oldest archive)
  2. Each server.log.N is renamed to server.log.{N+1}
  3. server.log is renamed to server.log.1
  4. A fresh server.log is created on the next write

With the defaults (max_file_size_mb: 50, max_files: 5), you retain up to 300 MB of log history:

server.log # current (up to 50 MB)
server.log.1 # previous rotation
server.log.2
server.log.3
server.log.4
server.log.5 # oldest — deleted on next rotation

JSON Lines is designed for tooling. Here are common patterns:

Terminal window
grep '"level":"error"' /var/log/cliq/server.log | jq .
Terminal window
tail -f /var/log/cliq/server.log | jq .
Terminal window
jq 'select(.component == "a2a")' /var/log/cliq/server.log
Terminal window
jq 'select(.level == "error" or .level == "warn")' /var/log/cliq/server.log
Terminal window
jq 'select(.ts >= "2026-03-18T14:00:00" and .ts <= "2026-03-18T15:00:00")' /var/log/cliq/server.log
Terminal window
jq 'select(.ctx.taskId == "abc-123" or .ctx.task_id == "abc-123")' /var/log/cliq/server.log
Terminal window
jq -r '.component' /var/log/cliq/server.log | sort | uniq -c | sort -rn
Terminal window
tail -20 /var/log/cliq/server.log | jq '{ts: .ts, level: .level, comp: .component, msg: .msg}'

Maximum verbosity during local development:

{
"logging": {
"server_level": "trace",
"core_level": "trace",
"max_file_size_mb": 10,
"max_files": 2
}
}

Keep HTTP noise down, but capture full pipeline orchestration detail:

{
"logging": {
"server_level": "warn",
"core_level": "info"
}
}

Focused debugging of the A2A + mesh layer:

{
"logging": {
"server_level": "info",
"core_level": "info",
"component_levels": {
"a2a": "trace",
"mesh": "debug"
}
}
}

When gates keep failing and you need to see check execution and verdict parsing:

{
"logging": {
"server_level": "info",
"core_level": "info",
"component_levels": {
"gate": "trace",
"signal": "debug"
}
}
}

Write logs to a shared volume (e.g., for centralized collection):

{
"logging": {
"dir": "/mnt/logs/cliq",
"server_level": "info"
}
}

ContextLogger active?Where logs go
cliq server startYesserver.log (JSON Lines)
cliq run (interactive)Noorchestrator.log (plain text, in .cliq/)
cliq run --headlessNoorchestrator.log (plain text, in .cliq/)

The server logger (SLog) is initialized only during cliq server start. When cliq run invokes the same core modules (signal manager, channel manager, etc.) directly, those modules call SLog but the calls are no-ops because the logger was never initialized. This is by design — interactive runs already have the orchestrator log and tmux pane output.


/var/log/cliq/ # or ~/.cliqrc/logs/
├── server.log # current log file
├── server.log.1 # most recent rotation
├── server.log.2
├── server.log.3
├── server.log.4
└── server.log.5 # oldest rotation

IssueFix
No log file createdCheck that the server was started with cliq server start. The logger is not active during cliq run.
Logs in ~/.cliqrc/logs/ instead of /var/log/cliq//var/log/cliq/ is not writable by the current user. Create the directory and set permissions: sudo mkdir -p /var/log/cliq && sudo chown $USER /var/log/cliq
Log file growing too largeReduce max_file_size_mb or lower the log level. At trace level with active A2A traffic, logs grow quickly.
Missing context in log entriesNot all entries include a ctx field. Entries with no additional data beyond the message omit ctx entirely.
Want logs from cliq runInteractive pipelines write to .cliq/orchestrator.log (plain text). Server logging covers the server process only.
Component not loggingCheck that the effective level for that component allows the log level you expect. Use component_levels to set the component to trace for debugging.