Add a first-run onboarding card to OK Desktop. A dismissable checklist…#411
Merged
Conversation
* docs: add Migrate section for Notion and Obsidian imports Add a Migrate section with import guides for Notion (export to Markdown and open in OpenKnowledge, with cleanup prompts) and Obsidian (open a vault in place). Move the existing Obsidian guide out of Get Started into Migrate, wire the section into the docs nav, and redirect the old /docs/get-started/obsidian URL to its new home. * docs: address review feedback on Migrate section - Restore high-value See also links on the Obsidian page (Editor, Timeline and recovery, Ignore patterns) - Fix product name (OpenKnowledge) and the GitHub sync link text and description convention on both pages - Add icon frontmatter to the Notion page - Remove the incomplete placeholder callout and add a missing table row period on the Notion page GitOrigin-RevId: 48db6e125f88e1ca70db36cbae10c9ba6eae129b
…page (#2318) * docs(open-knowledge): add "What OpenKnowledge writes to your system" page Document the full install + runtime write footprint — npm install, ok init, ok start, ok mcp, and OK Desktop — grouped by trigger and by in-project vs. outside-project scope, with the opt-outs collected in one place and the privacy posture (nothing leaves the machine by default). Cross-linked from the CLI reference and both Quickstart tabs. Verified against source: the Claude launch.json preview port is 39848 (the audit's 3000/3101 were both wrong) and embeddings API keys live in ~/.ok/secrets.yml (0600), not global.yml. Closes PRD-7234. * docs(open-knowledge): address review — ok start repair sweeps + framing - Document ok start's three per-boot repair sweeps (MCP configs incl. user-level editor configs, .claude/launch.json, skill files), which can write outside the project — previously only attributed to OK Desktop. Verified against packages/cli/src/commands/start.ts + repair-mcp-configs.ts. - Reframe the Desktop "keeping MCP entries current" note as shared with ok start, and widen the OK_RECLAIM_DISABLE opt-out row accordingly. - Clarify the desktop auto-update check is automatic (not opt-in/on-demand) in the intro callout and the egress section. - Broaden the CLI cross-link text to cover install + runtime + desktop. - Drop the temporal "today" from the page description. - Add the transparency cross-link to the Obsidian onboarding page. --------- GitOrigin-RevId: 03438df81d9ba8564707bc40884130f84cf9366c
* feat(open-knowledge): add brand assets download page + logo menu Adds a /brand page and a right-click menu on the site logo so people can grab the OpenKnowledge logo and icon (SVG + PNG) to share about us. - /brand: logo (light + dark bg) and icon tiles with per-asset SVG/PNG downloads plus a "Download all" zip, footer + sitemap links. - Right-click the site logo: copy SVG / download SVG / download PNG, and a link to the full kit. - Assets generated from the logo components (bun run generate:brand-assets): flat SVGs keeping the mark's drop-shadow, high-res transparent PNGs, zip. - MarketingButton: an explicit `download` now forces a raw <a download> (next/link dropped it), and `tertiary` honors size="sm". * fix(open-knowledge): throw on non-ok fetch when copying brand SVG fetch only rejects on network failure, so a missing/renamed asset would copy the server's error page to the clipboard. Guard on res.ok so the caller's catch falls back to the download links. * fix(open-knowledge): distinct a11y names for brand downloads + use BRAND_ROUTE - Add sr-only asset name inside each SVG/PNG download link so screen-reader users can tell the six links apart (WCAG 2.4.4). - Use the BRAND_ROUTE constant in sitemap.ts and the page canonical instead of a hardcoded /brand. * fix(open-knowledge): announce brand-logo copy to screen readers - Add an always-mounted aria-live status region so the 'Copied' confirmation in the logo context menu is announced (a text swap on the focused menu item isn't reliably announced on its own). - Correct copy-svg.ts doc comment: the logo menu is now the only consumer. --------- GitOrigin-RevId: 45d0ebd6fccb96ab1dc35f7b51faa190eca4de25
* docs(open-knowledge): add OpenClaw integration guide
Add docs/content/integrations/openclaw.mdx documenting how to connect
OpenClaw agents to an OpenKnowledge knowledge base over MCP: manual
registration (JSON block / `openclaw mcp add`), `mcp reload` + `doctor
--probe` verification, `ok init`, a copy-pasteable end-to-end smoke test,
route-only vs full preview URLs, agent working rules, and a troubleshooting
table. Add the page to the Integrations nav.
The page auto-flows into /llms.txt, /llms-full.txt, and its per-page .md
route, so the same content serves both human readers and agents.
* docs(open-knowledge): address review feedback on OpenClaw guide
OpenClaw page:
- Cross-reference the installed skill instead of restating its rules
- Consolidate the two verification sections into one (server-side probe +
agent-side prompt), with their relationship explained
- Condense the Preview section to a cross-reference (dedupes the MCP reference)
- Fold the mental-model framing into the intro; drop the standalone section
- Match the sibling description pattern ("Use OpenKnowledge with X")
- Reframe the unverified `openclaw mcp add` command as a pointer to `--help`;
the JSON config is the verified path
- Use clearer placeholder paths: /path/to/your/knowledge-base and
/Users/<your-username>/.ok/bin/ok (avoids literal-paste of /Users/you/...)
reference/mcp.mdx:
- Fix stale "17 tools" -> "19 tools" and add the missing `skills` and `install`
rows so the count and table agree with the registry and SKILL.md
Move the "Using with Obsidian" guide from Get Started to Integrations so it's
out of the first-run flow; update both section nav files.
* docs(open-knowledge): redirect the moved Obsidian docs URL
Moving "Using with Obsidian" from Get Started to Integrations orphaned
/docs/get-started/obsidian (live since #2249). Add a redirect to its new
home, matching the existing deleted-page pattern in next.config.ts — both
slash variants, since skipTrailingSlashRedirect is on.
---------
GitOrigin-RevId: a65891352c84066ab9506308f1c12faa81713769
* [US-001] add onboarding card persistence store
Module-level singleton backed by localStorage and bound to React via
useSyncExternalStore. Tracks onboarding step completion, collapse,
dismissal, and completion so card state survives remounts and reloads;
the dismissed and completed flags persist device-local so a dismissed or
finished card never returns.
Mirrors the update-notices-store module-store shape and adds localStorage
write-through (that store is in-memory only). Installed at main.tsx
module-init; SSR-safe when localStorage is unreachable.
* [US-002] add new-user visibility hook (useOnboardingCardVisible)
Host-gated, fail-safe fresh-project predicate (listRecent filtered to other
switchable projects + /api/documents entry count 0) with an activation latch so
the card persists through step completion. evaluateFreshProject resolves false
on any bridge/fetch failure (suppress rather than ambush). 7 unit + 6 DOM tests.
* [US-003] wire onboarding step-completion signals (file + Ask AI)
File step: useOnboardingFileCompletion watches the documents-changed bus and
marks the step once entry count >= 1 (with a mount-time check). Ask-AI step:
recordOnboardingAskedAi fires from BottomComposer's two successful-dispatch
paths, gated on an active onboarding session. Shared document-count fetch
extracted to onboarding-document-count.ts. 6 unit + 3 DOM tests added.
* [US-004] add OnboardingCard expanded UI (steps, shortcuts, click-to-act, dismiss)
Three-step checklist: step 1 pre-checked (endowed progress), steps 2/3 show
registry shortcuts (formatShortcutLabel) and are clickable to fire the create-file
/ open-Ask-AI actions. Completion indicator is a presentational aria-hidden
Checkbox; the actionable affordance is a real Button with a full accessible name.
Dismiss routes through store.dismiss(). Injectable store seam for tests; 5 DOM tests.
* [US-005] add collapse-to-pill and auto-closing success state
Collapse toggle persists via store.setCollapsed; collapsed renders a compact
'Setup · N of 3' pill that expands on click. Completing all three steps renders
a polite live-region success message that auto-closes after ~4s and marks the
card completed so it never returns (timer cleared on unmount; motion-safe fade).
autoCloseMs is a test seam. +2 DOM tests.
* [US-006] mount gated onboarding card in editor pane + extract i18n catalogs
OnboardingCardMount evaluates the visibility predicate and renders the card
floating bottom-left of the editor-column panel (right of the sidebar, hidden
below a narrow breakpoint); renders nothing on web/CLI. Regenerated en + pseudo
Lingui catalogs for the new card strings. +2 DOM tests for the gated mount.
* test(onboarding): assert Ask-AI step records only on successful dispatch
Closes the R5 negative-half gap from the spec-fidelity check: pins that
recordOnboardingAskedAi fires after BottomComposer's submit guards, so an
aborted submit (null compose input) leaves the Ask-AI step unchecked.
* fix(onboarding): address local review findings
Major:
- Ask-AI step now records only on a CONFIRMED-successful dispatch (gate inside
.then on outcome.ok); a failed handoff ({ok:false}) no longer checks it off —
fixes silent onboarding-completion for the exact new-user population. + tests
for success / abort / {ok:false}.
- Add changeset for the user-facing feature.
Minor:
- recordOnboardingFileStep gains the initialized guard its comment claimed (symmetry).
- console.warn breadcrumbs on the fail-safe catches (store write, listRecent/fetch, file step).
- Replace fixed-duration setTimeout waits in negative DOM tests with deterministic waitFor.
- Persistent always-rendered sr-only polite live region for the success announcement.
- Add onboarding-document-count.test.ts (kind/hidden filtering + fetch/parse).
* fix(onboarding): glyph shortcuts, non-interactive step rows, full-opacity checkbox
Per design feedback:
- Render shortcuts via the reusable Kbd component + formatShortcut (⌘ N / ⌘ L
glyphs) instead of the verbose 'Command N' label.
- Make step rows informational only (drop click-to-act) — the clickable Button
rows read as confusing; steps check off as the user performs ⌘N / ⌘L.
- Render the decorative completion checkbox at full opacity (override the
disabled dim) since it's a status glyph, not a form field.
- a11y preserved: rows convey completion via strikethrough + an sr-only marker.
* feat(onboarding): move card to sidebar footer + success toast; drop collapse/pill
Per design feedback (simplification):
- Mount the card in the sidebar footer (FileSidebar) instead of a floating overlay
in the editor pane — anchored, full-width app chrome; removes the absolute
positioning, z-index, breakpoint, and footer/composer-overlap concerns.
- Completion now fires a Sonner success toast ("You're all set up! 🎉") instead of
an in-card success state — deletes the success branch, auto-close timer, and
persistent live region (Sonner handles announcement). Toast + markCompleted are
deferred off the mount commit so the unmount can't race-drop the toast; the card
lingers ~1.5s at 3/3, then auto-closes.
- Drop the collapse-to-pill (and the store's collapsed/setCollapsed) — redundant
in the footer; simpler component + store.
* feat(onboarding): re-add collapse — card folds to its header row
In the sidebar footer the card folds to a single 'Finish setting up · N/3' header
row with an expand chevron (persisted via store.collapsed); expanding restores the
full checklist. Restores collapsed/setCollapsed on the store. Dismiss stays the
permanent opt-out; collapse is the lightweight reclaim-space escape.
* feat(onboarding): celebrate completion in-card with the blob mascot (drop toast)
The success toast popped bottom-right, disconnected from the bottom-left card.
Replace it with an in-card celebration: on completing all three steps the card
transforms into the OkBlob mascot doing a happy-eyes firework burst beside an
'all set up' message (celebrateSignal — on-brand, no new dependency, reduced-
motion-aware), lingers ~2.8s, then auto-closes. Removes the Sonner dependency
from the card and the toast-render timing workarounds. Completion is announced
to assistive tech via an sr-only live region.
* feat(onboarding): make the completion celebration last longer + keep it lively
The single 2.8s burst was easy to miss. Extend the dwell to ~5.2s and re-fire the
blob's firework every 1.5s so it keeps popping over the whole celebration instead
of bursting once and going static, then auto-close.
* feat(onboarding): remove collapse — card is just checklist + Dismiss
Collapse didn't save meaningful space in the footer, and onboarding isn't
essential enough to warrant the extra control — Dismiss already covers opting
out. Drops the collapse toggle, the folded header state, and the store's
collapsed/setCollapsed.
* feat(onboarding): animate the celebration in and out (no abrupt close)
The celebration appeared and vanished abruptly. Add CSS-first transitions
following the repo's tw-animate-css convention (no Motion dependency):
- enter: animate-in fade-in-0 zoom-in-95 (300ms) as the checklist gives way
- exit: an 'exiting' state plays animate-out fade-out-0 zoom-out-95 (200ms) and
holds the unmount until it finishes, so markCompleted no longer cuts it off
- reduced motion: animate-none / duration-0 (instant, no jank)
* fix(onboarding): hold the celebration exit's faded state (fix close flicker)
tw-animate-css's 'exit' keyframe only defines a 'to' state and defaults
fill-mode:none, so at the end of the fade-out the card snapped back to opacity 1
for the ~20ms before unmount — a flicker. Add fill-mode-forwards so it holds the
faded-out end state until markCompleted unmounts it. Verified: opacity ramps to
0.00 and stays there through unmount (no 1.0 snap-back).
* docs(changeset): update onboarding-card changeset to final design
* fix(onboarding): header copy "Get setup" -> "Get set up"
Reviewer (pullfrog) flagged the header as non-idiomatic: "set up" is the
verb phrase, "setup" the noun. The imperative reads "Get set up". Regenerate
Lingui catalogs for the changed string.
* fix(onboarding): symmetric read-path logging + Zod cause on schema mismatch
Two reviewer (claude[bot]) diagnostics:
- readPersistedState now console.warns on catch, matching writePersistedState
— distinguishes a silent privacy/parse degradation from a correct
not-yet-activated state when debugging "card never appears".
- fetchDocumentEntryCount attaches the Zod error as `cause` so a /api/documents
shape change pinpoints the failing field in caller logs.
* fix(onboarding): pre-register completion live region + aria-labelledby heading
Two reviewer (claude[bot]) a11y findings on the card:
- The completion live region was mounted already-populated inside the
allComplete branch; VoiceOver/Safari miss a region added and filled in one
render. Mount it unconditionally at the component root, empty until complete,
so it is pre-registered (WCAG 4.1.3). Reduced-motion users who can't see the
blob rely on this announcement.
- Replace the checklist section's aria-label ("Getting started") with
aria-labelledby pointing at the visible <h2> ("Get set up") so landmark nav
and heading nav announce one string (WCAG 2.4.6); drops a redundant i18n key.
* test(onboarding): cover terminal-launch-throws guard + already-complete early-return
Closes two reviewer (claude[bot]) Consider-level test-gap recommendations:
- BottomComposer: a throwing launchInTerminal must keep the draft, toast, and
record no Ask-AI step. Asserts the guard's user-observable outcomes (draft
preserved, error toast, step not recorded) — mutation-verified RED if the
catch's early-return is removed.
- useOnboardingFileCompletion: an already-complete file step performs no
/api/documents fetch (defense-in-depth over recordOnboardingFileStep's own
steps.file guard) and ignores later files events.
* test(onboarding): isolate the steps.file guard arm in the already-complete no-op test
Reviewer (claude[bot]) caught that the "no-op when already complete" test never
called activate(), so `initialized` stayed false and the guard's `!initialized`
arm alone satisfied it — dropping `steps.file ||` from the guard would still
pass. activate() first so only the steps.file arm is exercised. Mutation-verified:
removing `steps.file ||` now fails this test.
* docs(onboarding): drop stale "collapse" from two comments
The collapse affordance was removed from the card design; OnboardingCardState
has no `collapsed` field. Remove the leftover word from the store JSDoc and the
main.tsx hydration comment so they match the shipped state shape.
* test(onboarding): cover non-files channel filter + live-region silence
Two reviewer (claude[bot]) Consider-level coverage suggestions:
- useOnboardingFileCompletion: a non-files documents-changed channel (graph,
backlinks) triggers no extra /api/documents fetch. Mutation-verified RED if
the channels.includes('files') guard is removed.
- OnboardingCard: the pre-registered live region stays empty (silent) during the
checklist state — the other half of the WCAG 4.1.3 pre-registration invariant.
Mutation-verified RED if the allComplete ternary is broken.
---------
GitOrigin-RevId: b3e89b56ade28f0a4acef3b59f417f0c1915f67d
* fix(open-knowledge): terminal file-drop path insertion and Ask-AI terminal reuse Drop a file onto the docked terminal to insert its shell-escaped absolute path at the prompt (VS Code / Cursor / JetBrains parity) instead of the drop being ignored; the CLI reads the file from disk. Resolves the dropped File to its path via a new bridge getPathForFile (Electron webUtils.getPathForFile), since Electron removed File.path. Ask AI on a selection now routes the launch into the terminal that is already open (writing into the active session's live PTY) rather than spawning a fresh tab per intent. The + control and Terminal > New Terminal menu still open new tabs, so multi-session is preserved. PRD-7238, PRD-7239 * fix(open-knowledge): actually route Ask-AI into the open terminal's live PTY The prior commit's message claimed the Ask-AI reuse fix but only shipped the file-drop change; the terminal-reuse logic was never implemented. The spec's plan (re-hand the launch to the active session, zero panel changes) was written before the movable-dock refactor, which made launches bake into the PTY spawn. Mutating the active session's launch now re-runs the mount effect and respawns (kills) the running shell, defeating the point. Reuse instead by writing into the live PTY: each panel reports its resolved ptyId up via a new onPtyId callback (TerminalPanel, TerminalGate), and the host keeps a per-session ptyId map. On a new launch nonce with an active live session, the host writes buildCliLaunchArgString(cli, prompt) into that PTY via bridge.terminal.input rather than opening a tab; it falls back to a new tab when no session has a live PTY yet. Adopted reload-survivors report their ptyId too, so reuse covers them (fixes the review's silent-drop concern). Known Phase-1 limit unchanged: writing into a shell prompt runs the command; a CLI already running interactively receives it as literal text. PRD-7239 * test(open-knowledge): pin adopted-session reuse and null drop-path edge cases Address the automated PR review's two test-hardening suggestions. Adopted-session Ask-AI reuse: extend the reload-survival dock test so a rehydrated survivor reports its adopted ptyId up (mirroring the real attachSession callback), then a launch writes the command straight into that adopted PTY with no new tab and no fresh create. Pins the reload-survivor reuse claim that was previously only asserted in a source comment. File-drop null paths: add TerminalPanel drop tests for getPathForFile returning empty/null. An all-null drop (clipboard blob, no disk backing) writes nothing; a mixed drop writes only the resolvable path, never a literal null or empty shell argument. * fix(open-knowledge): Ask-AI bubble button sends selection into the open terminal The WYSIWYG bubble-menu Ask AI button now sends the selected passage straight into the active shell (e.g. a running claude TUI) via a new active-terminal-input channel; the host owns the PTY state and falls back to the bottom Ask-AI composer when no terminal is open or the selection is empty. Mirrors the terminal-launch-events idiom but the payload is verbatim text, no CLI discriminant. PRD-7239 * fix(open-knowledge): CLI launches always open a new terminal tab A 'Create with CLI' / 'Open in terminal' / bottom-composer launch was reusing an already-open terminal — writing the launch command into the live PTY of a shell the user already had running (e.g. dropping a codex launch into a running claude). That was the wrong reuse surface: 'create' means a fresh terminal. Reuse of an open terminal now belongs solely to the selection bubble (requestActiveTerminalInput), which types highlighted text into the live shell. The launch-nonce path always opens its own tab; the panel still bakes the CLI launch into that fresh PTY spawn. PRD-7239 * fix(open-knowledge): defer Ask-AI bubble dispatch a frame; align reuse tests+comments Ask-AI bubble click deferred to rAF so ProseMirror's mouseup focus can't steal the caret back before composer/terminal focus lands. Reload-survivor reuse test now exercises requestActiveTerminalInput (launches always open a new tab), and the stale ptyIdBySessionRef comments now name the selection- input reuse path. * fix(open-knowledge): capture-phase terminal drop listeners; test selection reuse Terminal external-drop dragover/drop listeners now bind in the capture phase (matching FileTree) so xterm's canvas child can't swallow the event before the container sees it — the behavior the existing comment already claimed. Adds the counterpart reuse test: requestActiveTerminalInput writes the raw selection straight into the live PTY (no wrapping, no new tab) while launches open their own tab. * fix(open-knowledge): filter control chars from dropped paths; pin gate PTY forwards Dropped filenames are untrusted input written into the live PTY. A path with an embedded newline/CR is acted on by the tty line discipline before shell quoting, so it could auto-submit a partial command (injection via a dropped file). shellSingleQuote keeps the bytes shell-inert but can't stop the tty acting first — so the drop path now filters any path carrying an ASCII control char (codepoint scan, not a regex, so no lint-disable to strip on the public mirror). Also extends the TerminalGate forwarding test to pin onPtyId + adoptPtyId: the gate is the only host->panel crossing for those wires and every Dock/reload test stubs the gate, so a dropped forward would silently break reuse + reload survival while passing all of them. --------- GitOrigin-RevId: f0eeecbc6ad4493b2d5715532e905f66eb155e06
Contributor
There was a problem hiding this comment.
Automated approval from agents-private public-mirror-sync (run: https://github.com/inkeep/agents-private/actions/runs/28497989378). Source of truth is the monorepo; direct edits on inkeep/open-knowledge are overwritten on next sync.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add a first-run onboarding card to OK Desktop. A dismissable checklist in the sidebar footer guides genuinely new users through three momentum steps — create a project (pre-checked), create the first file (⌘N), and ask AI (⌘L) — each showing its keyboard shortcut. Steps check off as the user actually performs them; on finishing all three the card celebrates in place with the OK blob mascot before animating away for good. It shows only for a fresh single-project desktop session and never returns once dismissed or completed (device-local). Web and CLI render nothing.
Two docked-terminal fixes. Dropping a file onto the terminal now inserts its shell-escaped absolute path at the prompt (matching VS Code / Cursor / JetBrains), so you can drag a screenshot straight into a running
claudesession instead of the drop being ignored. And highlighting text and choosing "Ask AI" now sends the selection straight into the open terminal (or opens the Ask AI composer when no terminal is open) — consistent with the fact that there is no composer visible while the terminal is up. Launching a CLI (Create with…, Open in terminal) always opens a new terminal tab rather than reusing the one already running.