Troubleshooting
Hansard separates provider sources, normalized archive files, derived viewer payloads, search indexes, and the background watcher. Diagnose the affected layer before choosing a repair.
Start in the app
Section titled “Start in the app”First determine whether the data is absent or only hidden. In Conversations, select Reset filters, search a distinctive phrase, then set Source, Time, and Folder one at a time. If the conversation opens but looks incomplete, inspect its source and Not recorded fields rather than assuming the viewer dropped them.
Next open Settings → Indexing & Imports. Confirm the source-selection mode, Sources scanned, watcher status, rolling window, and whether search indexing is paused. Review incomplete runs covers lifecycle-only records hidden from ordinary lists. These checks distinguish an app filter problem from a watcher, importer, or index problem before the terminal diagnostics below change any state.
Start with a health snapshot
Section titled “Start with a health snapshot”-
Inspect the active archive and runtime.
Terminal window hansard status -
Run installation and source diagnostics.
Terminal window hansard doctor -
Check the watcher and search index separately.
Terminal window hansard watcher statushansard index status -
Capture JSON when filing an issue or comparing two runs.
Terminal window hansard status --jsonhansard doctor --json
A source or conversation is missing
Section titled “A source or conversation is missing”Confirm that the source is in the configured list, then preview a direct import:
hansard config sources listhansard import --source cursor --since all --dry-run --explain-skipsIf the dry run finds candidates, run the import without --dry-run. Add
--json to inspect structured imported, skipped, and error results.
Check these source-specific boundaries:
claude-cloudis opt-in and never part of--source all. Runhansard import claude-cloud --since allexplicitly.devin-cloudis opt-in the same way and needs a Devin API key inDEVIN_API_KEYordevin.apiKey. It reports a missing key as a setup note rather than an error, and skipscli-origin cloud rows thatdevin-clialready archives in full.julesis opt-in the same way and needs a Jules API key inJULES_API_KEYorjules.apiKey;hansard doctorshows an informational row when none is set. Jules exposes no model ids or token usage, so its sessions are archived without model or spend attribution unlessjules.modelHintdeclares one.copilot-agent-cloudis opt-in and needs a GitHub token inGH_TOKEN,GITHUB_TOKEN, orcopilot.token, or a signed-in GitHub CLI;hansard doctorshows an informational row when neither is available. Its agent-task metadata allows 60 requests per hour, so a run during a cooldown imports sessions without the prompt, model, and premium-request charge and says so. An unavailable transcript degrades to a metadata-only import rather than failing. These sessions report premium requests instead of tokens, so they carry no token usage or spend.cursor-cloudis opt-in and needs a Cursor API key inCURSOR_API_KEYorcursor.apiKey;hansard doctorshows an informational row when none is set. The transcript comes from the legacy v0 conversation endpoint, and an agent that has been deleted or archived answers409: it still imports as a metadata shell carrying each run’s final reply. Cloud agents expose no tool calls and no model id, so they stay unmodelled and never appear in the tool stats. Token usage is an early-access endpoint and is skipped with a warning when the account does not have it.factory-cloudis opt-in and needs a Factory API key inFACTORY_API_KEYorfactory.apiKey;hansard doctorshows an informational row when none is set. Every Droid Sessions API endpoint is enabled for selected organizations only, so an account without it gets one “not enabled for this organization” warning and no error. A session the localfactoryimport already archived keeps its own transcript and only gains cloud metadata.codex-cloudis opt-in and needs the Codex CLI installed and signed in;hansard doctorshows an informational row when the binary is not on PATH. A missing binary, a signed-out CLI, and an exhausted plan all produce a setup note rather than an error. The CLI returns the task record and its diff only, so these tasks carry no prompt, no assistant text, no tool calls, no model, and no token usage.- ChatGPT and Claude.ai histories require downloaded web exports.
- Windsurf protobuf-only rows remain repair stubs until a downloaded trajectory is imported, optionally with its claim token.
- Modern Cursor transcripts and historical Cursor SQLite data have different coverage; a complete manual import is the recovery path for older history.
- Aider histories are repository-local, so the repository containing
.aider.chat.history.mdmust still be reachable.
When doctor --deep reports an archived parser version older than the current
importer, reimport that source with --since all. hansard rebuild does not
rerun provider parsers.
Setup reports insufficient disk space
Section titled “Setup reports insufficient disk space”Run a read-only inventory and storage plan against the intended archive path:
hansard init --dry-run --data-dir /path/to/archiveThe source-byte total describes local provider history, not a download. Hansard also preserves raw records and writes normalized transcripts, events, Markdown, viewer payloads, and indexes. The displayed range keeps a separate recovery reserve available because a completely full archive filesystem can also block cleanup.
Choose a filesystem with more free space or use hansard init --skip-import to
finish configuration without enumerating or copying provider history. A bounded
source scan is explicitly a lower bound. Artifact capture is excluded from the
projection, so leave additional space when it will be enabled. Existing shared
raw-source snapshots can be reviewed without deleting them:
hansard prune raw-sources --dry-runApply a prune only after reviewing its preservation and rebuild implications.
The watcher is running but data is stale
Section titled “The watcher is running but data is stale”Stream the watcher log while producing one new provider message:
hansard watcher logs --followThen test the same source directly:
hansard import --source cursor --since 30d --dry-run --explain-skipsIf manual import works, recreate the background process and its filesystem watches:
hansard watcher restartAfter changing the source list, a restart establishes event watchers for the
new roots immediately. A repeated tick skipped: previous tick still running
message means a previous pass is still active; inspect nearby log lines for the
slow or failing source rather than assuming the process has stopped.
Search returns no results
Section titled “Search returns no results”Check whether the index is paused, then rebuild it:
hansard index statushansard index resumehansard index rebuildUse --markdown-fallback only for legacy archives that lack canonical events:
hansard history "migration plan" --markdown-fallbackSearch filters combine. Remove --repo, --provider, --tool, or --command
one at a time when diagnosing an unexpectedly empty result. --no-web-chats
intentionally excludes imported non-repository web conversations.
The viewer is stale or will not open
Section titled “The viewer is stale or will not open”Refresh view payloads without reading provider sources:
hansard rebuild --since allOpen the browser viewer directly if native-app activation fails:
hansard app --no-fallbackhansard web --no-openapp --no-fallback reports a missing or unsupported native app instead of
silently opening the browser fallback. The default browser viewer binds to
127.0.0.1:7824; choose another port when it is occupied:
hansard web --no-open --port 7825Binding beyond loopback requires a password. A bare --host binds to all
interfaces and is not appropriate without a deliberate network boundary:
HANSARD_WEB_PASSWORD='<strong-password>' \ hansard web --host 0.0.0.0 --read-onlyA web export will not import
Section titled “A web export will not import”- Run
hansard doctorand installunzipwhen ZIP support is missing, or pass an extracted folder. - Move the export into a terminal-readable local directory if access is denied.
- For split ChatGPT privacy exports, pass the parent
User Online Activityfolder rather than one conversation part. - Supply
--usernamefor a new export account when it cannot be inferred. - Use
hansard import chatgpt --instructionsorhansard import claude-web --instructionsto print the current walkthrough.
Original provider files are unavailable
Section titled “Original provider files are unavailable”Hansard may have preserved individual source files even after a provider rotated or deleted them. Preview safe restoration:
hansard restore-sources claude --dry-runThe command never overwrites existing files and never restores shared SQLite stores. Claude Code also has a dedicated preview:
hansard repair claude-code-backups --dry-runAfter restoring source files, reimport the affected provider with --since all.
Optional system tools are missing
Section titled “Optional system tools are missing”hansard doctor reports the relevant dependency and affected feature:
| Tool | Impact when missing |
|---|---|
sqlite3 |
Required for Codex, Devin, and Cursor SQLite stores. |
rg |
Recommended for fast recall and search. |
unzip |
Required to read ZIP web exports; extracted folders remain usable. |
Last-resort refresh
Section titled “Last-resort refresh”When a package upgrade requires a clean local reimport, preview the update path:
hansard update --dry-run --since allupdate clears local agent-session archive and derived import state before
reimporting configured sources. Confirm that provider histories or restorable
raw backups exist first. reset is broader and should be reserved for a fresh
setup.