π¦ 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
- 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, and relative image workspace resolving; 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
- 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 |
| GitHub/Copilot | GitHub Models, Copilot Azure | Server-side proxy |
| 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)
- Provider-specific error handling with help dialogs
- Prompt API session retry loop β automatically retries
LanguageModel.create()while the model is still downloading, with availability rechecks between attempts
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, list_files, open_file, attach_file_to_chat, send_file, search_files, diff_files |
| Shell | bash (WebVM or just-bash emulator) |
| 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 CORS proxy) |
| 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), tools are also registered through the browser's Model Context Protocol (@mcp-b/webmcp-polyfill v3).
// get available tools
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
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
- Workspace-relative links β Links and images in pages resolve relative to the workspace
- Page sidebar β Persistent list of saved pages with optional toggle to hide the entire sidebar
- Default page β Configurable starting page shown on app launch
- Navigation β Click to view any saved page; page state persists across sessions
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.
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
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
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
- 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
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
- 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).
