Extension Details

- Claude Code Bridge
- by okapi-ca
- 22 Recent Installs | 22 Total Installs
- Integrates Claude Code CLI with Nova via the WebSocket MCP protocol, providing context sharing, diff viewing, and selection tracking.
- Repository
- Bug Reports
-
Read & Write Files
-
Launch Subprocesses
-
Send Network Requests
-
This extension is allowed to:
Readme
Claude Code Bridge for Nova
Integrate Claude Code CLI with Nova (by Panic) through the WebSocket MCP protocol — the same protocol used by the official VS Code and JetBrains extensions.
Why?
Claude Code has official IDE integrations for VS Code and JetBrains, but nothing for Nova. If you love Nova's native macOS experience and want Claude Code's full agentic capabilities — context sharing, inline diffs, selection tracking — this extension bridges the gap.
The approach was pioneered by coder/claudecode.nvim for Neovim. This project brings the same idea to Nova using its JavaScript extension API.
How It Works
┌──────────────────────────────────────────────────┐
│ Nova Editor │
│ │
│ ┌─────────────┐ JSON lines ┌─────────────┐ │
│ │ main.js │◄──────────────►│ ws-server.js │ │
│ │ (Extension)│ stdin/stdout │ (Node.js │ │
│ │ │ │ subprocess) │ │
│ └──────┬──────┘ └──────┬───────┘ │
│ │ │ │
│ Nova APIs: WebSocket MCP │
│ • TextEditor (RFC 6455) │
│ • Workspace │ │
│ • NotificationCenter │ │
│ • FileSystem │ │
└─────────────────────────────────────────┼─────────┘
│
┌─────────────────────┘
│
▼
┌─────────────────┐
│ Claude Code CLI │
│ (claude → /ide) │
└─────────────────┘
The extension spawns a Node.js subprocess that runs a WebSocket server implementing the MCP (Model Context Protocol). Claude Code CLI discovers this server through a lock file at ~/.claude/ide/<port>.lock — exactly the same mechanism used by the official extensions. All communication uses JSON-RPC 2.0 over WebSocket frames.
Features
- Automatic context sharing — Claude Code sees your active file, selection, and workspace structure
- Selection tracking — Real-time selection broadcasts as you navigate and select code
- Diff review — Accept or reject Claude's proposed changes via notification prompts; user edits in the proposed-changes tab are preserved on Accept and signalled back to Claude
- File operations — Claude can open files, save documents, and check for unsaved changes
- Sidebar tracking — Three live sections: connection status, pending diffs queue with per-item Accept/Reject, and an activity log of file operations and diff outcomes (auto-refreshes every 30s)
- One-click launch — Open Claude Code in iTerm or Terminal.app with the IDE-bridge env vars pre-set; the bridge connects automatically
- Secure by default — Localhost-only WebSocket with UUID token authentication
Requirements
| Dependency | Minimum Version |
|---|---|
| Nova | 10.0 |
| Node.js | 18.0 |
| Claude Code CLI | Latest |
Installation
From Source
git clone https://github.com/okapi-ca/claudecode-nova.git
cp -r claudecode-nova/claudecode-nova.novaextension \
~/Library/Application\ Support/Nova/Extensions/
For Development
git clone https://github.com/okapi-ca/claudecode-nova.git
ln -s "$(pwd)/claudecode-nova/claudecode-nova.novaextension" \
~/Library/Application\ Support/Nova/Extensions/claudecode-nova.novaextension
Then enable Extension Development in Nova: Preferences → General → Extension Development.
Quick Start
- Open a project in Nova
- The extension starts automatically (you'll see a notification)
- Run the Launch Claude Code command from Extensions → Claude Code Bridge (or the Command Palette).
- It opens Claude in your configured terminal (iTerm by default if installed, otherwise Terminal.app — see the
claudecode.terminalAppsetting) with the workspace cwd and IDE-bridge env vars already set. - The bridge connects automatically; no need to type
/ide. - You'll see a "Connected" notification in Nova. Claude now has access to your editor context.
Manual launch (alternative)
If you prefer to drive the terminal yourself, set claudecode.terminalApp to clipboard and run:
cd /your/project
CLAUDE_CODE_SSE_PORT=<port> ENABLE_IDE_INTEGRATION=true claude
The port is shown in the Show Claude Code Status command. Inside Claude, /ide triggers discovery if the env vars weren't picked up.
Supported MCP Tools
These are the tools that Claude Code can invoke through the bridge, matching the protocol used by the official VS Code and JetBrains extensions:
| Tool | Status | Description |
|---|---|---|
openFile |
✅ Full | Open a file with optional line navigation |
openDiff |
✅ Full | Diff via temp file + accept/reject notification. User edits in the proposed-changes tab are preserved on Accept and signalled back to Claude (see Known Limitations §1 for the side-by-side caveat). |
getCurrentSelection |
✅ Full | Current editor selection with file path and range |
getLatestSelection |
✅ Full | Most recently recorded selection |
getOpenEditors |
✅ Full | List all open editor tabs with metadata |
getWorkspaceFolders |
✅ Full | Workspace folder paths |
checkDocumentDirty |
✅ Full | Check for unsaved changes in a file |
saveDocument |
✅ Full | Save a document |
getDiagnostics |
⚠️ Partial | Requires LSP extension cooperation (see Limitations) |
closeAllDiffTabs |
⚠️ Best-effort | Removes our temporary proposed_* files; cannot close Nova editor tabs because Nova has no public tab-management API |
close_tab |
❌ Not supported | Nova exposes no public API to close an editor tab — see Known Limitations §6. Not advertised in tools/list. |
executeCode |
❌ Not supported | Nova has no Jupyter kernel integration. Not advertised in tools/list. |
Direct Tool Invocation (debug helper)
The Claude Code CLI only forwards mcp__ide__getDiagnostics to the model — the other 9 tools registered by ws-server.js are consumed internally by the CLI and not callable from a model conversation. For debugging or scripting, Scripts/call-bridge.js connects to the running bridge directly via the lock file and invokes any tool by name. No npm dependencies.
SCRIPT="$HOME/Library/Application Support/Nova/Extensions/ca.okapi.claudecode-nova/Scripts/call-bridge.js"
# (or wherever the extension is installed; for development use the project path)
node "$SCRIPT" --tools # list tools advertised by the bridge
node "$SCRIPT" getOpenEditors # call with empty args
node "$SCRIPT" getCurrentSelection
node "$SCRIPT" getWorkspaceFolders
node "$SCRIPT" openFile '{"filePath":"/abs/path","lineNumber":42}'
node "$SCRIPT" saveDocument '{"filePath":"/abs/path"}'
The script auto-discovers the lock file under ~/.claude/ide/, preferring one whose workspaceFolders matches the current cwd when several Nova instances are running. Output is the unwrapped tool result as pretty-printed JSON; errors go to stderr with a non-zero exit code.
Sidebar
The Claude Code sidebar exposes three sections:
▼ Claude Code
▼ Status
● Server Running
Port: 12345
Clients: 1
▼ Pending Diffs
▼ auth.ts 5s ago
✓ Accept
✗ Reject
▼ Button.tsx 1m ago
✓ Accept
✗ Reject
▼ Activity
📄 Opened src/parser.ts just now
💾 Saved README.md 12s ago
✓ Accepted diff: components/Button.tsx 1m ago
✂️ Sent selection from src/types.ts 2m ago
✗ Rejected diff: middleware/cors.ts 5m ago
▶ Tool Calls (47)
- Status — connection state, port, client count. Header buttons start/stop the bridge.
- Pending Diffs — every diff Claude proposes is queued here with file name + age. Double-click Accept or Reject to resolve. Notifications still appear for the first diff (so it gets your attention); the sidebar handles multi-diff overflow. Double-click the parent item to see details with Open / Accept / Reject buttons.
- Activity — visible-effect events (file opens/saves, selections sent, diff outcomes). Click an item to open the corresponding file (file ops) or see a details dialog (diff ops). The collapsible Tool Calls group at the bottom shows the raw MCP traffic for debugging — including the bookkeeping calls Claude makes constantly (
getCurrentSelection,getOpenEditors, …). - Buffers are bounded (50 activity events, 100 tool calls). Header Refresh re-renders, Clear empties both buffers. Auto-refresh every 30 s keeps relative timestamps accurate.
Commands
Access these from Extensions → Claude Code Bridge or the Command Palette:
| Command | Description |
|---|---|
| Start Claude Code Bridge | Start the WebSocket MCP server |
| Stop Claude Code Bridge | Stop the server and disconnect clients |
| Send Selection to Claude | Push the current selection as context |
| Add Current File to Claude | Send the entire active file as context |
| Show Claude Code Status | Display connection status and server info |
| Launch Claude Code (with IDE integration) | Open Claude Code in your terminal of choice (iTerm or Terminal) with the IDE bridge env vars pre-set. Falls back to clipboard for unsupported terminals — see claudecode.terminalApp setting. |
Configuration
Global Preferences
| Key | Default | Description |
|---|---|---|
claudecode.portMin |
10000 |
Minimum port for the WebSocket server |
claudecode.portMax |
65535 |
Maximum port |
claudecode.autoStart |
true |
Start the bridge automatically on activation |
claudecode.trackSelection |
true |
Broadcast selection changes in real time |
claudecode.nodePath |
node |
Path to the Node.js executable |
claudecode.terminalApp |
auto |
Where the Launch Claude Code command opens the CLI: auto (iTerm if installed, else Terminal), iTerm, Terminal, or clipboard (just copy the command). Other terminals (Warp, Ghostty, Hyper) fall back to clipboard automatically. |
Per-Project Settings
| Key | Default | Description |
|---|---|---|
claudecode.claudeCommand |
claude |
Command to launch Claude Code CLI |
Known Limitations
The following limitations exist due to Nova's extension API boundaries:
-
Diff viewer — Nova does not expose a native diff API like VS Code's
vscode.diff. Proposed changes are shown by opening a temporary file alongside the original, with an accept/reject notification. Edits the user makes in the proposed-changes tab before clicking Accept are preserved (the actual content of the temp file is what gets saved) and signalled back to Claude viauserEdited: truein the response. A future version may leverage Nova's built-in Git comparison view for side-by-side rendering. -
Diagnostics — Nova does not provide a global API for reading LSP diagnostics from third-party extensions. The
getDiagnosticstool currently returns an empty list. Full support would require cooperation with language server extensions or a sharedIssueCollection. -
No native WebSocket server — Nova's JavaScript runtime does not include
WebSocketserver or raw TCP socket APIs. The workaround is a Node.js subprocess, which adds a dependency but works reliably. -
No HTTP preview integration — Nova's built-in web preview is not accessible through the extension API, so Claude cannot interact with the preview pane.
-
Selection line numbers — Nova's
Rangeis character-offset based. Line number mapping in selection tracking is approximate. A future version will useTextDocumentline-counting methods for precise ranges. -
No tab-management API — Nova exposes no method on
TextEditororWorkspaceto close an editor tab from an extension. As a consequence: close_tab(tool 11 in claudecode.nvim PROTOCOL.md) is not advertised in ourtools/list— Claude will not call it.closeAllDiffTabsonly removes the temporaryproposed_*files staged in extension storage; the corresponding tabs in Nova remain open until the user closes them manually (Cmd+W).-
Confirmed by the Tabs Sidebar extension, which documents the same limitation.
-
No Jupyter kernel integration —
executeCode(tool 12 in PROTOCOL.md) is unsupported. Nova does not expose a notebook runtime, and exposing one would be a separate product. Not advertised intools/list.
Architecture
claudecode-nova.novaextension/
├── extension.json # Extension manifest (commands, sidebar, config)
├── Scripts/
│ ├── main.js # Nova entry point — editor API bridge
│ ├── ws-server.js # WebSocket MCP server (Node.js subprocess)
│ └── call-bridge.js # Standalone CLI client for invoking bridge tools
├── Images/
│ ├── claude-icon-small.png
│ ├── claude-icon-large.png
│ └── ...@2x variants
└── README.md
Communication Flow
- Nova extension (
main.js) spawnsws-server.jsas a child process ws-server.jsbinds a WebSocket server on127.0.0.1:<random_port>- A lock file is written to
~/.claude/ide/<port>.lockwith connection info - Claude Code CLI discovers the lock file via
/idecommand - CLI connects to the WebSocket, authenticates with the UUID token
- MCP tool calls arrive as JSON-RPC 2.0 requests over WebSocket
ws-server.jsforwards them tomain.jsvia stdout JSON linesmain.jsexecutes the tool using Nova APIs and sends the result back via stdinws-server.jswraps the result in MCP format and returns it over WebSocket
Lock File Format
{
"port": 12345,
"authToken": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"version": "0.2.0",
"ideName": "Nova",
"ideVersion": "1.0.0",
"workspaceFolders": ["/Users/you/project"],
"pid": 54321
}
Security
- WebSocket server binds to
127.0.0.1only (no network exposure) - Every connection requires the UUID auth token in the
x-claude-code-ide-authorizationheader - Lock files are removed on clean shutdown
- No data leaves your machine — all communication is local IPC
Roadmap
v0.2.0 (shipped)
- [x] One-click launch into iTerm or Terminal.app with IDE env vars pre-set
- [x] User edits in the proposed-changes tab are preserved on Accept and signalled to Claude (
userEdited/finalContent) - [x] Sidebar with Pending Diffs queue (per-item Accept/Reject) and Activity log (visible-effect events + raw tool-call group)
- [ ] Improved diff view with side-by-side file comparison
- [ ] Diagnostics integration via shared IssueCollection
- [ ] Accurate line number tracking in selections
v0.3.0
- [ ] Warp / Ghostty / Hyper launch support (URL-scheme or wrapper-script approach)
- [ ] Configurable keyboard shortcuts
- [ ] Multi-workspace support
- [ ] File watcher for external changes
v1.0.0
- [ ] Full MCP protocol v2 compatibility
- [ ] Automated test suite
- [ ] Publication on extensions.panic.com
- [ ] Proper icon set
Contributing
Contributions are welcome! This project exists because the community (notably coder/claudecode.nvim) proved that third-party IDE integrations with Claude Code are fully achievable.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-thing) - Commit your changes (
git commit -m 'Add amazing thing') - Push to the branch (
git push origin feature/amazing-thing) - Open a Pull Request
Development Tips
- Enable Nova's Extension Console: Extensions → Show Extension Console, filter by source
- The
ws-server.jssubprocess logs are piped through — check the console for both layers - Use
claude --idefrom an external terminal to test connections - The PROTOCOL.md from claudecode.nvim is the definitive protocol reference
Credits
- Author: Marc Bourget — CISSP, Principal Director of Cybersecurity
- Sponsor: LCI Education — An international educational community of 12 higher education institutions across 17 campuses on 5 continents. LCI Education supports open-source initiatives and encouraged the public release of this project.
- Protocol reverse engineering: coder/claudecode.nvim by Thomas Kosiewski and contributors
- Nova Extension API: docs.nova.app
- Claude Code: Anthropic
Sponsor
LCI Education
Proudly supporting open-source development
LCI Education is an international educational community comprising 12 higher education institutions
operating across 17 campuses on 5 continents, dedicated to accessible, quality education worldwide.
License
MIT — See LICENSE for details.
Release Notes
Changelog
0.3.0 — 2026-04-30
Added
- Real line/column numbers in selections —
getCurrentSelection,
getLatestSelection, and liveselection_updatepayloads now expose
0-indexedstartLine/endLine/startColumn/endColumn
computed from the document offset (was hardcoded to 0). The
selection_sentactivity events render as(L42-L58)in the
sidebar. - Git branch in context — current branch is cached via
git rev-parse --abbrev-ref HEAD(refreshed on bridge start and
every 5 minutes) and shipped in everyselection_updateand
getWorkspaceFoldersresponse. Silently null outside git repos. - Diff line stats — every
openDiffcomputes a lightweight
+N / -M linesdelta (multiset line intersection vs. the file on
disk; detects new files) and surfaces it in the system notification,
the Pending Diffs sidebar label, the row tooltip, and the details
dialog. - Pending Diffs tooltip preview — hovering a diff row now shows
the first 5 lines of the proposed content with an overflow marker. - Activity log persistence —
activityLogandtoolCallLogare
serialized toglobalStoragePath/activity.json(debounced 1s) and
restored on activate.pendingDiffsare intentionally not persisted
(their Claude-siderequestIds die with the session). claudecode.diffTimeoutMinutessetting (default 30, 0 disables)
— auto-rejects pending diffs older than the threshold via the
existing 30s sidebar tick. Stops deadrequestIds from piling up
when Claude crashes mid-flow.Restart Claude Code Bridgecommand (claudecode.restart) —
stop + 300ms + start, useful after changing the port range or the
Node.js path.- Default keyboard shortcuts:
Cmd+Ctrl+L→ Send Selection to Claude (when a selection exists)Cmd+Ctrl+A→ Add Current File to Claude
AvoidsCmd+Shift+Lwhich Nova already uses for "Reveal in Files
Sidebar".claudecode.claudeArgsper-workspace setting — extra arguments
appended after the Claude command inLaunch Claude Code. Unlocks
--continue,--model claude-opus-4-7,
--dangerously-skip-permissions, etc. without code changes.- Auto-save before
Send Selection to Claude— if the document is
dirty, it's saved first so Claude's disk-reading tools (Read, Bash)
see the same content as the buffer.
Fixed
closeAllDiffTabsno longer leaks pending diffs — the tool now
rejects every still-pending diff viaresolveDiff(id, false)before
sweeping the temp-file directory, freeing Claude-siderequestIds
that would otherwise wait forever. The Nova editor tabs themselves
still need a manualCmd+W(no public tab-close API in Nova).
Notes
- No protocol changes;
ws-server.jsis untouched. - All payload additions are additive — existing Claude Code clients
will simply ignore the new fields (gitBranch,startLine,
endLine, …).
0.2.1 — 2026-04-29
Changed
- Identifier renamed from
com.marcbourget.claudecode-novato
ca.okapi.claudecode-novato match theokapi-caorganization
registered on the Panic Extension Library. Required for marketplace
publication — Panic ties extensions to a registered organization
via the reverse-DNS prefix of the identifier, and thecom.marcbourget
prefix had no corresponding org. Organization metadata in the manifest
was updated from"Marc Bourget"to"okapi-ca"for the same reason. - Side-effect on local installs: Nova treats the new identifier as
a different extension. Anyone who previously installed v0.2.0 from
source undercom.marcbourget.claudecode-nova/should remove that
directory and copy the new bundle toca.okapi.claudecode-nova/,
otherwise both versions cohabit and the bridge port allocation can
collide.
0.2.0 — 2026-04-29
Added
- Sidebar activity tracking — two new sections under the Claude Code
sidebar mirror what the VS Code v2.1.69+ activity panel shows: - Pending Diffs — every diff Claude proposes appears with its file
name and a relative timestamp. Each diff has Accept / Reject child
items so you can resolve from the sidebar without going through
the system notification. Notifications are still emitted (3A) so
the first diff still attracts attention; the sidebar is the
multi-diff overflow path. - Activity — file opens, saves, sends-to-context, file-added-to-
context, and diff outcomes appear at the top with timestamps that
auto-refresh every 30s. Below them, a collapsible "Tool Calls (N)"
group exposes every raw MCP tool invocation for debugging. - Click-through on activity items:
- File operations (
opened,saved,added,selection_sent) →
open the file in Nova - Diff events → details dialog with timestamp, length, and Open /
Accept / Reject buttons - Five new commands wired internally for the sidebar (not in the
Extensions menu):claudecode.activityClick,
claudecode.activityClear,claudecode.diffAccept,
claudecode.diffReject,claudecode.diffShowDetails,
claudecode.sidebarRefresh. - "Launch Claude Code" command now opens Claude in a real terminal
instead of just copying a command to the clipboard. Driven via
AppleScript so the workspace cwd and the IDE-bridge env vars
(CLAUDE_CODE_SSE_PORT,ENABLE_IDE_INTEGRATION=true) are pre-set
— no manual paste, no/idetyping required, the bridge connects
automatically. - New global setting
claudecode.terminalApp(enum): auto(default) — iTerm2 if installed, otherwise Terminal.appiTerm— iTerm2, opens a new tab in the current windowTerminal— Terminal.app, opens a new windowclipboard— keep the v0.1.x copy-to-clipboard behaviourScripts/call-bridge.js— standalone CLI client for debugging
and scripting. The Claude Code CLI only forwards
mcp__ide__getDiagnosticsto the model side; the other 9 tools
registered byws-server.jsare consumed internally by the CLI
and unreachable from a model conversation. This script connects
to the running bridge directly via the lock file and invokes any
tool by name. No npm dependencies — manual WebSocket framing
mirrorsws-server.js. See README §Direct Tool Invocation.
Fixed
- RFC 6455 handshake — the
Sec-WebSocket-Acceptcalculation
used a transposed magic GUID (…-5AB5DC11CE56instead of
…-C5AB0DC85B11), so any RFC-compliant client computed a
different digest and closed the connection right after the 101.
Symptom:read ECONNRESET~5 ms after "Claude Code client
connected" in the Nova extension console with Claude CLI v2.1.x
(which uses thewsNode.js library). Without this fix the
bridge was effectively unusable on recent Claude CLI builds. - WebSocket subprotocol echo —
ws-server.jsnow echoes back
the first offeredSec-WebSocket-Protocol(Claude CLI sends
mcp). Strict clients reject the connection if a requested
subprotocol is not selected by the server. - Disconnect logging — the close-event
hadErrorflag is now
surfaced in the extension console so future handshake regressions
are visible at a glance.
Changed
openDiffwas refactored: pendingDiffs is now the source of truth.
The notification handler and the sidebar Accept/Reject commands both
call the sameresolveDiff(id, accepted)function. Idempotent —
resolving a diff a second time is a no-op, so race conditions
between the notification and the sidebar are harmless.
Notes
- Other terminals (Warp, Ghostty, Hyper, kitty, Alacritty) lack a
reliable AppleScript control surface and fall back to the clipboard
path. Pickclipboardexplicitly to silence the auto-detect. - If the configured terminal isn't installed at launch time, the
extension falls back to clipboard automatically and notifies the user. - Activity buffers are bounded: 50 visible events, 100 raw tool calls.
Older entries roll off — there is no persistence across Nova restarts.
0.1.1 — 2026-04-29
Fixed
openDiffnow respects edits the user made in the proposed-changes tab
before clicking Accept. Previously the originalnewContentfrom Claude
was always written to disk, silently discarding any in-IDE edits.
Changed
openDiffresponse payload now carriesuserEdited: trueand
finalContentwhen the saved file differs from Claude's original proposal.
This mirrors the v2.1.110 Claude Code CLI behaviour where the model is
informed of edits the user made before accepting (see CLI changelog
2026-03 entry).closeAllDiffTabsMCP description corrected to reflect what it actually
does on Nova: cleans up temporaryproposed_*files in extension storage.
Nova exposes no public API to programmatically close editor tabs, so the
prior wording ("Close all open diff views") was misleading.
Investigated, not implemented
close_tabandexecuteCode(added toclaudecode.nvimPROTOCOL.md as
the canonical 12-tool list) are not implementable on Nova:close_tab: Nova has no public tab-management API
(TextEditor/Workspaceexpose noclose()method, no command, no
keyboard-shortcut surface for extensions).executeCode: Nova has no Jupyter kernel integration.
Neither tool is advertised in ourtools/listresponse — Claude will
not call them on Nova.
0.1.0 — 2026-02-26
- Initial release
- WebSocket MCP server bridge via Node.js subprocess
- MCP tools: openFile, openDiff, getCurrentSelection, getLatestSelection, getOpenEditors, getWorkspaceFolders, checkDocumentDirty, saveDocument, getDiagnostics, closeAllDiffTabs
- Real-time selection tracking
- Sidebar status panel
- Lock file discovery mechanism for Claude Code CLI