{"slug": "caged-code-vanilla-claude-code-binary-in-a-webpage", "title": "Caged Code – Vanilla Claude Code Binary in a Webpage", "summary": "A developer has released 'Caged Code', a webpage that embeds the vanilla Claude Code binary and connects it to a notebook environment via WebSocket, allowing users to run Claude Code through their Anthropic account or OpenRouter API endpoints, with defaults restricted to MiMo models. The tool, which is not endorsed by Anthropic, bridges a lopecode notebook to Claude Code and includes features such as variable watching, cell editing, and voice input/output.", "body_md": "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.\n\nLive values of variables being observed by Claude Code.\n\nBridges a lopecode notebook to Claude Code via WebSocket.\n\n```\nClaude Code CLI  ←MCP→  Channel Server  ←WS→  This Module (browser)\n```\n\n**Cell groups** (in dependency order):\n\n`cc_chat`\n\n(main interface), `cc_watch_table`\n\n(variable inspector)`cc_config`\n\n, `cc_notebook_id`\n\n, `cc_activity`\n\n, `cc_status`\n\n, `cc_messages`\n\n, `cc_watches`\n\n, `cc_module`\n\n, `voiceEnabled`\n\n`cc_find_module`\n\nresolves module names via `runtime.mains`\n\n`cc_serialize_value`\n\n(safe value→string for transport)`cc_watchers`\n\nobserves variables, debounces & sends updates`cc_handle_*`\n\n(one per MCP tool)`cc_command_handlers`\n\nroutes action→handler`cc_ws`\n\nmanages connect/pair/auto-reconnect and message dispatch`cc_change_forwarder`\n\nstreams cell edits, `cc_voice`\n\noptional speech I/O`currentModules`\n\n, `exportToHTML`\n\n, `compile`\n\n, `history`\n\n, runtime-sdk helpersReactive `Inputs.input()`\n\ncells holding connection state. These are the shared mutable atoms that UI and WebSocket cells read/write.\n\n`cc_find_module`\n\nresolves a module name (e.g. `\"@tomlarkworthy/exporter-3\"`\n\n) to a runtime Module object by polling `viewof currentModules.value`\n\nat call time (not reactively). `cc_serialize_value`\n\nsafely converts any runtime value to a truncated string for transport.\n\nSubscribes to Observable variables via `observe()`\n\n, debounces updates (1s), and forwards changes to Claude Code over the WebSocket. Also maintains the `cc_watches`\n\ntable UI.\n\nOne handler per MCP tool. Each receives a `cmd`\n\nobject and the Observable `runtime`\n\n, returns `{ok, result}`\n\nor `{ok:false, error}`\n\n. Handlers: get-variable, define-variable, define-cell, delete-variable, list-variables, list-cells, run-tests, create-module, delete-module, eval, fork, watch, unwatch.\n\n`cc_command_handlers`\n\nmaps action strings to handler functions. `cc_ws`\n\nmanages the WebSocket lifecycle: connect, pair with token, dispatch incoming messages (commands, replies, tool-activity), and auto-reconnect from the URL hash `cc=`\n\nparam or sessionStorage.\n\n`cc_change_forwarder`\n\npolls the local-change-history and streams new cell edits to Claude Code. `cc_voice`\n\nprovides optional speech recognition input and TTS output for hands-free pairing.\n\nSerialize literate computational notebooks with their dependancies into single [downloadable](#) files. Double click to open locally. No server required, works in a `file://`\n\ncontext for simplicity.\n\n`Inputs`\n\n, `htl`\n\n, `highlight`\n\n, `_`\n\n(lodash) and `markdown`\n\nare bundled for offline operation.Exporter improves upon [exporter 2](https://observablehq.com/@tomlarkworthy/exporter-2) by refactoring out Observable Javascript concepts, it works on the low level reprentation directly.\n\nTo put the exporter in one of your notebooks, first import the UI builder.\n\n``` js\nimport {exporter, forkAnchor, exportAnchor } from '@tomlarkworthy/exporter'\n```\n\nThen 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.\n\n``` js\nexporter({\n  handler: (action, state) => {}, // Optional UI click handler\n  style: undefined,// customer reference to a style DOM node or a string to insert as a style block\n  output: (out) => {}, // hook to get result of exporting\n  notebook_url: undefined,// hardcode the default notebook_url\n})\n```\n\nIf you want to export without a UI, use the function `exportToHTML`\n\n, see the [example](https://observablehq.com/@tomlarkworthy/export-to-html-example)\n\n``` js\nimport {exportToHTML } from '@tomlarkworthy/exporter'\nphp\nasync function exportToHTML({\n  mains = new Map(), // (name -> module) Map of main modules\n  runtime = _runtime,\n  options = {} // Object, export options, e.g. head, title\n} = {})\n```\n\nYou can also just use inline anchor tags: [forkAnchor()](#) or [downloadAnchor()](#)\n\nThe HTML file contains `<script>`\n\nblocks that hold content to serve internal network requests locally.\n\n```\n<script id=\"d/c2dae147641e012a@46\" \n        type=\"text/plain\"\n        data-encoding=\"base64+gzip\"\n        data-mime=\"application/javascript\"\n>\n...inline text or base64 string\n</script>\n```\n\nRequests to the URL matching the `id`\n\nare served locally, this includes `import`\n\n, `fetch`\n\n, `XMLHttpRequest`\n\nand `<script>`\n\nsrc attribute.\n\nThe 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`\n\n. `@tomlarkworthy/bootloader`\n\nis the default which comes with d3, Plot, md, htl and lodash local.\n\nTo help carry state across an export, the URL hash parameter is remembered in the `bootconf.json`\n\nand 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](https://observablehq.com/@tomlarkworthy/fileattachments) instead.\n\nThemes 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.\n\nSerialize a single module from the live runtime to a `.js`\n\nmodule source string. Unlike `module_specs`\n\n(which serializes all modules as part of the full HTML export pipeline), `exportModuleJS`\n\nworks on-demand against the live runtime with no `task`\n\ndependency.\n\n``` js\nimport {exportModuleJS} from \"@tomlarkworthy/exporter-3\"\nconst {source, fileAttachments} = await exportModuleJS(moduleId, {runtime, moduleNamesFn})\n```\n\n**Parameters**\n\n`moduleId`\n\n— module name string, e.g. `\"@tomlarkworthy/flow-queue\"`\n\n`options.runtime`\n\n— Observable runtime instance (default: `_runtime`\n\n)`options.moduleNamesFn`\n\n— function to build module name map (default: `buildModuleNames`\n\n)**Returns** `{source, fileAttachments}`\n\n`source`\n\n— full `.js`\n\nmodule source with `export default function define(runtime, observer)`\n\n`fileAttachments`\n\n— `Map<name, {url, mimeType}>`\n\nof the module's file attachments`()`\n\nFigures out the import structure of a runtime, just pass a runtime to the function `moduleMap`\n\nto get a summary of the modules. Returns a map indexed by a Module object to a record.\n\n``` php\nmodule -> {\n  type: \"notebook import\" | \"module variable\",\n  name: <module name>,\n  module: <module object ref>\n  dependsOn: [<module name>*],\n  dependedBy: [<module name>*],\n}\n```\n\n`currentModules`\n\n`()`\n\nWe resolve what we can using variables named with prefix `module`\n\nthat hold module values. We `forcePeek`\n\nthe variables to make them resolve, which forces loading of the modules.\n\nmodules 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", "url": "https://wpnews.pro/news/caged-code-vanilla-claude-code-binary-in-a-webpage", "canonical_source": "https://tomlarkworthy.github.io/lopebooks/notebooks/Caged_Code.html", "published_at": "2026-08-13 20:54:42+00:00", "updated_at": "2026-08-13 21:13:08.955985+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "artificial-intelligence"], "entities": ["Anthropic", "Claude Code", "OpenRouter", "MiMo", "lopecode", "Tom Larkworthy"], "alternates": {"html": "https://wpnews.pro/news/caged-code-vanilla-claude-code-binary-in-a-webpage", "markdown": "https://wpnews.pro/news/caged-code-vanilla-claude-code-binary-in-a-webpage.md", "text": "https://wpnews.pro/news/caged-code-vanilla-claude-code-binary-in-a-webpage.txt", "jsonld": "https://wpnews.pro/news/caged-code-vanilla-claude-code-binary-in-a-webpage.jsonld"}}