Skip to content

Background work

Hansard shares a work queue across imports, indexing, sync, and Stats. This reference explains its resource controls and temporary files. For normal setup and troubleshooting, start with Background archiving or Maintenance.

The default queue admits two jobs and reserves one eighth of system RAM, with a memory allowance between 1,536 MB and 4,096 MB.

Environment variable Accepted range Effect
HANSARD_WORKER_CONCURRENCY 1–8 Maximum admitted jobs. Default: 2.
HANSARD_WORKER_MEMORY_MB 256–32768 Combined memory estimate used to admit jobs.

These values are admission estimates, not operating-system memory limits. A job whose estimate exceeds the allowance runs alone. Capture and interactive queries have priority. Waiting maintenance gains priority over time.

The queue releases a running job when its process exits. If a full disk prevents a finished job from releasing its place, the queue releases it when writes succeed again. A waiting job loses its place after five minutes without a check-in and regains eligibility when it checks in again.

Automatic meaning search, graph builds, labeling, summaries, and archive refresh also follow the background-work controls in Settings → Imports → Search. Battery power, thermal pressure, unknown power state, or Pause holds this work. Foreground reads remain available. The retired index.batteryIntervalMinutes setting has no effect.

The watcher refreshes older archived conversations after an update. It rebuilds conversation data, converts eligible files to archive format 2, and compresses eligible raw copies. When provider history is gone, or a conversation came from a manual export, it can parse the preserved raw copies again for supported sources. Older conversations whose provider files the import window does not reach are read again in one low-priority import run. Rebuild everything in Settings → Imports → Maintenance, or hansard rebuild --everything, asks the refresh for one pass that derives and parses every conversation again.

The refresh waits for AC power, acceptable thermal conditions, and idle import work. Each batch holds the import lock for at most 15 seconds, then releases it. The next batch starts at least 45 seconds later. Conversations that are still growing remain with their normal imports. Very large conversations wait for normal memory pressure before a larger worker starts.

The refresh never accepts a parse with fewer messages or replaces files written by newer code. Storage conversion waits until all relevant installed copies and sync devices support the new form. These checks also apply to explicit rebuild and compaction commands.

Use Settings → Imports → Maintenance → Refresh after updates to control automatic refresh. The equivalent configuration key is archive.autoRefresh:

Terminal window
hansard config set archive.autoRefresh false
hansard status
hansard watcher status

hansard status reports it on its Archive refresh line as off, current, running, waiting, failed, or newer. A stopped batch resumes from its saved position. Explicit maintenance commands remain available when automatic refresh is off.

The watcher records its loaded runtime in state/watcher-runtime.json under Hansard home. It restarts after loaded code changes, after its Node.js binary disappears, and once a day. Before restarting, it checks that the replacement code loads and waits for its current work to finish.

A restart for changed code or a missing binary stops admitting new work after 30 minutes. Ten minutes later, it stops remaining background jobs. Interrupted imports and sync resume afterward. This does not stop agents that the MCP host runs. The login service retains supervision through the restart.

To turn off either automatic restart:

Terminal window
hansard config set watcher.restart.onCodeChange false
hansard config set watcher.restart.daily false

hansard status and hansard doctor identify older running copies and the action that restarts each one. Settings → Imports → Importer version can move the watcher and login startup to the copy serving the app.

Terminal window
hansard watcher logs
hansard watcher logs --follow

The watcher writes logs/supervisor.log. At 4 MB, it replaces supervisor.log.1 with a copy and empties the live file in place. A pass that overlaps later ticks logs the first skipped tick and a final skipped-tick count. hansard doctor reports slow watcher ticks and their slowest steps.

One Stats process per Hansard home serves open viewers. It starts with the first Stats request and reuses unchanged session, classification, and configuration data. Imports update the conversations that changed instead of reading the whole archive for each request.

Changes to memories, classification settings, time zone, calendar day, or a curated price window can trigger recomputation. Otherwise the full result refreshes at most every six hours. Memory ages refresh separately.

The process exits after ten minutes without a request, shortly after the last viewer closes, or when its code changes. A viewer running another installed copy computes its result in a separate child. If an internal comparison disagrees with a full computation, Hansard stops using the shared process until an update.

Set HANSARD_STATS_ENGINE=0 in the launching environment to compute each Stats and Pricing request in a separate child instead.

During the desktop app’s first import, Stats can show a preliminary count from Claude Code and Codex source files. A notice identifies these sources. The same parsers count them before and after archiving, and the preliminary view ends when their imports finish.

The watcher runs one MCP host for the Hansard home. Agent recall connections use lightweight relays carrying their own session identity. A relay uses a host of its own version or newer. Without a compatible host, it serves its session itself and checks again every minute.

Relays reconnect and repeat their handshake after a host restart. The host waits between calls and for its agent runs before leaving after a code change. hansard status reports its version.

Codex uses the host’s loopback HTTP endpoint. hansard integrations sync updates that entry when the host starts or stops. The managed entry allows 1,860 seconds for waiting tools and preserves a larger existing timeout. Reload the agent after changing its integration.

Environment variable Effect
HANSARD_MCP_HOST=off Serve each recall connection in its own process.
HANSARD_MCP_PORT Request another loopback port instead of 7839. If unavailable, the host selects and records another port.

See Agent recall for installation and Agent messaging for delivery behavior.

Parser checkpoints speed up growing Claude Code and Codex transcripts. Reuse requires matching source identity, parser settings, and a hash of the previous source prefix. Edits, truncation, or incompatible checkpoints trigger a full parse. A file that grows during parsing can retain its checkpoint when the captured prefix remains unchanged.

Checkpoints use a small record and an append-only message log. Saving one writes only changed messages. Other import reads and output generation can still cover the complete transcript.

Subagent summaries live under cache/subagent-runs/, one file per parent. Unchanged runs reuse their summary. A child already parsed in the same import is not parsed again for its parent. Parent imports can resume a child’s parser checkpoint but do not create one. Cache cleanup removes unused summaries after 30 days. Set HANSARD_SUBAGENT_RUN_CACHE=0 to disable this cache.

Original text can remain in caches. Parser checkpoints and subagent summaries can contain source text before redaction. Protect Hansard home as private data. They are regenerable caches, not substitutes for preserved raw files.

Automatic maintenance shares a 2 GiB budget across regenerable received views and source copies, decompressed Markdown, conversation derivations, subagent summaries, and transcript checkpoints. Eligible entries expire after 30 days unused. Older single-file transcript checkpoints expire after seven days unused. A pass removes at most 256 entries and keeps active readers pinned, so a backlog can require several passes. Reported bytes are logical sizes, not a promise of physical disk savings on a copy-on-write filesystem.

The watcher’s separate conversation derivation cache retains recently active conversations, up to 1 GiB in total. It avoids writing when less than 2 GiB would remain above the storage floor. Turn it off with:

Terminal window
hansard config set archive.derivationCache false

On Node.js 22.8 and later, import children also reuse compiled modules under cache/node-compile-cache/. Set NODE_DISABLE_COMPILE_CACHE=1 to disable this Node.js cache.

A store shared by several conversations is preserved once per relevant change. An unchanged snapshot can be reused for six hours, controlled by HANSARD_SHARED_RAW_SNAPSHOT_INTERVAL_MS. Codex and Cursor snapshots must still hold the exact conversation facts the importer uses. A newer turn timestamp alone does not require another Codex state-database snapshot.

Each store’s latest capture record lives under cache/shared-raw-snapshots/. Maintenance removes these records 30 days after their last capture. It removes the older combined cache/shared-raw-snapshots.json after seven days unchanged.

For large accumulated Cursor snapshots, automatic maintenance can queue a consolidation import. It does so when old captures occupy at least 256 MiB and four times the new snapshot size, with room for another capture. Existing conversations then reference the newest snapshot that preserves their facts. Ordinary cleanup removes copies whose references have been released.

The import ledger uses state/imports.json plus state/imports.journal.jsonl. Imports append changed entries and fold the journal when it would outgrow the ledger. hansard import ledger reads both. Older copies never discard ledger entries written by newer ones.

Viewer responses include a Server-Timing header with their measured phases. hansard doctor summarizes slow or abandoned reads and event-loop delays over the last 24 hours. state/viewer-requests.json retains hourly totals and the last 50 slow or abandoned requests.

The normal read budgets are 250 ms for a conversation, two seconds for a conversation list, 12 seconds for a Stats refresh, and one second for most other reads. Streams, downloads, remote-service waits, and writes do not enter the slow-read report. These diagnostic budgets are not response-time promises.

Saved Stats payloads live under indexes/stats/v2-<rules>/. Earlier versions’ payloads expire after a week unused. Pricing, Behavior, and project-filter payloads live under indexes/viewer-payloads/, limited to 64 MiB per page and two weeks of age. Older naming schemes retain the same limits separately.