The vanilla Claude Code binary hosted in a webpage, hardwired to a notebook environment. This is not endorsed by Anthropic in any way. Use your existing Anthropic account through /login with token copying, or use OpenRouter API endpoints. Defaults to our OpenRouter demo endpoint, restricted to MiMo models only.
Live values of variables being observed by Claude Code.
Bridges a lopecode notebook to Claude Code via WebSocket.
Claude Code CLI ←MCP→ Channel Server ←WS→ This Module (browser)
Cell groups (in dependency order):
cc_chat (main interface), cc_watch_table (variable inspector)cc_config, cc_notebook_id, cc_activity, cc_status, cc_messages, cc_watches, cc_module, voiceEnabledcc_find_module resolves module names via runtime.mainscc_serialize_value (safe value→string for transport)cc_watchers observes variables, debounces & sends updatescc_handle_* (one per MCP tool)cc_command_handlers routes action→handlercc_ws manages connect/pair/auto-reconnect and message dispatchcc_change_forwarder streams cell edits, cc_voice optional speech I/OcurrentModules, exportToHTML, compile, history, runtime-sdk helpersReactive Inputs.input() cells holding connection state. These are the shared mutable atoms that UI and WebSocket cells read/write.
cc_find_module resolves a module name (e.g. "@tomlarkworthy/exporter-3") to a runtime Module object by polling viewof currentModules.value at call time (not reactively). cc_serialize_value safely converts any runtime value to a truncated string for transport.
Subscribes to Observable variables via observe(), debounces updates (1s), and forwards changes to Claude Code over the WebSocket. Also maintains the cc_watches table UI.
One handler per MCP tool. Each receives a cmd object and the Observable runtime, returns {ok, result} or {ok:false, error}. Handlers: get-variable, define-variable, define-cell, delete-variable, list-variables, list-cells, run-tests, create-module, delete-module, eval, fork, watch, unwatch.
cc_command_handlers maps action strings to handler functions. cc_ws manages the WebSocket lifecycle: connect, pair with token, dispatch incoming messages (commands, replies, tool-activity), and auto-reconnect from the URL hash cc= param or sessionStorage.
cc_change_forwarder polls the local-change-history and streams new cell edits to Claude Code. cc_voice provides optional speech recognition input and TTS output for hands-free pairing.
Serialize literate computational notebooks with their dependancies into single downloadable files. Double click to open locally. No server required, works in a file:// context for simplicity.
Inputs, htl, highlight, _ (lodash) and markdown are bundled for offline operation.Exporter improves upon exporter 2 by refactoring out Observable Javascript concepts, it works on the low level reprentation directly.
To put the exporter in one of your notebooks, first import the UI builder.
import {exporter, forkAnchor, exportAnchor } from '@tomlarkworthy/exporter'
Then call the builder to make the UI. You don't need to pass any options, but the options is where you can customise the output format.
exporter({
handler: (action, state) => {}, // Optional UI click handler
style: undefined,// customer reference to a style DOM node or a string to insert as a style block
output: (out) => {}, // hook to get result of exporting
notebook_url: undefined,// hardcode the default notebook_url
})
If you want to export without a UI, use the function exportToHTML, see the example
import {exportToHTML } from '@tomlarkworthy/exporter'
async function exportToHTML({
mains = new Map(), // (name -> module) Map of main modules
runtime = _runtime,
options = {} // Object, export options, e.g. head, title
} = {})
You can also just use inline anchor tags: forkAnchor() or downloadAnchor()
The HTML file contains <script> blocks that hold content to serve internal network requests locally.
<script id="d/c2dae147641e012a@46"
type="text/plain"
data-encoding="base64+gzip"
data-mime="application/javascript"
>
...inline text or base64 string
</script>
Requests to the URL matching the id are served locally, this includes import, fetch, XMLHttpRequest and <script> src attribute.
The main script loads the Observable runtime with no standard library and loads a bootloader module. The bootloader is responsible for setting up the standard library and loading the first real modules, which it discovers by reading the bootconf.json. @tomlarkworthy/bootloader is the default which comes with d3, Plot, md, htl and lodash local.
To help carry state across an export, the URL hash parameter is remembered in the bootconf.json and set automatically when opening the file if one is not present. URLs are limited in size, ff you need to move large amount of data across an export, use a local FileAttachment instead.
Themes are sourced from NotebookKit. A theme is fetched once from Github once when switching themes, but integrated into the export, and reused locally on subsequent exports. This keeps the bundle small, and you only need a network connection if switching to obtain the new CSS source files.
Serialize a single module from the live runtime to a .js module source string. Unlike module_specs (which serializes all modules as part of the full HTML export pipeline), exportModuleJS works on-demand against the live runtime with no task dependency.
import {exportModuleJS} from "@tomlarkworthy/exporter-3"
const {source, fileAttachments} = await exportModuleJS(moduleId, {runtime, moduleNamesFn})
Parameters
moduleId — module name string, e.g. "@tomlarkworthy/flow-queue"options.runtime — Observable runtime instance (default: _runtime)options.moduleNamesFn — function to build module name map (default: buildModuleNames)Returns {source, fileAttachments}
source — full .js module source with export default function define(runtime, observer)fileAttachments — Map<name, {url, mimeType}> of the module's file attachments()Figures out the import structure of a runtime, just pass a runtime to the function moduleMap to get a summary of the modules. Returns a map indexed by a Module object to a record.
module -> {
type: "notebook import" | "module variable",
name: <module name>,
module: <module object ref>
dependsOn: [<module name>*],
dependedBy: [<module name>*],
}
currentModules()We resolve what we can using variables named with prefix module that hold module values. We forcePeek the variables to make them resolve, which forces loading of the modules.
modules imported via notebook imports do not have module variables, so they are trickier to figure out. We can sniff the page DOM to find the import expressions, and try to map them to the modules we could to resolve earlier