v0.0.10 · Pure JavaScript ESM · AGPL

Claude agents,
each in its own container.

jsclaw is the lightweight engine for autonomous Claude AI agents — isolated in Docker, woken by heartbeats, reachable from a browser or over Nostr. Zero dependencies, down to the WebSocket server.

$ npm install jsclaw Copied
Then: npx jsclaw gateway
0
Dependencies
~57 kB
Installed
109
Tests passing
1
Command to run
Capabilities

Everything an agent needs.
Nothing your bundler doesn't.

The host side is built entirely on Node.js built-ins — no native modules, no build step, no supply chain. You bring the I/O and storage; jsclaw brings the engine.

Container isolation by design

Every agent runs in its own Docker, Podman, or Apple container with an isolated filesystem. Not an optional sandbox — the architecture.

Heartbeat autonomy

Agents wake on an interval, read their HEARTBEAT.md, act if anything needs attention — and stay silent when it doesn't. Quiet hours included.

Scheduler with zero-dep cron

Cron, interval, and one-shot tasks — including a full 5-field cron parser in plain JavaScript. Agents schedule their own follow-ups.

Souls & identity

openclaw's identity stack — SOUL.md, IDENTITY.md, AGENTS.md, TOOLS.md, USER.md — loaded into the system prompt in order.

Memory in Markdown

Persistent context as plain files the agent edits itself — preferences.md, projects.md, custom categories. Human-readable, git-diffable.

Skills

Teach capabilities with SKILL.md files — YAML frontmatter, keyword / regex / attachment triggers, instructions injected only when they fire.

Pluggable channels

One small interface — connect, sendMessage, ownsJid — and the manager routes outbound messages to the right platform automatically.

Webhooks, both ways

Ingress with {{body.field}} templates and secret auth; egress on events like agent.task.completed. CI, Slack, PagerDuty, home automation.

Gateway & webchat

npx jsclaw gateway runs the whole host: WebSocket control plane in openclaw's wire shape, token auth, and a browser chat at /chat.

Nostr, natively

Your agent gets an npub. Encrypted DMs from any Nostr client — BIP340 Schnorr and NIP-04 in pure node:crypto, verified against the Bitcoin test vectors.

MCP passthrough

Declare any of the 32,000+ MCP servers in openclaw's mcp.servers shape and your agents get their tools — secrets via stdin, never ps-visible.

Mount security

Allowlist-validated volume mounts with symlink resolution. .ssh, .aws, .env and friends are blocked by default, always.

Run it

One command. A whole agent host.

The gateway wires everything — orphan reaping, scheduler, heartbeat, IPC — and exposes a WebSocket control plane in openclaw's frame shape, with a chat UI in your browser. The WebSocket server itself is hand-rolled RFC 6455 on Node built-ins: still zero dependencies.

jsclaw — zsh
$ npx jsclaw gateway

jsclaw gateway v0.0.10
  chat:    http://127.0.0.1:18789/chat?token=2f0a…
  ws:      ws://127.0.0.1:18789/?token=2f0a…
  agents:  main
  token:   2f0a… (generated; set JSCLAW_GATEWAY_TOKEN to pin)

Ctrl-C to stop.

Open the chat URL and talk to your containerized agent — or connect anything that speaks {type:"req", method:"chat.send"}: dashboards, scripts, other agents. Methods: status · chat.send · tasks.* · heartbeat.trigger · memory.*

Decentralized

Your agent has an npub.

DM it from Damus, Amethyst, or any Nostr client — encrypted NIP-04 DMs, no bot tokens, no platform accounts, no central server. The only claw runtime with a decentralized channel built in, and the whole stack — BIP340 Schnorr, NIP-04, bech32, relays — is node:crypto + native WebSocket.

import { createNostrChannel } from 'jsclaw';

const channel = createNostrChannel({
  privateKey: process.env.NOSTR_PRIVATE_KEY,        // hex or nsec
  relays: ['wss://relay.damus.io', 'wss://nos.lol'],
  allowedPubkeys: ['npub1you…'],                   // default-closed
  onMessage: (jid, text) => { /* run the agent, reply */ },
});

await channel.connect();
console.log('DM your agent at', channel.npub);

Every inbound event is signature-verified; only allowlisted pubkeys reach the agent. Schnorr signing is validated against the official BIP340 test vectors and cross-checked against node:crypto's independent secp256k1.

Architecture

A host process, a container,
and files between them.

Input goes in over stdin; results stream back as sentinel-delimited JSON. Everything else — messages, tasks, follow-ups — is atomic JSON files on a shared mount. No sockets to secure, no ports to leak.

HOST · YOUR APP container-runner spawns & streams scheduler · heartbeat cron, intervals, wake-ups ipc · queue · channels routing & concurrency skills · memory · webhooks CONTAINER · ISOLATED agent-runner drives the Claude SDK mcp-server send_message · schedule_task /workspace/agent SOUL.md · memory/ · HEARTBEAT.md isolated filesystem, own cwd stdin stdout ipc files data/ipc/{agent}/ messages/ tasks/ input/ /workspace/ipc/ messages/ tasks/ input/ same directory, two views
Quick start

From npm install to an agent with a pulse.

Plain JavaScript, granular imports, no compilation. These four snippets are the whole learning curve.

import { runContainerAgent, createConfig } from 'jsclaw';

const result = await runContainerAgent(
  { name: 'main', folder: 'main' },
  { prompt: 'Summarize the repos in my workspace.',
    agentId: 'main', chatJid: 'user-1', isMain: true },
  null,
  async (output) => console.log(output.result),  // streams as it works
  createConfig(),
);
import { TaskStore, createTaskIpcHandler, startTaskScheduler,
         startHeartbeat, startIpcWatcher, createConfig } from 'jsclaw';

const config = createConfig();
const store  = new TaskStore(config);

// Agents schedule their own work via the schedule_task MCP tool…
startIpcWatcher({ onTask: createTaskIpcHandler(store), /* … */ }, config);

// …the scheduler fires them (cron / interval / once)…
startTaskScheduler({ store, runTask: runAgentForTask }, config);

// …and the heartbeat wakes each agent to check HEARTBEAT.md.
startHeartbeat({ getAgents: () => agents, runAgent, onAlert },
  config, { quietHours: { start: '22:00', end: '07:00' } });
---
name: deploy-helper
description: "Helps with deployments"
trigger: "deploy|ship|push to prod"
tools: [shell, http]
---
# Deploy Helper

When asked to deploy:
1. Run the test suite first — abort on failure
2. Tag the release and push the tag
3. Report what shipped, in one line

# jsclaw skill install ./deploy.skill.md
# injected only when a message mentions deploy / ship
import { ChannelManager, startIpcWatcher, createConfig } from 'jsclaw';

const channels = new ChannelManager();
channels.register(telegramChannel);   // any object with the
channels.register(discordChannel);    // Channel interface

await channels.connectAll();

// Outbound routing by JID — agents' send_message just works
startIpcWatcher({
  sendMessage: channels.sendMessage,
  /* onTask, getRegisteredAgents */
}, createConfig());
Autonomy, on paper

Two Markdown files turn a chatbot
into a colleague.

Drop them in an agent folder. The agent reads both — one shapes who it is, the other tells it what to watch.

agents/main/SOUL.md identity

You are the colleague who actually gets things done.

Core truths
  • Results over process — don't explain, do.
  • Ownership — you own it end-to-end.
Boundaries
  • Skip "Great question!" — just help.
  • If you change this file, say so.
agents/main/HEARTBEAT.md standing orders
Every heartbeat
  • Check for failed deployments — alert me if any
  • Watch the inbox for anything from finance@
Daily, morning
  • Summarize my calendar in three lines
Weekly, Monday
  • Report open PRs older than a week
Command line

A CLI that works with no daemon running.

Tasks and memory are plain files, so npx jsclaw inspects and manages everything directly — no gateway process, no RPC, no port.

jsclaw — zsh
$ npx jsclaw status
jsclaw v0.0.10
  runtime:  docker (jsclaw-agent:latest)
  agents:   ./agents (2: main, research)
  tasks:    3 total, 2 active
    main: heartbeat, soul, memory

$ npx jsclaw tasks list
b2b5bf61  [active]  cron:0 9 * * 1-5  main  next: tomorrow 09:00
          Post the morning briefing to the channel

$ npx jsclaw skill test ./deploy.skill.md "ship the api"
MATCH  deploy-helper (trigger: deploy|ship|push to prod)

$ npx jsclaw heartbeat main
HEARTBEAT_OK
Where it fits

The lightweight engine in the claw family.

openclaw is the full platform. nanoclaw is the secure WhatsApp assistant it inspired. jsclaw is the engine underneath, repackaged as a library you can build anything on.

jsclawnanoclawopenclaw
ShapeLibrary + CLIPersonal assistant appFull agent platform
LanguagePure JS, no build stepTypeScriptTypeScript
Host dependencies0~7 (sqlite, baileys…)Many
Container isolation core design core designOptional sandbox
Heartbeat + schedulerScheduler only
SOUL.md · memory · skills · MCP openclaw-compatible
ChannelsNostr built in + interfaceWhatsApp, Telegram26+ built in
Gateway / web UI optional, one command required
API surface

Small modules. Import what you need.

Granular ESM exports — every module works standalone. Full reference in the README.

Ship an autonomous agent this afternoon.

One install, one Docker build, one Markdown file with standing orders.

$ npm install jsclaw Copied
See the Telegram example