π¦ ShadowClaw
A browser-native, fully-featured AI assistant. TypeScript + Web Components + IndexedDB + File System API.
npm install && npm run dev # Dev server β http://localhost:8888Open Settings, select a provider (or use browser Prompt API), and start chatting.
Desktop: npm run electron or npm run electron:build for distributable.
A fully-functional agent runtime that runs entirely in the browserβno AI processing on a server. Built with TypeScript, it provides:
- Multi-model support: OpenRouter, Anthropic, Google Gemini, AWS Bedrock, Ollama, Llamafile, Mesh LLM, Transformers.js, and browser-native Prompt API
- Web Components UI: Native Custom Elements + TC39 Signals for reactive updates
- Persistent storage: IndexedDB for messages/config, OPFS for files
- Agent tools: File I/O, shell (with optional WebVM), Git, HTTP, JavaScript execution
- Multi-conversation support: Each conversation has isolated chat history, file workspace, and scheduled tasks
- Messaging channels: Browser chat, PeerJS, Telegram Bot API, iMessage bridge (configurable)
- PWA + offline: Service Worker, Web Push notifications, scheduled task execution even when closed
- Desktop app: Electron wrapper with full parity to the web version
- Streaming responses β Token-by-token text updates with live chat bubble
- Dynamic context windowing β Token-aware message history (not fixed-size window)
- Tool profiles β Per-model/provider tool customization and system prompt overrides
- Conversation-scoped subagent policy β Per-conversation subagent mode (
automaticormanual) with optional pinned provider/model - Conversation-scoped agent token budget β Optional per-conversation max output tokens override (clamped to selected model limits)
- Conversation-scoped provider runtime overrides β Per-conversation runtime overrides for Bedrock proxy and Llamafile (auth/profile/region/host/mode/offline/port)
- Model registry β Dynamic metadata fetch (context window, modality support)
- Attachment capabilities β Native multimodal delivery with automatic text fallback
- Remote MCP β Discover and execute tools from external MCP servers
- A2UI interactive surfaces β Render responsive UI components (Text, Button, TextField, Row/Column layouts) from agents via PeerJS WebRTC with two-way data binding
- Multi-Agent Shared State β Synchronize agent knowledge across participants using
STATE_SNAPSHOTandSTATE_DELTAevents - Email integration β IMAP/SMTP support with encrypted credentials
- Web Share Target β Receive files/URLs directly from OS share sheet
- Scheduled tasks β Cron expressions with server-side persistence and Web Push
- Git integration β Clone, branch, merge (with conflict reports), push/pull
- File viewer β Syntax highlighting (locally bundled CSS, no CDN), PDF preview, media playback, Web Share, native/fallback fullscreen, relative image workspace resolving, and configurable iframe embed sanitization; iframe sandbox hardened (no
allow-same-origin) - Files browser β Clipboard-driven Cut/Copy/Paste actions, hidden Paste button when empty, folder self-paste protection, inter-group transfers, and conflict resolution (rename/overwrite)
ShadowClaw follows a worker-isolated runtime pattern:
graph TD
UI["Web Components<br>Chat, Files, Tasks"]
Orchestrator["Orchestrator<br>State Machine + Queue"]
Worker["Agent Worker<br>LLM + Tool Loop"]
Providers["Providers<br>OpenRouter, Bedrock, etc."]
Tools["Tool Execution<br>Bash, Git, Files, Fetch"]
UI --> Orchestrator
Orchestrator --> Worker
Worker --> Providers
Worker --> Tools
DB["IndexedDB<br>Messages, Config, Tasks"]
FS["OPFS<br>Workspace Files"]
Orchestrator --> DB
Orchestrator --> FS
SW["Service Worker<br>PWA, Push, Scheduling"]
UI --> SW
Key design principles:
- Agent in Web Worker β LLM calls, tool execution, and WebVM all run off-main-thread to keep UI responsive
- Message-based protocol β Strict
postMessageboundaries between main thread and worker - Reactive signals β TC39 Signals (via
signal-polyfill) drive all UI updates - Storage isolation β Each conversation gets a workspace (
shadowclaw/<groupId>/workspace/); shared config in IndexedDB
Full architecture docs: See Architecture for orchestrator state machine, worker protocol, storage system, context management, and streaming.
Each conversation has:
- Independent chat history
- Isolated file workspace
- Scheduled tasks
- Editable
MEMORY.md(loaded as system context) - Optional per-conversation tool tagging
- Optional per-conversation pinned provider/model and max output tokens
- Accessible sidebar with drag-and-drop reordering and clone support
- Unread indicators with pulsing highlights
Last-active conversation persists across reloads. On first launch, a default "Main" conversation is auto-created.
Full guide: docs/architecture/orchestrator.md
ShadowClaw supports multiple LLM providers with a unified adapter pattern:
| Category | Examples | Notes |
|---|---|---|
| Cloud | OpenRouter, OpenAI, Anthropic, Google Gemini, AWS Bedrock, Vertex AI | API key required |
| Local | Ollama, Llamafile, Mesh LLM, Transformers.js | Runs on local server or in-browser |
| Browser | Prompt API (window.LanguageModel), LiteRT |
Experimental, keyless, Gemini Nano |
Features:
- Streaming responses (OpenAI + Anthropic formats)
- Adaptive rate limiting with
retry-aftersupport - Dynamic model registry with capability metadata (context, modalities, tool support)
- Multi-format support (OpenAI, Anthropic, Prompt API)
- Prompt API session retry loop & hardware feature probing β automatically probes WebGPU adapter capabilities (requiring
shader-f16support), retriesLanguageModel.create()during downloads, and dynamically falls back to WebAssembly CPU (device: "wasm",dtype: "q4") if WebGPU initialization fails or software emulation is detected. - Polyfill model cache β Service Worker
CacheFirstcaching strategy stores Hugging Face polyfill model binaries (.onnx,.onnx_data) for offline performance
Setup & details: docs/guides/adding-a-provider.md | docs/subsystems/providers.md
The agent has access to 50+ tools including:
| Category | Tools |
|---|---|
| Files | read_file, write_file, patch_file, delete_file, move_file, copy_file, create_directory, list_files, open_file, attach_file_to_chat, send_file, search_files, diff_files |
| Shell | bash (WebVM or just-bash emulator) |
| Built-in AI | summarize_text, write_text, rewrite_text, proofread_text, detect_language, translate_text (defaults to Active Conversation LLM backend with opt-in local browser Task API polyfill) |
| Git | git_clone, git_init, git_add, git_unstage, git_commit, git_push, git_pull, git_fetch, git_merge, git_diff, and more |
| Web | fetch_url, fetch_file, web_search (DuckDuckGo via configurable CORS search proxy and URL templates) |
| Compute | javascript (sandboxed) |
| Agents | spawn_subagent (parallel task delegation), ask_user (human-in-the-loop pause) |
| Time | get_current_time (ISO 8601 or IANA timezone) |
| Tasks | create_task, list_tasks, update_task, delete_task, enable_task, disable_task, run_task |
| UI | show_toast, send_notification, clear_chat |
| Context | update_memory (edits MEMORY.md) |
| Remote | remote_mcp_list_tools, remote_mcp_call_tool (external MCP servers) |
manage_email, email_read_messages, email_send_message |
|
| Rooms | create_room, invite_to_room, leave_room, list_room_members |
| A2UI | list_components, render_component |
WebMCP integration: When document.modelContext is available (with navigator.modelContext fallback for Chrome < 152), tools are also registered through the browser's Model Context Protocol (@mcp-b/webmcp-polyfill v3). ShadowClaw provides parseWebMcpInputSchema to normalize input schemas across Chrome 154+ (native object) and Chrome < 154 (DOMString JSON) versions, and getWebMcpTools() to safely query registered tools with graceful degradation.
// get available tools (safely normalizes input schemas across Chrome versions)
var tools = await document.modelContext.getTools();
// format the tool list
var formattedToolsJSON = JSON.stringify(
tools.map(
({ annotations, description, inputSchema, name, origin, title }) => ({
annotations,
description,
inputSchema,
name,
origin,
title,
}),
),
null,
2,
);
// list available tools
console.log(formattedToolsJSON);
// get the toast tool
var [toastTool] = tools.filter((v) => v.description.includes("Show a toast"));
// run the toast tool
await document.modelContext.executeTool(
toastTool,
'{ "message": "Hello from π¦ Shadow Claw!"}',
);Full reference: docs/subsystems/tools.md | docs/subsystems/webmcp.md
ShadowClaw supports four messaging channels by default:
br:β In-browser chatim:β iMessage bridgepeer:β PeerJS WebRTC (includes Peer Rooms for multi-agent collaboration)tg:β Telegram Bot API
Each channel creates isolated conversations with their own message history and workspace.
Setup & architecture: docs/guides/configuring-messaging-channels.md (setup) | docs/subsystems/channels.md (architecture + custom channels)
ShadowClaw includes a Pages sidebar for organizing and viewing workspace content.
- Render markdown & HTML β Save any markdown or HTML file as a page for structured preview, including optional visible YAML frontmatter metadata
- Workspace-relative links β Links and images in pages resolve relative to the workspace
- Page sidebar β Persistent list of saved pages with drag-and-drop reordering and responsive mobile sidebar collapse
- Static Main Site Seeding β Automatically seeds default main pages from the
pages/main/manifest, respecting page suppression rules - Static Pretty Paths & DSD Pre-rendering β Build-time pre-rendering for
pages/routes.jsongenerates static HTML with Declarative Shadow DOM templates for clean URLs across Node.js, Electron, and GitHub Pages (pages flagged for purge are excluded from the output manifest); same-origin links are validated viaisPossibleAppRouteso non-app paths fall back to native browser navigation - Page Suppression β Deleting pages suppresses auto-reseeding (
SUPPRESSED_PAGES_LIST) until re-added - Safe iframe embeds β HTML previews use a configurable iframe host allowlist in Settings, with safe defaults for common embedded content hosts
- Ebook-Style Navigation β Functional Previous/Next pagination controls with HTML-entity decoded frontmatter headers, seamless page transitions,
ArrowLeft/ArrowRightkeyboard navigation, touch/mouse swipe gestures, andaria-livescreen reader announcements - Pre-rendered Content Override β Optional setting (
OVERRIDE_PRERENDER_SKELETON) suppresses Declarative Shadow DOM (DSD) pre-rendered content during boot to eliminate hydration flash - Declarative Site Configuration β Support for
site-config.jsonenabling template repositories to customize site metadata, branding, custom theme stylesheets, custom element security allowlists, and navigation visibility without modifying core source - Dynamic Sidebar Navigation Visibility β Runtime toggling of Pages, Chat, Tasks, and Files sidebar tabs via Settings, with automatic fallback routing and build-time DSD navigation attribute synchronization
- Content-Only Publishing β Supports GitHub Pages publishing via the
shadow-claw-templatetemplate repository that pulls ShadowClaw as a CI-time build dependency.
Pages complement the main group MEMORY (auto-created as MEMORY.md on first setup) which serves as a workspace-scoped system context for the agent. An index.html is also auto-created as the default home page.
For advanced bash operations, ShadowClaw includes an optional WebVM (v86 Alpine Linux) that runs in the Web Worker.
- Boot modes:
auto(9p, lighter weight),ext2(full filesystem), ordisabled(fallback to JavaScript shell) - Coordination: Terminal sessions and tool execution share exclusive access with graceful handoffs
- Workspace sync: 9p mode syncs VM
/workspacechanges back to OPFS so Files view stays in sync - Interactive terminal: Full shell access via
<shadow-claw-terminal>component
Full guide: docs/subsystems/vm.md
ShadowClaw uses IndexedDB for structured data (messages, config, tasks) and OPFS for files.
Security:
- AES-256-GCM encryption for API keys at rest
- TC39 private fields to prevent accidental leakage via console
- 30-second key expiry for plaintext operations
- No plaintext secrets on disk β encrypted before storage
- Trusted Types enforcement β idempotent
"default"policy (src/security/default-trusted-types-policy.ts) registered at boot viatheme-init.ts;getPolicy()fallback prevents duplicate-creation errors on module reload - Custom element security guards β
installCustomElementsRegistryGuardandinstallCustomElementDomGuardprevent unauthorized custom element registration and dynamic DOM injection, strictly enforcing allowlists fromsite-config.jsonor storage - Iframe sandbox & CSP hardening β sandboxed preview iframes omit
allow-same-originby default and apply a nonce-gated Content Security Policy with domain restrictions - Iframe embed sanitization β DOMPurify-based iframe allowlisting protects markdown and HTML previews, with Settings-backed host patterns and a safe default host list
- SSRF proxy hardening β
/proxyblocks non-HTTP/S schemes and private/loopback IP ranges by default; bypassed via--allow-private-proxyflag or the authenticated service-worker JSON format - Prompt injection defense β external tool outputs (
fetch_url,web_search,remote_mcp_call_tool) are structurally wrapped inUNTRUSTEDdelimiters; system prompt includes explicit anti-injection instructions when untrusted-content tools are active
File I/O:
- OPFS β browser-sandboxed storage (
shadowclaw/<groupId>/workspace/) - Local Folder β user-selected directory via File System Access API
- Centralized write paths β cross-browser fallback for Safari compatibility
- Zip export/import β for conversation backup/restore
- Copy/move safety β folder copy/move operations prevent pasting a folder into itself or one of its descendants, and support inter-group operations with conflict resolution
Full details: docs/architecture/storage.md | docs/subsystems/crypto.md | docs/subsystems/custom-element-security.md
ShadowClaw supports cron-based scheduled tasks with Web Push notifications. Tasks fire even when the app is closed.
- Task expressions use standard 5-field cron syntax
- Task sequences β Execute a single text prompt, or sequentially run a list of agent tools
- Server-side persistence β SQLite database ensures reliable firing (can be toggled via Settings)
- Web Push integration β OS-level notifications when tasks trigger
- Recursion guard β prevents infinite task β notification β task loops
- Client/Server parity β Express dev server and Electron both support full scheduling
- Fresh Context & Subagent isolation β Toggle task execution to bypass conversation history (fresh context) or run isolated in the background (subagent)
Setup & architecture: docs/subsystems/notifications.md
Connect external Model Context Protocol (MCP) servers to extend agent capabilities dynamically. Tools from remote servers are discovered and executed transparently.
- Bearer, Basic, and custom header authentication
- OAuth token refresh support
- Automatic reconnection on failure
Full guide: docs/subsystems/remote-mcp.md
Email (IMAP/SMTP), RSS, webhooks, and other integrations via a plugin architecture.
- Encrypted credential storage
- Typed action dispatch
- Configurable plugin catalog
Full guide: docs/guides/protocol-agnostic-integrations.md
Receive files, URLs, and text directly from your OS share sheet into ShadowClaw.
- Supported on all PWA-capable browsers and Android
- Files are persisted to workspace
- Auto-opens dated conversation with imported files
Full details: manifest.json | src/service-worker/share-target.ts
Create model-specific or task-specific tool profiles to optimize the context window.
- Enable/disable individual tools
- Override system prompt per profile
- Auto-activate profiles by model
- Save custom selections
- Built-in Profile β Default Prompt API profile is restricted to core file and script tools (
javascript,list_files,open_file,read_file,write_file) - Execution-time allowlist enforcement β Tool calls are re-validated at runtime against the active enabled tool list (profile/manual), not only generation-time schema hints
- Shared internet access control β Toggles public internet access (
fetchand shell networking) globally for thebashandjavascripttools
Full guide: docs/subsystems/tools.md
Native multimodal delivery with automatic text fallback.
- Model registry fetches capability metadata dynamically
- Attachments sent as native content blocks when supported
- Automatic fallback to OCR/markdown for unsupported formats
Full details: docs/subsystems/attachment-capabilities.md
Instead of fixed-size message windows, context is token-aware and adaptive.
- System prompt + max output tokens budgeted first
- Messages walked newest-to-oldest within budget
- Large outputs truncated at line boundaries
- UI progress bar tracks context usage
- Token estimation & cache tracking β Tracks token usage and cache hits/misses across context window
- Auto-compaction triggers at 80% usage
Full details: docs/architecture/context-management.md
Architecture docs, subsystem guides, and decision records live in docs/:
- Architecture β Orchestrator, worker protocol, storage, context, streaming
- Subsystems β Shell, VM, git, channels, tools, providers, notifications, Electron, reactive UI, crypto
- Guides β Adding providers, tools, shell commands, pages, channels
- Decisions β ADRs for bundled architecture, TypeScript, Signals, worker-owned VM, IndexedDB
Agent-specific conventions and guardrails: AGENTS.md
E2E test architecture: e2e/README.md
npm run dev # Dev server (watch mode)
npm start # Express server
npm test # Jest (*.test.ts files live next to source)
npm run e2e # Playwright E2E tests (e2e/*.test.ts)
npm run e2e:install # Install Playwright browser binaries
npm run tsc # TypeScript type-check
npm run build # Bundle application via Rolldown + generate service worker
npm run build:service-worker # Generate the Workbox service worker
npm run build:prod # Production bundle build
npm run format # Prettier
npm run electron # Launch Electron desktop app
npm run electron:build # Build Electron distributable
npm run electron:build:win # Build Electron for Windows
npm run electron:build:mac # Build Electron for macOSAGPLv3. Core logic derived from openbrowserclaw (MIT).
