Troubleshooting Guide

User Section

These are the most common issues reported by dashboard users.

Dashboard shows no events

Symptoms: The dashboard loads but the timeline is empty. The connection dot may be green (connected) but no event cards appear.

Checklist:

  1. Verify hook installation. Claude Code must have send-event.js registered for all 24 hook events in ~/.claude/settings.json:
    {
      "hooks": {
        "PreToolUse":          [{ "type": "command", "command": "node /path/to/send-event.js", "matcher": "" }],
        "PostToolUse":         [{ "type": "command", "command": "node /path/to/send-event.js", "matcher": "" }],
        "PostToolUseFailure":  [{ "type": "command", "command": "node /path/to/send-event.js", "matcher": "" }],
        "Notification":        [{ "type": "command", "command": "node /path/to/send-event.js", "matcher": "" }],
        "PreCompact":          [{ "type": "command", "command": "node /path/to/send-event.js", "matcher": "" }],
        "PermissionRequest":   [{ "type": "command", "command": "node /path/to/send-event.js", "matcher": "" }],
        "Elicitation":         [{ "type": "command", "command": "node /path/to/send-event.js", "matcher": "" }],
        "PermissionDenied":    [{ "type": "command", "command": "node /path/to/send-event.js", "matcher": "" }],
        "UserPromptSubmit":    [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "Stop":                [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "SessionStart":        [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "SessionEnd":          [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "SubagentStart":       [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "SubagentStop":        [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "TaskCompleted":       [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "TeammateIdle":        [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "StopFailure":         [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "PostCompact":         [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "InstructionsLoaded":  [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "ConfigChange":        [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "CwdChanged":          [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "FileChanged":         [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "TaskCreated":         [{ "type": "command", "command": "node /path/to/send-event.js" }],
        "ElicitationResult":   [{ "type": "command", "command": "node /path/to/send-event.js" }]
      }
    }

    Run the appropriate setup script to install hooks: setup.ps1 (Windows), setup-wsl.sh (WSL), setup-macos.sh (macOS), or setup-linux.sh (Linux).

  2. Verify the server is running. From any terminal:
    curl http://localhost:3131/health

    Expected response: {"status":"ok"}. If the command fails, the server is not running.

  3. Check port 3131. Ensure no firewall rule blocks localhost:3131. On WSL2, verify that localhost forwarding is working (Windows should forward WSL localhost automatically on recent builds).
  4. Start a Claude Code session. Events only appear when Claude Code is actively running with hooks installed. Start a conversation and send a prompt — you should see events within 1–2 seconds.

WebSocket keeps disconnecting

Symptoms: The connection dot flashes between green and red. Events appear intermittently or the dashboard shows a reconnecting message.

Possible causes:

Token costs show $0.00

Symptoms: Session cost chips in the nav bar and session headers show $0.00 even though Claude Code is being used.

Requirements for cost tracking:

Security tab is empty

Symptoms: The Security tab shows no events or chains.

This is normal if no security-relevant events have occurred. The Security tab only shows:

Run a Claude Code session that involves Bash commands with network activity, file writes to sensitive paths, or credential operations to see security events appear.

Insights show “pending” forever

Symptoms: The Insights tab shows session cards stuck in a “pending” or “analyzing” state that never complete.

Requirements:

Debugging:

Server won’t start

Symptoms: npm start or node start.js fails with an error.

Common causes:

Events appear duplicated

Symptoms: The same event appears twice in the timeline.

The dedup system uses a fingerprint of session_id|agent_id|hook_event_name|tool_use_id|tool_name|prompt[:40] with a 2-second window. Duplicate events within this window are automatically suppressed.

Events that appear duplicated may be legitimately distinct:

If true duplicates persist, verify that only one hook command is registered per event type in settings.json. When upgrading from v1.0.x, ensure no legacy send-event.py entries remain alongside the new send-event.js entries — the installer's upgrade flow strips them, but manual config files may still have both.

Windows-Specific Issues

node not found on Git Bash PATH (nvm-windows / Volta / fnm): Claude Code on Windows runs hook commands through Git Bash, which sometimes doesn't share PATH with the shell that installed Agent Recon. The installer probes for node --version at install time and falls back to the absolute path of the current Node runtime when the probe fails. If you switch Node versions after installing Agent Recon, re-run agent-recon install (or setup.ps1) to refresh the hook command.

ExecutionPolicy blocks npm scripts: The default Restricted policy prevents npm.ps1 from running. Fix:

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

Node.js blocked by Windows Firewall: Windows Defender blocks inbound connections to node.exe on dynamic ports. Allow access for private networks when prompted, or create a manual firewall rule in Windows Security → Firewall & network protection → Allow an app through firewall.

PATH not updated after installing prerequisites: Tools installed via winget or standalone installers add to PATH, but existing terminal sessions may not see the change. Close and reopen your terminal, or start a new PowerShell window.

Installation order matters: Install Claude Code first and run it at least once (to create ~/.claude/settings.json). Then install Agent Recon. The installer merges hooks into the existing settings file.

EACCES on global install

If sudo npm install -g agent-recon was used and the server crashes with:

Error: EACCES: permission denied, mkdir '...data'

The data directory resolved to a root-owned location (/usr/lib/node_modules/agent-recon/data/). As of v1.0.3, the server uses platform-specific user-writable directories:

PlatformDefault path
Linux / WSL~/.config/agent-recon/data/
macOS~/Library/Application Support/agent-recon/data/
Windows%APPDATA%\agent-recon\data\

Upgrade to v1.0.3+ to resolve. As a workaround, set AGENT_RECON_DATA_DIR:

AGENT_RECON_DATA_DIR=~/.config/agent-recon/data agent-recon start

Credential storage on headless Linux / SSH

On headless Linux servers or SSH sessions, libsecret requires a D-Bus session and unlocked keyring, which are typically unavailable. The server falls back to PBKDF2 file-based encryption automatically.

If you see credential-related errors, set a master key explicitly:

export AGENT_RECON_MASTER_KEY=$(openssl rand -hex 32)
agent-recon start

Store the key securely — it is needed to decrypt any previously encrypted API keys.

Session labels show hex instead of project name

Symptoms: Session labels display as session:a3f7 instead of myproject:a3f7.

Session labels are generated by resolving the project name in this priority order:

  1. Git remote repository name (from git remote get-url origin in the session’s cwd)
  2. project_name field from the first event payload
  3. Last component of cwd from the first event payload
  4. Fallback: "session"

If labels show session:xxxx, it means the working directory is not a git repository or the git remote is not configured. This is cosmetic only and does not affect functionality.


Developer / Support Section

For maintainers and support engineers debugging deeper issues.

Diagnostic Endpoints

The server exposes several diagnostic endpoints (no authentication, localhost only):

EndpointDescription
GET /healthReturns {"status":"ok"} when server is running
GET /diagUptime, memory usage, event counts by env, session count, cache size
GET /api/db/statsDatabase statistics: event count, session count, DB file size, schema version
GET /api/settingsAll settings (sensitive values redacted to {configured, prefix})
GET /api/versionServer version from package.json
GET /api/tokensPer-session token summaries
GET /api/tokens/periodToday and month cost aggregates
GET /api/licenseCurrent license tier and feature availability

Database Inspection

Direct SQLite inspection for debugging:

# Open the database
sqlite3 data/agent-recon.db

# Check schema version
PRAGMA user_version;

# List tables
.tables

# View full schema for a table
.schema events

# Recent events
SELECT id, session_id, hook_event, tool_name, received_at
FROM events ORDER BY received_at DESC LIMIT 20;

# Session labels
SELECT session_id, session_label, history_status
FROM sessions ORDER BY last_seen DESC LIMIT 10;

# Settings (with encrypted values masked)
SELECT key,
  CASE WHEN value LIKE '$ENC$%' THEN '<encrypted>'
       ELSE substr(value, 1, 50)
  END AS value
FROM settings;

# Security chains
SELECT chain_id, session_id, risk_level, is_final, chain_type
FROM security_chains ORDER BY created_at DESC LIMIT 10;

# LLM analysis costs
SELECT module, model, SUM(input_tokens) as total_in,
  SUM(output_tokens) as total_out, SUM(cost_usd) as total_cost
FROM llm_analysis_usage GROUP BY module, model;

Hook Verification

Verify that hooks are correctly installed and forwarding events:

  1. Check settings.json:
    node -e "console.log(JSON.stringify(JSON.parse(require('fs').readFileSync(require('os').homedir() + '/.claude/settings.json','utf8')), null, 2))"

    Confirm all 24 hook events are listed with the correct path to send-event.js.

  2. Test the hook script manually:
    echo '{"session_id":"test","hook_event_name":"UserPromptSubmit","prompt":"hello"}' | \
      node ~/.claude/hooks/send-event.js

    Check the server terminal for the received event.

  3. Verify hook script matches source:
    sha256sum ~/.claude/hooks/send-event.js
    sha256sum /path/to/agent-recon/.claude/hooks/send-event.js

    If hashes differ, re-run the setup script.

Common Development Issues

NTFS path performance for SQLite

SQLite on NTFS/DrvFs (Windows drives mounted in WSL) is significantly slower than on ext4. Additionally, WAL mode is not supported on DrvFs because mmap is unavailable. start.js detects this and automatically migrates the database to a WSL-native path.

For manual override, set DB_PATH to a WSL-native location:

DB_PATH=/home/user/.agent-recon/agent-recon.db npm start

LF line endings required

The Node.js hook script (send-event.js) and bash setup scripts (.sh) must have LF line endings. CRLF breaks the #!/usr/bin/env node shebang line on Unix and bash set -euo pipefail. If hooks fail silently after editing on Windows, check line endings:

file ~/.claude/hooks/send-event.js
# Should show: Node.js script executable, ASCII text
# Bad: Node.js script executable, ASCII text, with CRLF line terminators

build.js function-form replacement

The build system uses replace('{{JS}}', () => js) with a function argument, not a string. This is because the JavaScript source contains $&, $', and similar sequences that would be interpreted as replacement patterns with string form. Never change this — it will cause silent corruption of the built SPA.

start.js binary swap for cross-platform development

When switching between Windows/WSL/macOS terminals, start.js automatically detects better-sqlite3 binary mismatches and triggers npm rebuild. The old binary is renamed (not deleted) because NTFS may lock the file. This means you may see files like better_sqlite3.node.win32 or better_sqlite3.node.linux in the build directory — these are safe to ignore.

Debug Mode

Enable verbose logging by setting environment variables before starting the server:

# Show all DB queries
DEBUG=db npm start

# Show LLM API calls
DEBUG=llm npm start

# Show WebSocket message details
DEBUG=ws npm start

# Multiple debug channels
DEBUG=db,llm,ws npm start

Log Locations

Agent Recon does not write log files by default. All output goes to stdout/stderr of the server process:

Process Monitor Debugging

The process monitor (process-monitor.js) uses different mechanisms per platform:

If the process monitor is causing issues, disable it in Settings (process_monitor_enabled = false).

OTEL Export Issues

If events are not reaching your OTEL collector:

  1. Verify otel_enabled is 'true' in Settings.
  2. Check the otel_endpoint URL is correct (default: http://localhost:4318).
  3. For authenticated collectors, verify otel_auth_type and credentials are set correctly.
  4. Check the server terminal for OTLP export errors.
  5. Verify the collector accepts OTLP/HTTP (JSON) on the configured endpoint.

TLS / HTTPS Issues

mkcert not found

The server reports “mkcert is not installed” when attempting TLS setup. Install mkcert for your platform (brew install mkcert on macOS, choco install mkcert on Windows, apt install mkcert on Linux/WSL), then run mkcert -install to create and trust the root CA.

Elevation required

mkcert -install needs admin/sudo privileges to install the root CA into the system trust store. On macOS you will be prompted by Keychain Access. On Linux run sudo mkcert -install. On Windows run the terminal as Administrator.

Certificate expired

The server auto-regenerates certificates within 30 days of expiry on startup. If the certificate has already expired, restart the server or run npx agent-recon tls setup to regenerate immediately.

WSL trust store

If browsers do not trust the certificate on WSL, ensure mkcert -install was run from WSL (not native Windows). mkcert uses Windows interop to install the CA into the Windows trust store, which is required for Windows-side browsers to accept the certificate.

Custom cert errors

“ENOENT” or “unable to read” errors when using custom certificates. Verify that the cert and key paths are absolute and that the files are PEM-encoded. Check file permissions to ensure the Node process can read them.

Port conflict on 3132

HTTPS defaults to port 3132. If another process is using that port, change it via the tls_https_port setting in Settings, or set TLS_PORT=<port> as an environment variable before starting the server.

Telemetry Heartbeat

The server sends an optional privacy-respecting heartbeat containing only: { install_id, version, platform, timestamp }. No PII, session content, or API keys.

To disable: set telemetry_enabled to 'false' in Settings. To verify status: GET /api/telemetry/status (not authenticated).