# Editor workflows

> WYSIWYG and source-mode editing, ephemeral single-file sessions (`ok notes.md`), Open with AI handoffs, properties pane, timeline panel, and rich MDX embeds.

- Repository: sashimikun/open-knowledge
- GitHub: https://github.com/sashimikun/open-knowledge
- Human docs: https://grok-wiki.com/public/docs/sashimikun-open-knowledge-5c45105c876e
- Complete Markdown: https://grok-wiki.com/public/docs/sashimikun-open-knowledge-5c45105c876e/llms-full.txt

## Source Files

- `docs/content/features/editor.mdx`
- `docs/content/features/assets-and-embeds.mdx`
- `packages/cli/src/commands/single-file-open.ts`
- `packages/cli/src/commands/single-file-dispatch.ts`
- `packages/cli/src/commands/open.ts`
- `packages/server/src/handoff-api.ts`
- `docs/content/features/timeline-and-recovery.mdx`

---

---
title: "Editor workflows"
description: "WYSIWYG and source-mode editing, ephemeral single-file sessions (`ok notes.md`), Open with AI handoffs, properties pane, timeline panel, and rich MDX embeds."
---

The Open Knowledge editor is a CRDT-backed web surface (`packages/app`) served by the collaboration server and opened via `ok start`, `ok ui`, `ok open`, or the `ok <file>` single-file dispatch in `packages/cli`. Each open document binds a TipTap WYSIWYG view and a CodeMirror source view to the same Yjs `source` text; the right document panel hosts Outline, Links, Graph, and Timeline tabs, while frontmatter properties render as a form above the WYSIWYG body.

## Editor layout

```text
┌─────────────────────────────────────────────────────────────────┐
│ File sidebar (project mode only) │ Editor canvas │ Document panel │
│                                   │  Properties*  │ Outline/Links/ │
│                                   │  WYSIWYG or   │ Graph/Timeline │
│                                   │  Source       │                │
│                                   │  Ask AI*      │                │
└─────────────────────────────────────────────────────────────────┘
  * Properties + Ask AI hidden in source mode / embedded / single-file constraints
```

| Surface | Default at ≥1024px | Embedded AI-editor webview | Single-file (`ok notes.md`) |
| --- | --- | --- | --- |
| File sidebar (left) | Open | Collapsed | Hidden |
| Document panel (right) | Open | Collapsed | Outline only |
| Properties form | WYSIWYG only | WYSIWYG only | WYSIWYG only |
| Ask AI composer | Desktop, non-embedded | Hidden | Hidden |

Toggle sidebars with `Cmd+Option+S` (file sidebar) and `Cmd+Option+B` (document panel). On Windows and Linux, use `Ctrl` in place of `Cmd`. Pin state persists per layout context in browser storage.

## WYSIWYG and source mode

The editor defaults to WYSIWYG (`wysiwyg`). The toolbar mode toggle switches to source mode (`source`), which lazy-loads CodeMirror on first visit per document. Both views edit the same CRDT-backed `source` Y.Text, so human edits, agent MCP writes, and concurrent collaborators stay synchronized.

<ParamField body="editorMode" type="'wysiwyg' | 'source'">
Persisted in `localStorage` under `ok-editor-mode-v1`. Source mode is disabled when the collab provider is disconnected (`sourceDisabled`).
</ParamField>

| Mode | Rendering | Properties pane | Find/replace |
| --- | --- | --- | --- |
| WYSIWYG | TipTap markdown | Form above editor body | WYSIWYG find bar |
| Source | CodeMirror raw markdown | Hidden (edit YAML in `---` fence) | CodeMirror find bar |

Type `/` in WYSIWYG to open the slash insert menu for headings, lists, code blocks, callouts, and registered MDX components.

<Note>
Source-mode copy always places styled code blocks on the clipboard `text/html` payload — never rendered HTML. Cross-app paste into Gmail or Slack shows literal markdown bytes, consistent with VS Code and Obsidian source mode.
</Note>

## Ephemeral single-file sessions

Run `ok <file>` to open one markdown file without initializing a project:

<CodeGroup>
```bash title="Loose file"
ok notes.md
```

```bash title="File inside a project"
ok ./specs/foo/SPEC.md
```

```bash title="Explicit open alias"
ok open ./start.md
```
</CodeGroup>

`decideSingleFileTarget` in the CLI root argv scanner routes operands that look like files (`.md`/`.mdx` extension or `existsSync`) before subcommand parsing. `prepareSingleFileOpen` chooses between two modes:

| Mode | When | Behavior |
| --- | --- | --- |
| `project` | File sits under an enclosing `.ok/` project root | Delegates to `ok open <docName>` — full project UI, focused on the doc |
| `ephemeral` | No enclosing project | Throwaway session scoped to one file |

Ephemeral sessions write **nothing** into the file's directory. `createEphemeralProjectDir` creates a temp `ok-ephemeral-*` directory with `.ok/config.yml` pointing `content.dir` at the file's parent folder. The CLI boots a local server with `singleFile: true`, opens the desktop app via `openknowledge://open?file=…` when installed, or starts a browser session (press `Ctrl-C` to tear down).

```text
ok notes.md
    │
    ├─ inside .ok/ project? ──yes──► ok open (project mode)
    │
    └─ no ──► ephemeral temp .ok/
              ├─ desktop? ──yes──► openknowledge:// deep link
              └─ no ──► boot server + browser (Ctrl-C teardown)
```

In single-file mode the UI drops the file sidebar, project switcher, settings shortcut, Ask AI composer, and document-panel tabs other than Outline. `/api/config` returns `singleFile: true`, which `useSingleFileMode` reads to gate layout.

<Warning>
Ephemeral sessions have no MCP wiring, no git project scaffold, and no agent handoff surfaces. Edits save directly back to the original file on disk; opening without editing leaves the file byte-identical.
</Warning>

## Properties pane

Document properties live in YAML frontmatter — the fenced `---` block at the top of each `.md`/`.mdx` file. In WYSIWYG mode, `PropertyPanel` renders above the editor body as a collapsible form bound to the same CRDT frontmatter region via `bindFrontmatterDoc`.

Supported property types:

| Type | Widget | Notes |
| --- | --- | --- |
| `text` | Text input | Default for new properties |
| `number` | Numeric input | |
| `boolean` | Checkbox | |
| `date` | Date picker | ISO `YYYY-MM-DD` |
| `list` | Sortable list rows | Drag-reorder via `@dnd-kit` |
| `object` | Nested key/value editor | |

Add a property from the toolbar **Add property** button (WYSIWYG only) or edit the raw frontmatter block in source mode. Changes propagate live in both directions. The key `frontmatter` is reserved.

<Tip>
When frontmatter YAML has a parse error, the panel shows a read-only warning. Switch to source mode to fix the fence, then return to WYSIWYG.
</Tip>

Folder-level default properties and templates are configured separately — see [Folders and templates](/folders-and-templates).

## Document panel

The right **document panel** (`DocPanel`) hosts informational tabs for the active document:

| Tab | Purpose |
| --- | --- |
| Outline | Heading tree; click navigates to heading (source mode places cursor on the heading line, skipping frontmatter) |
| Links | Forward links and backlinks for the open doc |
| Graph | Project link graph centered on the active doc |
| Timeline | Edit history with inline diffs and restore |

Properties are **not** a document-panel tab — they render in the editor column above the body.

### Timeline panel

Open Timeline from the clock icon in the document panel tab strip. `TimelineContent` polls `GET /api/history?docName=<name>&limit=100` every 10 seconds (backoff to 60s on errors, paused when the tab is hidden).

Each entry shows contributor attribution, timestamp, change summary, and entry type:

- Agent and human edits
- Upstream sync (git)
- File-system changes outside Open Knowledge

Click an entry to expand an inline diff against the current document. Toggle unified or split layout from the panel header. Identical versions show `no changes`. Frontmatter-only differences are stripped before diffing.

Restore uses `POST /api/rollback` with `{ docName, commitSha }`. Restore is append-only: it writes a new version with the old content rather than deleting history. A confirmation dialog warns that the current content is already preserved in the timeline.

## Open with AI handoffs

**Open with AI** dispatches the project, a folder, or a file to installed agent apps. Handoffs are provider-neutral: the editor composes scope-specific prompts and posts them to `POST /api/handoff`, which launches the target via OS protocol handlers (Claude, Codex) or the Cursor CLI binary.

| Scope | Menu trigger | Prompt shape |
| --- | --- | --- |
| Project | Sidebar empty-space menu | `Let's work on this project using Open Knowledge.` |
| Folder | Folder row menu | ``Let's work on the `<folder>` folder using Open Knowledge.`` |
| File | File row menu | ``Let's work on `<path>` using Open Knowledge.`` |

When `appearance.preview.autoOpen` is `true` (default), prompts append `Open the OK editor in web view.` Set `appearance.preview.autoOpen` to `false` in user config to omit that trailer so agents do not auto-navigate your preview.

<ParamField body="appearance.preview.autoOpen" type="boolean" default="true">
Resolved fresh on each handoff from merged config. Toggle in **Settings → Preferences → Open preview when agent edits**.
</ParamField>

### Handoff targets

| Section | Targets | Launch mechanism |
| --- | --- | --- |
| Desktop | Claude (Cowork + Code), Codex, Cursor | `POST /api/handoff` → `claude://`, `codex://`, or `cursor://` URL |
| Terminal (desktop only) | Claude CLI, Codex CLI, Cursor CLI | Docked terminal with scoped prompt |

Install detection probes macOS app bundles, Windows registry keys, or Linux `xdg-mime` handlers via `GET /api/installed-agents`. On `localhost`, results are accurate; on remote hosts the submenu lists all supported agents and relies on the browser's protocol-dispatch dialog.

The Claude **claude.ai** (Cowork) row appears on file-scope dispatches only. Folder and project dispatches hide it because the cloud agent has no project-root parameter.

<Note>
Inside an AI editor's embedded webview (Cursor, Codex, Claude Desktop), Open with AI menus and the Ask AI composer are hidden to prevent handoff loops. MCP tools and the document itself remain fully available.
</Note>

:::endpoint POST /api/handoff
Dispatches a composed agent URL from the editor UI. Body: `{ target, url, workspacePath? }`. `target` is one of `claude-cowork`, `claude-code`, `codex`, `cursor`. `url` max 4096 chars. Cursor recipes require `workspacePath` within the project content directory. Returns `200` on successful spawn, `404`/`422` when the target is not installed.
:::

## Ask AI composer

The bottom **Ask AI** composer (desktop, non-embedded, project mode) accepts free-text instructions scoped to the active document. `Shift+Enter` inserts a newline; `Enter` dispatches.

- Default agent: first installed in Claude → Codex → Cursor order
- Agent picker overrides per send; choice persists on the machine
- Active doc is threaded as an `@`-mention via `composeAskPrompt` / `assembleHandoffPrompt`
- Text selection in WYSIWYG shows a Sparkles **Ask AI** button that pins the passage as a removable context pill

Selection handoffs embed the passage inline when under the 4096-char URL budget; larger selections fall back to locus mode (anchor + directive to read the full passage via MCP).

## Rich MDX embeds and assets

WYSIWYG editing supports standard markdown plus MDX-style JSX components registered in `@inkeep/open-knowledge-core` and rendered in `packages/app`.

### Slash-insert components

| Component | Category | Purpose |
| --- | --- | --- |
| `Callout` | Content | Tips, warnings, notes (16 `type` variants, optional collapsible) |
| `Accordion` | Content | Collapsible section |
| `Tabs` / `Tab` | Content | Horizontal pill panels |
| `img` | Media | Image with alt text |
| `video` | Media | Native player; YouTube, Vimeo, Loom embeds |
| `audio` | Media | Native audio player |
| `Pdf` | Media | Multi-page inline PDF viewer |
| `Embed` | Media | External iframe (docs, Figma, CodeSandbox) |
| `MermaidFence` | Content | Mermaid diagram from fenced source |
| `Math` | Content | KaTeX block equation |
| `Mirror` / `MirrorSource` | Content | Live cross-doc content mirrors |
| `File` | Media | Downloadable attachment row (drag-drop or picker) |
| `Tag` | Inline | `#tagname` cross-doc hashtag |

### Wiki-style asset embeds

Beyond JSX components, markdown supports wiki embeds and standard image syntax:

| Syntax | Semantics |
| --- | --- |
| `![alt](./path.png)` | Markdown image (relative path) |
| `![[diagram.png]]` | Wiki embed (opaque assets render as click-dispatch File rows) |
| `![[file.pdf#page=3\|Page 3]]` | Wiki embed with anchor and alias |
| `<Pdf src="./report.pdf" />` | Opt-in inline PDF viewer |

Public `https://` URLs pass through unchanged on cross-app copy. Private, loopback, and link-local URLs degrade to styled code blocks in HTML clipboard payloads so recipients see literal source instead of broken images.

Drop files into the editor to upload and insert; image uploads can emit wiki-embed or markdown-link shape depending on file type and config.

## Real-time collaboration

All editor state — body text, frontmatter, sidebar toggles — is CRDT-backed via Hocuspocus/Yjs. Multiple humans and agents can edit concurrently. Per-user presence appears in the editor header. For agent burst review and selective undo, switch the document panel to agent activity mode.

<Steps>
<Step title="Open a project doc">

Run `ok start --open` or `ok open <doc-path>` from the project root. Select a file from the sidebar.

</Step>

<Step title="Edit in WYSIWYG or source">

Use the toolbar toggle to switch modes. Add structure with `/` slash commands or edit raw markdown in source mode.

</Step>

<Step title="Set properties">

Expand the Properties section above the editor body. Add `status`, `owner`, `tags`, or custom keys. Verify the `---` fence updates in source mode.

</Step>

<Step title="Hand off to an agent">

Right-click a file in the sidebar → **Open with AI**, or type an instruction in the Ask AI composer. Confirm the agent receives the scoped prompt and can reach Open Knowledge MCP tools.

</Step>

<Step title="Review history">

Open the Timeline tab. Expand an entry to diff against the current version. Restore if needed via the undo icon (append-only rollback).

</Step>
</Steps>

## Related pages

<CardGroup>
<Card title="Core concepts" href="/core-concepts">
Three-layer model, filesystem-as-database, link graph, and git-backed attribution.
</Card>
<Card title="Collaboration server" href="/collaboration-server">
Hocuspocus/Yjs CRDT lifecycle and server-routed writes.
</Card>
<Card title="Wire agent editors" href="/wire-agent-editors">
MCP registration, bundled skills, and `exec` verification.
</Card>
<Card title="Folders and templates" href="/folders-and-templates">
Folder frontmatter and template resolution for new docs.
</Card>
<Card title="CLI reference" href="/cli-reference">
`ok <file>` dispatch, `ok open`, and server management commands.
</Card>
<Card title="MCP tools reference" href="/mcp-tools-reference">
`write`, `edit`, `history`, `checkpoint`, and `restore_version` for agent-driven edits.
</Card>
<Card title="Configuration reference" href="/configuration-reference">
`appearance.preview.autoOpen`, `appearance.sidebar.*`, and config precedence.
</Card>
</CardGroup>
