@radnine/claude-session-daemon
v0.6.2
Published
Node.js daemon for managing Claude CLI sessions
Readme
@radnine/claude-session-daemon
Node.js daemon that manages Claude CLI sessions over WebSocket. Pairs with @radnine/storybook-addon-claude to give designers and developers an AI chat panel inside Storybook.
Install
npm install @radnine/storybook-addon-claude @radnine/claude-session-daemonConfigure Storybook
In your .storybook/main.js:
export default {
addons: [
'@radnine/storybook-addon-claude',
// ... other addons
],
};Run the Daemon
Option A: Docker (recommended)
Docker runs Claude inside a container with filesystem isolation. Claude can only access your mounted project directory, so file edits happen automatically without permission prompts.
- Create a
docker-compose.ymlin your project root:
services:
claude-daemon:
build:
context: ./node_modules/@radnine/claude-session-daemon
ports:
- "${CLAUDE_DAEMON_PORT:-3001}:3001"
volumes:
- .:/workspace
environment:
- ANTHROPIC_API_KEY
- CLAUDE_DAEMON_MODE=standalone
- CLAUDE_WORKING_DIR=/workspace
- CLAUDE_DAEMON_PORT=3001
- CLAUDE_SKIP_PERMISSIONS=true
- CLAUDE_DISABLE_AUTH=true
stop_grace_period: 10s
restart: unless-stopped- Add your API key to a
.envfile:
ANTHROPIC_API_KEY=sk-ant-...Get an API key from https://console.anthropic.com/settings/keys
- Start it:
docker compose up -dStop with docker compose down.
Option B: Host mode
Runs the daemon directly on your machine. Claude will prompt for permission on each file edit since there's no filesystem isolation.
npx @radnine/claude-session-daemon startOr add to your package.json scripts:
{
"scripts": {
"claude-daemon": "claude-session-daemon start",
"claude-daemon:stop": "claude-session-daemon stop",
"claude-daemon:restart": "claude-session-daemon restart",
"claude-daemon:status": "claude-session-daemon status"
}
}The daemon manages a .claude-daemon.pid file in your project root. Add it to your .gitignore.
Authentication (host mode only)
Docker mode uses the ANTHROPIC_API_KEY environment variable. For host mode, choose one:
API Key — Set ANTHROPIC_API_KEY before starting the daemon, or add it to a .env file.
Claude Login — If you have a Claude Pro, Team, or Enterprise subscription:
npx @anthropic-ai/claude-code loginThis authenticates via your browser. Credentials are stored locally and the daemon uses them automatically.
WebSocket Authentication (Shared Secret)
By default, the daemon allows unauthenticated connections from localhost and auto-generates a random token for non-localhost connections (logged on startup). This works for local development but not for remote environments like GitHub Codespaces where port forwarding proxies prevent the localhost bypass.
To configure a shared secret that both the daemon and addon use:
- Set
CLAUDE_AUTH_TOKENfor the daemon andSTORYBOOK_CLAUDE_DAEMON_TOKENfor Storybook:
# Generate a secret (or use any string)
export CLAUDE_SHARED_SECRET=$(openssl rand -hex 32)
# Daemon reads this
export CLAUDE_AUTH_TOKEN=$CLAUDE_SHARED_SECRET
# Storybook addon reads this
export STORYBOOK_CLAUDE_DAEMON_TOKEN=$CLAUDE_SHARED_SECRET- Inject the token into Storybook's manager frame via
managerHeadin your.storybook/main.js:
export default {
addons: ['@radnine/storybook-addon-claude'],
managerHead: (head) => {
const port = process.env.STORYBOOK_CLAUDE_DAEMON_PORT || 3001;
const token = process.env.STORYBOOK_CLAUDE_DAEMON_TOKEN || '';
return `${head}<script>window.__CLAUDE_DAEMON_PORT__ = ${port};${
token ? `window.__CLAUDE_DAEMON_TOKEN__ = "${token}";` : ''
}</script>`;
},
};The addon reads the token from window.__CLAUDE_DAEMON_TOKEN__ (most reliable in the Storybook manager frame) and falls back to process.env.STORYBOOK_CLAUDE_DAEMON_TOKEN.
GitHub Codespaces
In Codespaces, each forwarded port gets its own subdomain (e.g. codespace-name-3001.app.github.dev). The addon auto-detects this URL pattern and connects via wss:// instead of ws://localhost.
Setup:
- Add the shared secret env vars to your
devcontainer.json:
{
"containerEnv": {
"CLAUDE_SHARED_SECRET": "${localEnv:CLAUDE_SHARED_SECRET}"
},
"postStartCommand": "export CLAUDE_AUTH_TOKEN=$CLAUDE_SHARED_SECRET && export STORYBOOK_CLAUDE_DAEMON_TOKEN=$CLAUDE_SHARED_SECRET"
}Or generate a fresh secret on every Codespace start:
{
"postStartCommand": "export CLAUDE_SHARED_SECRET=$(openssl rand -hex 32) && export CLAUDE_AUTH_TOKEN=$CLAUDE_SHARED_SECRET && export STORYBOOK_CLAUDE_DAEMON_TOKEN=$CLAUDE_SHARED_SECRET"
}Set the daemon port to public visibility in the Codespaces Ports tab. The shared secret provides the auth layer — you don't need GitHub's proxy auth.
Add the
managerHeadinjection to your.storybook/main.js(see above).Start the daemon and Storybook as usual. The addon will automatically detect the Codespaces hostname and connect to
wss://codespace-name-PORT.app.github.dev.
Custom Skills
The addon's skills bar shows configurable shortcut buttons. Define them in a YAML file at .storybook/claude-skills.yml in your project:
skills:
- id: sync-components
label: Sync Components
icon: "↻"
type: prompt
prompt: "Synchronize all Storybook components with their Figma designs. Report what changed."
description: "Sync components with designs"
- id: run-tests
label: Run Tests
icon: "▶"
type: slash_command
command: /test
description: "Run the full test suite"
- id: audit-stories
label: Audit
icon: "🔍"
type: prompt
prompt: "Audit all components and list any that are missing Storybook stories or have outdated ones."
description: "Find missing or outdated stories"Each skill requires id, label, icon, and either prompt or command:
type: prompt(default) — sends theprompttext as a chat messagetype: slash_command— sends thecommandvalue (e.g./test) as a chat messagedescription— shown as a tooltip on hover; falls back topromptif omitted
If no YAML file is found, the addon falls back to built-in default skills. The dynamic PR skill (New PR / Finalize PR) is always included regardless of config — it's driven by git context, not YAML.
The daemon looks for the YAML file relative to its working directory. By default this is process.cwd(). If you run the daemon from a different directory than your Storybook project (e.g. via a Procfile from the repo root), set CLAUDE_WORKING_DIR to point to the directory containing .storybook/:
CLAUDE_WORKING_DIR=path/to/storybook-project claude-session-daemon startIn Docker mode, CLAUDE_WORKING_DIR should point to your mounted workspace (e.g. /workspace).
Environment Variables
| Variable | Default | Description |
|---|---|---|
| ANTHROPIC_API_KEY | — | Required for Docker mode |
| CLAUDE_WORKING_DIR | process.cwd() | Project root for skills config and git context |
| CLAUDE_DAEMON_PORT | 3001 | WebSocket server port |
| CLAUDE_AUTH_TOKEN | random UUID | Shared secret for WebSocket auth (see above) |
| CLAUDE_MAX_SESSIONS | 10 | Max concurrent Claude sessions |
| CLAUDE_LOG_LEVEL | info | Log level (debug, info, warn, error) |
| CLAUDE_SKIP_PERMISSIONS | false | Skip Claude CLI permission prompts (Docker only) |
| CLAUDE_DISABLE_AUTH | false | Disable WebSocket auth (Docker only) |
Addon-side variables (set when starting Storybook):
| Variable | Default | Description |
|---|---|---|
| STORYBOOK_CLAUDE_DAEMON_PORT | 3001 | Daemon port (or inject via window.__CLAUDE_DAEMON_PORT__) |
| STORYBOOK_CLAUDE_DAEMON_TOKEN | — | Shared secret (or inject via window.__CLAUDE_DAEMON_TOKEN__) |
License
Proprietary. See LICENSE for terms.
