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

Heap snapshot diagnostics (memory bloat investigation via CLI)

A CLI endpoint that captures a heap snapshot of the renderer, parses it, and returns a small summary of where the memory is going — the supported way to answer "Omniscio is using 2 GB of RAM, where is it going?" without opening DevTools.

What it is

POST /diagnostics/heap-snapshot is a CLI endpoint on Omniscio's local control server (port 19519) that captures a V8 heap snapshot of the renderer process, parses it, and returns a small JSON summary describing where the memory is going. It's the supported way for an agent — Claude Code, the in-app chat, an external tool reading ~/.amc/cli-token — to investigate "Omniscio is using 2 GB of RAM, where is it going?" without the user having to open DevTools.

Why this exists. Omniscio strips the Windows menu accelerators (mainWindow.removeMenu()), so Ctrl+Shift+I does not open DevTools. The standard developer workaround — launching with --remote-debugging-port — is forbidden by the project's security postmortem (it would expose an authenticated debugger socket on every Omniscio start). This endpoint lets agents drive a memory diagnosis programmatically while keeping Omniscio's debugger surface closed.

Where to find it

How to use it

Calling the endpoint

TOKEN=$(cat ~/.amc/cli-token)
curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://127.0.0.1:19519/diagnostics/heap-snapshot

A successful response looks like:

{
  "ok": true,
  "snapshotBytes": 312654321,
  "summary": {
    "totals": {
      "nodeCount": 8421337,
      "edgeCount": 31845121,
      "totalSelfSize": 2147483648
    },
    "byNodeType": [
      { "type": "string", "count": 5132904, "totalSelfSize": 1612345678 },
      { "type": "object", "count": 1842031, "totalSelfSize": 412345122 },
      { "type": "array", "count": 421873, "totalSelfSize": 98123455 }
    ],
    "topClassNames": [
      { "name": "system / Module", "count": 8123, "totalSelfSize": 142312345 },
      { "name": "HTMLDivElement", "count": 142003, "totalSelfSize": 84123887 }
    ],
    "largeStrings": {
      "count": 1247,
      "totalSize": 783451123,
      "categories": { "dataImage": 612345128, "dataOther": 41205555, "generic": 129900440 },
      "samples": [{ "size": 4823472, "preview": "data:image/png;base64,iVBORw0KGgoAAAANSU…" }]
    }
  }
}

Reading the summary

  • totals.totalSelfSize is what to compare against the OS reported renderer RSS. It's the sum of every node's self_size in bytes — close to JS-reachable memory, not counting V8 internals or native buffers.
  • byNodeType is your first triage cut. If string dominates, you're looking at retained text/base64/buffers; if object dominates, you're looking at retained DOM or app objects; if code dominates, you have many compiled functions resident (rare).
  • topClassNames (capped at 25 by totalSelfSize) names the worst object retainers. Names are pulled from the V8 strings table for non-string-type nodes — for plain objects this is the constructor name (HTMLDivElement, Map, custom classes, etc.).
  • largeStrings isolates the >1 KB string nodes and splits them into dataImage (base64-encoded data:image/...), dataOther (other data: URLs — Office docs, blobs), and generic (everything else — long JSON blobs, pasted text, agent message buffers). The 10 largest are returned as samples with truncated previews so you can sanity-check what's pinned.

Optional behavior

  • ?keep=true — the captured .heapsnapshot file is normally deleted after parsing to save disk. With keep=true, the response includes snapshotPath so you (or the user) can later open the file in DevTools' Memory panel for a deeper retention-path walk.
  • A second POST while the first is still in-flight returns 409 with error: "snapshot capture already in flight". Capture is single-flight by design — running two concurrent takeHeapSnapshot calls would double the transient memory pressure.

How it behaves

Cost and limits

  • Time: ~2–6 seconds end-to-end on a 2 GB renderer. The capture itself is fast; reading and parsing the resulting JSON file is the slow part.
  • Disk: the snapshot file is 200–500 MB for a typical renderer. It is written under <userData>/heap-snapshots/<ISO-timestamp>.heapsnapshot and deleted unless keep=true.
  • Main-process memory: parsing the JSON briefly inflates the main process by ~2–3× the snapshot size. Omniscio's main is normally ~200–400 MB resident; expect a transient spike to ~1.5 GB while parsing a 500 MB snapshot. This is acceptable for a user-triggered diagnostic but is the reason capture is single-flight and rate-limited.
  • Rate limit: shares the 19519 server's global mutation cap (10/min). Combined with single-flight, the effective cap is one capture every few seconds.
  • Auth: the full-trust ~/.amc/cli-token is required. That is stricter than /projects, /sessions and the search routes, which also answer a scoped agent-session token; a scoped token is refused here.

When to use it

  • "Omniscio's RSS is climbing past 2 GB and I want to know what's pinned." Run the endpoint, look at byNodeType first, then drill into topClassNames or largeStrings.samples based on which dominates.
  • "I think feature X retains image data after the user navigates away." Capture a snapshot before opening X, capture another after closing it, compare largeStrings.categories.dataImage and topClassNames deltas.
  • "I want to verify a memory fix actually freed memory." Capture before and after — totals.totalSelfSize and the per-class entry for the fixed component should both drop.

When NOT to use it

  • Don't poll it on a timer. Each capture costs disk + transient RAM. Use it when you have a specific question, not as a heartbeat.
  • Don't use it to inspect non-renderer processes. The endpoint snapshots mainWindow.webContents only; child processes (CLI spawns, mempalace-server) are out of scope.
  • Don't ship code that depends on the response shape long-term — the summary shape is a debug aid and may evolve as the parser learns to extract more useful signals.

Related

Last verified 2026-10-06