Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents115
  3. Inbox & Notifications59
  4. Projects & Tasks95
  5. Automation & Scheduling75
  6. Knowledge & Memory26
  7. AI Features60
  8. Integrations100
  9. Plugins & Marketplace33
  10. Cloud & Teams56
  11. Settings & Customization58
  12. Account & Billing28
  13. Troubleshooting84
  14. CLI & API Reference22
  15. Legal & Policies4
  16. Uncategorised22

Logs & Debugging (where to find logs, export for support)

Where Omniscio's diagnostic output actually lives — the authoritative rotating log files and their archive, a separate bootstrap log for the earliest startup moments, and how far back the archive realistically reaches. Covers reading them, exporting a bundle for support, and the automatic crash reporting.

What it is

Omniscio writes four kinds of diagnostic output, each in a different place. You usually only need the first one:

  1. Log files on disk — the authoritative record. main.log (current) plus at least eighteen rotated backups (main.log.1 → main.log.18), each capped at 10 MB — the ring grows past that, up to 144 backups, to protect a 24-hour minimum of history under a 1.44 GB archive ceiling. Backups older than 30 days are auto-deleted on startup. A separate bootstrap.log captures the earliest startup moments with raw fs writes, so you still get a trace even if electron-log itself fails to initialize.

    How far back the archive actually reaches depends on how busy the app is, because the ring is primarily a file count (18), with a 24-hour time floor that can grow it up to 144 files on a busy machine. Every launch measures the real span and writes it to the log — [log-retention] archive holds NNh of history — and warns when it drops below 72 hours, the point where an incident reported a few days later would have no log left. If you see that warning and you need a longer window, raise MAX_BACKUPS in src/main/services/logging/log-rotation.ts.

  2. Debug Log Viewer — a live in-app console that shows a rolling window of the most recent ~2000 log lines from both the main and renderer processes, with filtering, level pills, time-period buttons, and one-click copy.

  3. Crash dumps — native minidump files (.dmp/.txt/.json) written automatically when the GPU or renderer process crashes at a level regular JavaScript logs can't capture (segfaults, access violations). They live in their own folder.

  4. Extra renderer diagnostics — optional verbose [scroll:*], [session:select], [session:nav], [mobile-perf] lines that can be switched on via a localStorage flag when you're deep-debugging a UI bug.

Where to find it

The log files are in the Omniscio logs folder on your machine — on Windows under %APPDATA%/omniscio/logs/. The in-app way to reach them, and to produce a bundle to send on, is Settings → Diagnostics, which also exposes the export-for-support action.

How it behaves

How to use it

The easy path (for support): Settings → Diagnostics

  1. Open Settings → Diagnostics. You'll see up to four cards: Log Level, Log Files, Crash Dumps (only if crashes have occurred), and Actions.
  2. Open Logs Folder reveals main.log in Explorer so you can open it in any text editor.
  3. Export Logs zips every log file into a dated archive (omniscio-logs-YYYY-MM-DD.zip) at a location you pick — this is the file to attach to a bug report. Crash dumps are deliberately NOT in it: a dump can embed a memory snapshot, absolute paths and prompt fragments, and this ZIP leaves the device. Attach one by hand from Open Crash Dumps Folder if a specific crash needs it.
  4. Log Level switches between Error / Warning / Info (recommended default) / Verbose / Debug. Bump it up to Verbose or Debug before reproducing a bug, then switch back so files don't fill up.
  5. Open Crash Dumps Folder (only shown when at least one dump exists) takes you to the minidumps. This button is the ONLY way to get one — they are not in the Export Logs ZIP (see above).

Reporting a wrong or missing agent reply: attach the conversation transcript

Logs tell you what the app DID. For "the agent's answer is missing / wrong / cut off", the evidence you actually need is what the agent wrote — and the screen is exactly what you cannot trust in that situation.

So the feedback dialog (the bug icon in the header) offers a tick-box, "Include this conversation's transcript", whenever you have a conversation open. Ticking it attaches the open conversation as a .md file, which then shows up as a normal removable attachment chip so you can see what you are sending before you send it.

It is off unless you tick it, and the choice does not carry over to your next report. A transcript is the most sensitive thing this app holds, so it never rides along unasked — and when it does, it is scrubbed exactly like the message before it leaves your computer: pasted keys, tokens, file paths and contact details are masked.

Why it is the right evidence: the transcript is built from the stored message text and does NOT pass through the display logic that folds tool activity and collapses the region before an agent's final-answer marker. It therefore shows what the agent wrote even when the screen hid part of it — the one artifact that can settle a "your reply is not there" report. (Same builder as Export Conversation in the session menu and the GET /session/:id/export CLI route, so all three produce an identical file. Exporting conversation content is privacy-adjacent and is always recorded in the audit log, this path included.)

Too big to attach (more than about 6 MB, or more than the room the report's other attachments leave) is reported as such rather than silently trimmed — a truncated transcript is worse than none, because it reads as the whole conversation. Use Export Conversation and send the file separately in that case.

Which code is actually running: Settings -> Diagnostics -> Running build

The version number tells you which RELEASE you have. It cannot tell you which COMMIT is running, and on a development install those two drift apart constantly - the app keeps running whatever was compiled the last time it started, while the checkout moves on beneath it. A fix can be merged, be sitting right there in the source, and still not be in the app you are using.

Settings -> Diagnostics -> Running build answers that directly. It shows three things:

Row What it means
Branch The branch this bundle was built from
Commit The short commit id - the exact code you are running
Built When that build was made

Each row reads Unknown when the build carries no git identity (a release tarball, a checkout with no .git, a build made outside the normal path). Unknown is a real answer, not a failure: it means the app genuinely cannot tell you, and it is deliberately never rendered as blank or as anything you could mistake for being up to date.

The same three values ride along in every bug report's diagnostics, so a report can be answered without asking the reporter to go and look. That is the point: before this, establishing which code produced a report meant reading a log file or querying the database.

When to reach for it: any time behaviour looks like an older version of the app - a fix that is definitely merged but is not showing up, an instruction or prompt that reads like it predates a change, a setting that behaves the way it used to. Compare the commit here against what you expect; if it is behind, the app needs a rebuild and restart, not a bug report.

The live view: Debug Logs toolbar button

  1. Click Debug Logs (terminal icon) in the toolbar. If it's not pinned, open the toolbar overflow (⋯) and either pin it or launch it from there each time.
  2. The viewer shows both main-process and renderer-process lines as they happen — useful for watching a bug reproduce in real time. Time buttons (30s / 1m / 5m / 15m / All) filter the window, level pills (error/warn/info/verbose/debug) toggle visibility, and the Dedup button collapses consecutive identical lines into a single row with a count.
  3. Copy puts the currently visible entries on the clipboard. Clear wipes the viewer only — the file on disk is untouched.
  4. Close with Esc or the × button.

The nuclear option: extra scroll/session logs

The renderer has three logging modes for scroll and selection events, toggled in the DevTools console:

localStorage.setItem('mc:log:scroll', 'verbose')   // every call
localStorage.setItem('mc:log:scroll', 'dedup')     // default — dedups per session+tag, suppresses hidden containers
localStorage.setItem('mc:log:scroll', 'silent')    // off

Reload the app after setting. Only useful when debugging scroll-positioning or session-navigation issues.

Where the files actually live

  • Log folder: %APPDATA%/omniscio/logs/ on Windows (or the equivalent userData folder on macOS/Linux). The Log Files card in Settings → Diagnostics always shows the resolved path.
  • Crash dumps: Electron's default crashDumps path (a sibling of the log folder inside the same userData directory).
  • E2E isolation: when AMC_INSTANCE_ID=e2e is set, everything lives under omniscio-e2e instead — lets npm run test:e2e:prod run alongside a live dev session with zero shared state.

Automatic crash reporting (auto-send-every-crash)

Separately from the on-disk logs above, Omniscio automatically sends a crash report whenever the app dies — by email (to the developer's address via Resend) and to Sentry. You don't have to export anything or file a bug; a crash reaches the developer on its own. This is deliberately broad about what counts as a "crash":

  • Live JavaScript errors — an unhandled exception or promise rejection while the app is running.
  • Hard native crashes: segfaults, out-of-memory kills, or heap corruption that bypass all JavaScript error handling. Sentry receives a short text report naming the process that crashed, never the memory dump itself, which stays on this computer because it can hold passwords and message text; the email channel gets a short note pointing at the local dump file (the binary itself can be megabytes, so it isn't emailed).
  • Silent deaths — the app is force-killed (Task Manager, OS, power loss) and never gets to run another line of code. Nothing can email at the moment of death, so Omniscio detects these on the next launch (see "heartbeat sentinel" below) and reports them retroactively.
  • Startup failures — a crash while the app is still loading its own code, before any of the safety nets above exist. Omniscio writes a tiny "starting up" marker as the very first thing it does; if that marker is still there at the next launch, the previous startup died early, and the failure is reported then.
  • A blank window at startup — the window opens but never shows the app (a display or data-loading failure). The main app process notices the window never became usable — even though the blank window itself can't report anything — and sends the report.

Also, if your machine is offline when a crash happens, the report can't leave right then; Omniscio saves it and sends it automatically the next time the app starts with a working connection (still capped at the daily limit below).

Always on, independent of telemetry

Crash reporting is not the same setting as telemetry. The optional telemetry opt-in controls only the weekly usage digest and Sentry breadcrumbs. Crash auto-send is on by default and keeps working even with telemetry off — the reasoning is that crashes are rare, and a silently-dropped crash is worse than a slightly noisier inbox.

Watching crash volume: the crash-free-session-rate

The reports above tell you that a crash happened; to answer how often — the number the public-beta "watch crash volume" step and the 1.0 release bar ("crash rate below X% of sessions") are judged against — read the crash-free-session-rate in Sentry Release Health. Omniscio's Sentry SDK counts one "session" per app run and marks it healthy or crashed, so Sentry computes crash-free-session-rate for you — no separate dashboard to build, nothing to divide by hand. To read it: open the Sentry project → Releases (or Release Health), filter to environment production and the release omniscio@<version> you're evaluating; the crash-free-sessions % is the crash-rate bar. Filtering to production matters — dev runs report under development and shouldn't count toward the release bar.

This is on automatically (it rides the same always-on Sentry init as crash capture) and is content-blind: a session carries only a healthy/crashed status and the release/environment tags — no message, stack, or IP. Automated test/sandbox launches don't pollute it because they suppress Sentry entirely (AMC_DISABLE_TELEMETRY / AMC_INSTANCE_ID). For repo-access readers: it's the SDK's default mainProcessSessionIntegration, kept on (and locked by a guard test) in /src/main/services/sentry-init.ts; the invariant + the measurement caveats are I28 in the crash-reporting contract.

Privacy

Before any crash report leaves the machine, Omniscio scrubs it. Secrets and paths are stripped — Anthropic API keys, Bearer/JWT tokens, OAuth access/refresh fields, and your Windows/Unix home-directory path — and so is contact PII: email addresses, phone numbers, and non-loopback IP addresses are masked ([EMAIL_REDACTED], [PHONE_REDACTED], [IP_REDACTED]). The scrub runs over the error message, stack trace, and every attached log/crash file. It is deliberately targeted at those shapes so it never mangles stack traces, file paths, or error fingerprints. Your OS username is no longer included. (Your machine's hostname is intentionally kept, so reports can be told apart across machines.)

For the Node diagnostic report specifically — a native-crash artifact that bundles your entire process environment — Omniscio goes further than the pattern scrub: it removes the whole environment-variables block before sending, wholesale and name-independent, so even an oddly-named custom key can't slip past the matcher. And if that report is itself corrupted or truncated (so the block can't be cleanly removed), it's withheld entirely rather than sent through the weaker pattern scrub — the crash is still reported, just without the unparseable attachment.

How to turn it off

Three switches, in order of bluntness:

  1. Settings toggle — Crash auto-send under Settings → System. Turning it off stops crash emails entirely (default is on).
  2. Crash hard kill-switch env var — launch with AMC_DISABLE_CRASH_AUTOSEND=1. This wins over the setting and additionally prevents the Sentry SDK from loading at all. It exists for automated test suites and incident-response windows that deliberately crash the app and must not spam reports.
  3. Master telemetry kill-switch env var — launch with AMC_DISABLE_TELEMETRY=1. This is the broadest off switch: one flag silences the ENTIRE phone-home stack — crash auto-send AND Sentry (main + renderer) AND the fleet-telemetry / weekly-digest / error-tail pipeline — by forcing every telemetry-gated check off. It is the isTelemetrySuppressed() master gate that both getCrashAutoSendEnabled() and getTelemetryEnabled() compose, so it wins over the two switches above. The E2E / cloud / CI launch fixtures set it so test boots never report; a real user MAY set it to opt out of everything at once. (A non-empty AMC_INSTANCE_ID — sandbox / e2e / throwaway instances — triggers the same suppression.)

There is also a built-in daily cap (15 crash emails per calendar day) that survives restarts, so an app stuck in a crash-restart loop can't flood the inbox. A matching guard protects the Sentry side: each distinct error is capped to a set number of events per rolling day (on top of a coarser per-minute limit), so one looping error can't quietly drain the shared monthly Sentry event quota and blind crash monitoring for everyone — the first several of every distinct error still send, so a genuinely new bug always gets through.

The heartbeat sentinel (how silent deaths are caught)

While running, Omniscio rewrites a tiny heartbeat-sentinel.json file in the logs folder every 5 seconds and deletes it on a clean shutdown. If that file is still present at the next launch, the previous run must have died without shutting down cleanly — a silent death. A boot-time sweep (sweepCrashEvidence) finds the leftover sentinel (plus any native crash dumps and Node diagnostic reports), forwards each as a crash report, and marks them so they're never re-sent. The sentinel carries the prior process's PID, uptime, the last operation it was performing, and a short tail of health ticks — enough to answer "was it healthy right before it vanished, and what was it doing?" It also records the launcher that started the app (its PID, name, and start time); on the next launch the sweep compares that against the new process's launcher, so a silent death of an otherwise-healthy app now also says who killed it — the same launcher respawning the app (the signature of a dev-server / electron-vite hot-reload restart) versus a different or absent one (an external kill). That verdict is included in the crash report. The report also says whether the app was still killing something when it died: Omniscio records every process tree-kill it dispatches, and clears the record once that kill finishes, so a record still on disk at the next launch means a kill was in flight when the process vanished. When the target was the app's own process ID — or the process that launched it — the report names it as a self-kill, because a Windows tree-kill carries /T and takes the target's whole subtree down with it, the app included. When nothing was in flight the report says so as evidence only, never as proof that nothing outside ended the process.

How it works (for repo-access readers)

The send path is reportCrash() in /src/main/services/telemetry/telemetry-reporter.ts, gated by getCrashAutoSendEnabled() in /src/main/services/config-store/accessors-settings.ts (env check first, then the crashAutoSendEnabled setting defaulting on). Sentry init is /src/main/services/sentry-init.ts. The boot sweep is /src/main/services/diagnostics/crash-evidence-sweeper.ts; the sentinel is written by /src/main/services/diagnostics/main-heartbeat.ts. The ledger behind the self-kill verdict is /scripts/lib/process-terminations-ledger.mjs, written from the single tree-kill dispatch point in /src/main/process/child-kill.ts. The exhaustive invariants (the telemetry asymmetry, the sentinel-ownership race fix, idempotency, the boot wiring order) live in the feature contract: /.claude/memory/contracts/crash-reporting-contract.md.

For agents

How it works

Logging is centralized in /src/main/services/logger.ts, which re-exports a configured electron-log instance. Setup happens at startup in /src/main/index.ts via setupLogging(): level is resolved as env LOG_LEVEL > persisted logLevel setting > default (verbose in dev, info in prod). Then configureFileRotation() caps each file at 10 MB and rotates via numbered suffixes (.1 newest, .5 oldest); older files are deleted in cleanupOldLogBackups() on the next startup (deferred via setImmediate to avoid blocking window creation while Windows antivirus scans the directory). A separate writeBootstrapLog() raw-fs appender writes bootstrap.log before electron-log is ready so a very-early startup crash still leaves a trace.

installDebugLogTransport() pushes every file-transport log entry into a 2000-entry O(1) circular ring buffer and emits an IPC.DEBUG_LOG push event so the DebugLogViewer gets real-time updates. On mount, the viewer calls IPC.LOGS_GET_BUFFER to replay history (de-duped against any push events already received), and also monkey-patches console.* methods in the renderer so those lines flow into the same viewer tagged source=renderer. Two guards prevent duplication: renderer console is not pushed back up to the main-process file to avoid a loop, and _debugHookInstalled prevents hook stacking during HMR reloads.

The Settings → Diagnostics UI is /src/renderer/src/features/settings/sections/diagnostics/DiagnosticsSettings.tsx, backed by the IPC handlers in /src/main/ipc/log-handlers.ts: LOGS_OPEN_FOLDER (uses shell.showItemInFolder), LOGS_EXPORT (async archiver ZIP including a crash-dumps/ subfolder), LOGS_GET_INFO (directory + file list + sizes), LOGS_GET_BUFFER (ring buffer snapshot), CRASH_DUMPS_GET_INFO, and CRASH_DUMPS_OPEN_FOLDER. Settings search indexes all four log-related setting IDs (log-level, log-files, export-logs, crash-dumps) in /src/renderer/src/features/settings/settings-search-index.ts, so Ctrl+, then typing "log" finds them.

Full internal reference for log levels, rotation rules, error notification coverage, and renderer diagnostic prefixes: /.claude/memory/observability.md.

Related

Last verified 2026-10-06