ContextDock (Native) — local-first library (in development)
The native ContextDock: a local-first rebuild of the document library that reads Omniscio's own store rather than a remote service, with panes for documents, bundles, lists, tags and assembling a context payload. Covers adding documents and files of any type, editing bundles and lists, the one-time cloud import, and what stays deferred.
What it is
Status: in-development — default-hidden. Gated via the contextdock-native
unreleased-feature entry (contextdockNativeEnabled toggle in Settings → Lab, or
launch with AMC_SHOW_CONTEXTDOCK_NATIVE=1). Ships dark until flipped to shipped
in src/shared/unreleased-features.ts.
The native ContextDock is a local-first rebuild of the ContextDock library UI that
reads Omniscio's own authoritative store — documents, bundles, lists, tags, and
on-demand context assembly — rather than the separate ContextDock web app. It is
distinct from the vendored ContextDock integration (__contextdock__,
which links bundles/lists snapshotted from the remote CLI); the native surface owns its
data end-to-end over the local contextdock-store:* IPC.
It adds a "ContextDock (Native)" sidebar virtual project (sentinel
__contextdock_native__, nested in the Productivity group). Its panel
(ContextDockNativeView) is NON-spawnable — it hosts no Claude session. Tab navigation
lives in a sub-sidebar (ContextDockNativeSubSidebar) with five panes:
- Library — browse, open, add, and edit documents: the "Add docs" button opens the import dialog (see Adding documents), an "Add files" button + drag-and-drop imports any local file type (text/office/pdf + image OCR + audio/video transcription), and the detail panel edits a selected doc (per-doc delete / retag / re-summarize — see Editing a doc).
- Bundles — hand-curated collections of docs (create / rename / add-remove docs / reorder docs / pin / delete / duplicate, with a per-doc content-version override).
- Lists — tag-driven views over the docs (create / rename / manage driving tags + any-all match / add-remove-reorder extra docs / pin / delete / duplicate, with persisted per-doc content-version overrides).
- Tags — manage the tag roster.
- Export — assemble a selection into one context payload and copy / download it.
Where to find it
It appears as its own ContextDock (Native) row in the sidebar, nested under the Productivity group, and its panel fills the pane with a five-pane sub-sidebar for Library, Bundles, Lists, Tags and Export. Because it is still in development it ships hidden: you have to switch it on from the Labs area of Settings before the row shows up, and until then it is simply not there.
How it behaves
Adding documents (the "Add docs" dialog)
The Library's Add docs button opens ContextDockNativeAddDocsDialog — the ongoing
import surface (distinct from the one-time cloud migration below), matching the original
ContextDock site's import loop. One dialog, four modes via a SegmentedControl:
- Paste URL(s) — one Google Doc URL imports it (multi-tab docs auto-flatten server-side); multiple URLs bulk-import with an imported / updated / skipped / failed summary.
- Google Drive folder — paste a folder URL, Browse lists its Google Docs, pick a subset, import.
- Manual — a title + markdown → a local doc.
- Upload — a
.md/.txt/.pdf/.doc(x)file → its extracted text (read to base64 in the renderer, size-guarded viaMAX_UPLOAD_BYTES).
Optional tags apply across every mode; Ctrl/Cmd+Enter submits. Errors are humanized (a
not-connected Google account shows a "connect it in Settings" toast, never a raw error).
The dialog drives the Stage-3 import backend through useContextDockStoreImport over six
contextdock-store: import channels (import-url, bulk-import-urls, list-folder,
import-folder, create-manual, upload-file) — typed in the response-map,
native-flag-gated, and WS-blocked. After a successful import the handlers emit
contextdock-store:changed {resource:'docs'} (ONLY when a doc was actually written), so
the Library refetches on its own. The five import COMMAND channels are cli-parity
deferred-no-route; the reads (list-folder / preview-url / discover-tabs) stay out
of scope.
Deferred (backend ready, not yet UI-wired): selective per-tab import
(discover-tabs / import-tabs) and the dry-run preview-url — import-url already
auto-flattens multi-tab, the source product's default. Post-import doc editing
(delete / retag / private-toggle / manual re-condense) and background auto-sync also stay
deferred; the Library rows themselves are still read-only.
Files: ContextDockNativeAddDocsDialog.tsx, useContextDockStoreImport.ts,
add-docs-helpers.ts, wired from LibraryPane.tsx.
Editing bundles and lists
Both panes are fully editable and reach parity with the original ContextDock's bundle/list
management, reusing the upsert-bundle / upsert-list channels (no dedicated edit channel):
- Pin / unpin — an inline pin toggle sits on each list row and its detail header (the same affordance bundles already have); pinned items sort to the top of their roster.
- Reorder docs — move-up / move-down controls order a bundle's member docs and a list's
extra docs (a list's tag-matched docs are a live query, so only the explicit extras reorder).
Order is stored in the
docIdsarray and drives the assembled output order. Backed by the puremoveInArrayhelper (reorder.ts). - Per-doc version override — pick Original / Key Points / Summary per doc. Bundles and lists
both PERSIST this now (a
doc_versions_jsoncolumn on each table); the choice survives a reload and feeds the context assembler. (Previously a list's choice was renderer-local and lost on refresh.)
Every edit rides saveList / saveBundle (humanized errors, no optimistic mutation) and the
contextdock-store:changed push refetches the affected pane. New controls carry data-ui-anchor
entries in the co-located *.ui-anchors.ts. Files: ListsPane.tsx, BundlesPane.tsx, reorder.ts.
Editing a doc
The Library's detail panel (LibraryDocDetail) makes a selected doc editable with three per-doc actions:
- Delete — a confirm dialog, then a soft-delete (
softDeleteContextDockStoreDoc); the doc drops out of the Library (every read filtersis_deleted=0, so it also disappears from any bundle/list automatically) and the selection clears. - Edit tags — toggle chips over the workspace tags; toggling patches
updateContextDockStoreDoc {tags}(doc tags are stored as NAMES). Tag filtering updates live. - Re-summarize —
requestCondense([id], {force:true})+ a queue drain, re-running the AI condensing (keyPoints / summary / aiSummary) on the user's own Claude credential (bypasses smart-skip + the auto-condense toggle). If no API-key account is connected the sweep no-ops; the button shows a "re-summarizing" state, never a faked completion.
These ride three contextdock-store: channels — delete-doc, update-doc, recondense-doc — through
useContextDockStoreDocActions (humanized errors, no optimistic mutation). Each emits
contextdock-store:changed {resource:'docs'}; the condense write-back now emits it too (after its transaction), so
a finished re-summary shows live. The detail panel re-loads the doc on that push (useIpcListener). The three write
channels are native-flag-gated, WS-blocked, and cli-parity deferred-no-route. Files:
useContextDockStoreDocActions.ts, LibraryDocDetail.tsx.
Importing your ContextDock cloud library (opt-in, Stage-5 cutover)
If you previously used the vendored (cloud) ContextDock, the Library tab shows an opt-in
"Import your ContextDock cloud library" card — but ONLY when a vendored ContextDock
API key still exists (getApiKey() in the vendored auth.ts). Clicking it confirms
first (the import spends your ContextDock cloud API quota), then reuses that key to pull
your cloud documents, bundles, lists and tags into the local store via the one-time
importer (runContextDockStoreMigration).
The importer is idempotent, resumable, and paced (400 ms/doc), so re-running is safe
and an interrupted run continues from where it left off — a very large library (>~1500
docs) that exceeds the IPC handler's abandon ceiling simply resumes on the next "Import".
A single migration runs at a time (a main-process single-flight guard refuses a concurrent
run). The vendored API key is read + used entirely in the main process; only its presence
(a boolean) ever crosses IPC. Once a run completes, the card collapses to a quiet
"imported" summary with a Re-import affordance. Wired in
src/main/services/contextdock/store-migration-trigger.ts +
src/main/ipc/contextdock-store-migration-handlers.ts; the card lives in
src/renderer/src/features/contextdock-native/MigrationCard.tsx.
Adding files (any file type)
The Library's "Add files" button (ContextDockUploadButton) imports local files as context docs —
any file type:
- Text, code, and data (
.md,.py,.json,.yaml,.csv,.html, notebooks, logs, config, or any file whose bytes are text) — decoded and imported immediately. The extension is only a hint; a byte-sniff decides, so an extension-less or mislabeled text file still imports and a true binary is rejected with a clear message. - Office + PDF (
.docx,.pptx,.xlsx,.pdf, …) — extracted to markdown. - Images (
.png,.jpg,.gif,.webp) — read with Claude vision (OCR + a short description). This costs about a cent per image on your Claude credit and sends the image to Claude; uploading a large batch confirms first. Audio, video, and text stay free and on-device. - Audio + video (
.mp3,.mp4,.mov,.wav, …) — transcribed on-device with Whisper (free, private). Needs system ffmpeg (install from Settings → Connected Tools if missing).
Images and audio/video process in the background: the doc appears immediately as "⏳ Processing…" and
fills in with the OCR text or transcript when ready (a contextdock-store:changed push refreshes the
row). You can also drag files straight onto the Library. Large media is streamed by file path (not
loaded into memory), and a transcription interrupted by an app restart is recovered on the next launch.
All of this reuses existing Omniscio building blocks — no new dependencies.
Availability
Desktop-only. The contextdock-store:* reads and writes are blocked on the
mobile/web WS bridge (desktop-blocked until cutover), so the row + panel are dropped in
Web Access / mobile mode and the surface declares mobile: desktop-only.
For agents
Data + IPC
The store is backed locally and read/written over the contextdock-store:* channel
family: reads (list-docs, get-doc, list-bundles, list-lists, list-tags,
assemble) and read-modify-write mutations (upsert-bundle / delete-bundle,
upsert-list / delete-list, upsert-tag / delete-tag), each of which emits a
scoped contextdock-store:changed push so the pane hooks refetch only the affected
resource. Every handler is gated by the native-ContextDock feature flag.
The Stage-5 cutover adds two more: get-migration-status (a read — does a vendored
ContextDock API key exist, plus any saved import progress) and run-migration (the
command that performs the one-time cloud→local import). Both are native-flag-gated and
desktop-blocked on the WS bridge; run-migration is cli-parity deferred-no-route.
Related
The older, cloud-backed version of this same surface — bundles and lists snapshotted from a remote service rather than owned locally — is on the ContextDock page, and the two are separate sidebar rows you can tell apart by name. A different local-first library of your own material, the knowledge vault, is described on the KMS page.
Last verified 2026-09-28