setup
Run initial ClaudeClaw setup. Use when user wants to install dependencies, authenticate messaging channels, register their main channel, or start the background services. Triggers on "setup", "install", "configure claudeclaw", or first-time setup requests.
Best use case
setup is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Run initial ClaudeClaw setup. Use when user wants to install dependencies, authenticate messaging channels, register their main channel, or start the background services. Triggers on "setup", "install", "configure claudeclaw", or first-time setup requests.
Teams using setup should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/setup/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How setup Compares
| Feature / Agent | setup | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Run initial ClaudeClaw setup. Use when user wants to install dependencies, authenticate messaging channels, register their main channel, or start the background services. Triggers on "setup", "install", "configure claudeclaw", or first-time setup requests.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# ClaudeClaw Setup
Run setup steps automatically. Only pause when user action is required (channel authentication, configuration choices). Setup uses `bash setup.sh` for bootstrap, then `npx tsx setup/index.ts --step <name>` for all other steps. Steps emit structured status blocks to stdout. Verbose logs go to `logs/setup.log`.
**Principle:** When something is broken or missing, fix it. Don't tell the user to go fix it themselves unless it genuinely requires their manual action (e.g. authenticating a channel, pasting a secret token). If a dependency is missing, install it. If a service won't start, diagnose and repair. Ask the user for permission when needed, then do the work.
**UX Note:** Use `AskUserQuestion` for all user-facing questions.
## Mode Detection
Before any steps, detect the execution mode:
```bash
cat .claude-plugin/plugin.json 2>/dev/null | grep '"name": "claudeclaw"' && echo "DEVELOPER_MODE" || echo "PLUGIN_MODE"
```
If `.claude-plugin/plugin.json` exists in the current directory AND contains `"name": "claudeclaw"`, we're inside the ClaudeClaw repo → **Developer mode**. Otherwise, the skill was loaded via `--plugin-dir` → **Plugin mode**.
### Directory = Instance model
The current working directory IS the ClaudeClaw instance. All state (`.env`, `store/`, `groups/`, `logs/`) lives in cwd. Multiple instances = multiple directories. No hidden state, no `~/.claude/plugin-data/`.
**Plugin mode** (no `.claude-plugin/` in cwd):
- Skip step 0 (Git & Fork) entirely
- The current directory is the data directory — all state goes here
- Plugin code directory: `${CLAUDE_PLUGIN_ROOT}`
- Ensure data directories exist: `mkdir -p store groups logs`
- Check for `.claudeclaw.json` — if it exists, this directory has been set up before; if not, this is a fresh setup
**CRITICAL — Plugin mode command prefix:** All `npx tsx setup/index.ts` commands in subsequent steps MUST be run from the plugin code directory with `CLAUDE_PLUGIN_ROOT` set, but the working directory for the service must be the USER's current directory (the data dir). Use this pattern:
```bash
cd ${CLAUDE_PLUGIN_ROOT} && CLAUDECLAW_ENV_FILE=$(pwd)/.env npx tsx setup/index.ts --step <name>
```
Where `$(pwd)` resolves to the user's data directory BEFORE the `cd`. Store the data dir first:
```bash
MCLAW_PROJECT=$(pwd) && cd ${CLAUDE_PLUGIN_ROOT} && CLAUDECLAW_PROJECT_DIR=$MCLAW_PROJECT CLAUDECLAW_ENV_FILE=$MCLAW_PROJECT/.env npx tsx setup/index.ts --step <name>
```
`CLAUDECLAW_PROJECT_DIR` tells setup scripts the actual project directory (where `.env`, `store/`, `groups/`, `logs/` live). Without it, they fall back to `process.cwd()` which is the plugin code root after the `cd`.
**Developer mode** (`.claude-plugin/` in cwd):
- Proceed with all steps unchanged
- Code and state live in the same directory
## 0. Git & Fork Setup (Developer mode only)
**Plugin mode:** Skip this step entirely — there is no git repo to manage.
Check the git remote configuration to ensure the user has a fork and upstream is configured.
Run:
- `git remote -v`
**Case A — `origin` points to `sbusso/claudeclaw` (user cloned directly):**
The user cloned instead of forking. AskUserQuestion: "You cloned ClaudeClaw directly. We recommend forking so you can push your customizations. Would you like to set up a fork?"
- Fork now (recommended) — walk them through it
- Continue without fork — they'll only have local changes
If fork: instruct the user to fork `sbusso/claudeclaw` on GitHub (they need to do this in their browser), then ask them for their GitHub username. Run:
```bash
git remote rename origin upstream
git remote add origin https://github.com/<their-username>/claudeclaw.git
git push --force origin main
```
Verify with `git remote -v`.
If continue without fork: add upstream so they can still pull updates:
```bash
git remote add upstream https://github.com/sbusso/claudeclaw.git
```
**Case B — `origin` points to user's fork, no `upstream` remote:**
Add upstream:
```bash
git remote add upstream https://github.com/sbusso/claudeclaw.git
```
**Case C — both `origin` (user's fork) and `upstream` (qwibitai) exist:**
Already configured. Continue.
**Verify:** `git remote -v` should show `origin` → user's repo, `upstream` → `sbusso/claudeclaw.git`.
## 1. Bootstrap (Node.js + Dependencies)
**Plugin mode:** Dependencies are pre-installed in the plugin directory. Verify only:
- `node --version` (must be 20+)
- `ls dist/service.js` (must exist — if not, run `npm run build` in the plugin dir)
- If agent runner needs compilation: `cd agent/runner && npx tsc`
- Skip `bash setup.sh` entirely.
**Developer mode:** Run `bash setup.sh` and parse the status block.
- If NODE_OK=false → Node.js is missing or too old. Use `AskUserQuestion: Would you like me to install Node.js 22?` If confirmed:
- macOS: `brew install node@22` (if brew available) or install nvm then `nvm install 22`
- Linux: `curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs`, or nvm
- After installing Node, re-run `bash setup.sh`
- If DEPS_OK=false → Read `logs/setup.log`. Try: delete `node_modules`, re-run `bash setup.sh`. If native module build fails, install build tools (`xcode-select --install` on macOS, `build-essential` on Linux), then retry.
- If NATIVE_OK=false → better-sqlite3 failed to load. Install build tools and re-run.
- Record PLATFORM and IS_WSL for later steps.
## 2. Check Environment
Run `npx tsx setup/index.ts --step environment` and parse the status block.
- If HAS_AUTH=true → WhatsApp is already configured, note for step 5
- If HAS_REGISTERED_GROUPS=true → note existing config, offer to skip or reconfigure
- Record APPLE_CONTAINER and DOCKER values for step 3
## 3. Container Runtime
### 3a. Choose runtime
Check the preflight results for `APPLE_CONTAINER` and `DOCKER`, and the PLATFORM from step 1.
Use `AskUserQuestion` with options:
- **Sandbox (Recommended)** — OS-level sandboxing via `@anthropic-ai/sandbox-runtime`. <10ms cold starts, no container daemon needed, kernel-enforced isolation. macOS/Linux only.
- **Apple Container** — Native macOS container (if APPLE_CONTAINER=installed)
- **Docker** — Cross-platform container runtime
If **Sandbox** chosen:
- Run `npm install @anthropic-ai/sandbox-runtime` if not already installed
- Set `RUNTIME=sandbox` in `.env`
- Pre-compile agent runner: `cd agent/runner && npx tsc`
- Skip container build (3b, 3c) — go directly to step 4
If **Apple Container** or **Docker** chosen, continue with the container setup below:
- PLATFORM=linux → Docker (only option among container runtimes)
- PLATFORM=macos + APPLE_CONTAINER=installed → Apple Container or Docker
- PLATFORM=macos + APPLE_CONTAINER=not_found → Docker
### 3a-docker. Install Docker
- DOCKER=running → continue to 4b
- DOCKER=installed_not_running → start Docker: `open -a Docker` (macOS) or `sudo systemctl start docker` (Linux). Wait 15s, re-check with `docker info`.
- DOCKER=not_found → Use `AskUserQuestion: Docker is required for running agents. Would you like me to install it?` If confirmed:
- macOS: install via `brew install --cask docker`, then `open -a Docker` and wait for it to start. If brew not available, direct to Docker Desktop download at https://docker.com/products/docker-desktop
- Linux: install with `curl -fsSL https://get.docker.com | sh && sudo usermod -aG docker $USER`. Note: user may need to log out/in for group membership.
### 3b. Apple Container conversion gate (if needed)
**If the chosen runtime is Apple Container**, you MUST check whether the source code has already been converted from Docker to Apple Container. Do NOT skip this step. Run:
```bash
grep -q "CONTAINER_RUNTIME_BIN = 'container'" src/orchestrator/container-runtime.ts && echo "ALREADY_CONVERTED" || echo "NEEDS_CONVERSION"
```
**If NEEDS_CONVERSION**, the source code still uses Docker as the runtime. You MUST run the `/convert-to-apple-container` skill NOW, before proceeding to the build step.
**If ALREADY_CONVERTED**, the code already uses Apple Container. Continue to 3c.
**If the chosen runtime is Docker**, no conversion is needed. Continue to 3c.
### 3c. Build and test
Run `npx tsx setup/index.ts --step container -- --runtime <chosen>` and parse the status block.
**If BUILD_OK=false:** Read `logs/setup.log` tail for the build error.
- Cache issue (stale layers): `docker builder prune -f` (Docker) or `container builder stop && container builder rm && container builder start` (Apple Container). Retry.
- Dockerfile syntax or missing files: diagnose from the log and fix, then retry.
**If TEST_OK=false but BUILD_OK=true:** The image built but won't run. Check logs — common cause is runtime not fully started. Wait a moment and retry the test.
## 4. Claude Authentication (No Script)
If HAS_ENV=true from step 2, read `.env` and check for `CLAUDE_CODE_OAUTH_TOKEN` or `ANTHROPIC_API_KEY`. If present, confirm with user: keep or reconfigure?
AskUserQuestion: Claude subscription (Pro/Max) vs Anthropic API key?
**Subscription:** Tell user to run `claude setup-token` in another terminal, copy the token, add `CLAUDE_CODE_OAUTH_TOKEN=<token>` to `.env`. Do NOT collect the token in chat.
**API key:** Tell user to add `ANTHROPIC_API_KEY=<key>` to `.env`.
## 5. Set Up Channels
AskUserQuestion (multiSelect): Which messaging channels do you want to enable?
- WhatsApp (authenticates via QR code or pairing code)
- Telegram (authenticates via bot token from @BotFather)
- Slack (authenticates via Slack app with Socket Mode)
- Discord (authenticates via Discord bot token)
**Delegate to each selected channel's own skill.** Each channel skill handles its own code installation, authentication, registration, and JID resolution. This avoids duplicating channel-specific logic and ensures JIDs are always correct.
For each selected channel, invoke its skill:
- **WhatsApp:** Invoke `/add-whatsapp`
- **Telegram:** Invoke `/add-telegram`
- **Slack:** Invoke `/add-slack`
- **Discord:** Invoke `/add-discord`
Each skill will:
1. Install the channel code (via `git merge` of the skill branch)
2. Collect credentials/tokens and write to `.env`
3. Authenticate (WhatsApp QR/pairing, or verify token-based connection)
4. **Auto-detect the bot's display name** from the platform API and set `ASSISTANT_NAME` in `.env`
5. Register the chat with the correct JID format (trigger uses the detected bot name)
6. Build and verify
**IMPORTANT:** The channel skill sets `ASSISTANT_NAME` in `.env` based on the platform API (e.g., Slack's `auth.test` → `users.info`). This ensures the trigger pattern matches the bot's actual display name. Never hardcode a name or use the default.
**After all channel skills complete**, install dependencies and rebuild — channel merges may introduce new packages:
```bash
npm install && npm run build
```
If the build fails, read the error output and fix it (usually a missing dependency). Then continue to step 6.
## 6. Mount Allowlist
AskUserQuestion: Agent access to external directories?
**No:** `npx tsx setup/index.ts --step mounts -- --empty`
**Yes:** Collect paths/permissions. `npx tsx setup/index.ts --step mounts -- --json '{"allowedRoots":[...],"blockedPatterns":[],"nonMainReadOnly":true}'`
## 7. Start Service
The setup script generates a service whose WorkingDirectory is the current data directory. In plugin mode, the ExecStart points to `${CLAUDE_PLUGIN_ROOT}/dist/service.js`. Logs go to `<dataDir>/logs/`.
> **Service name:** Derived from the directory name: `com.claudeclaw.<dirname>` (macOS) / `claudeclaw-<dirname>` (Linux). For example, if cwd is `/home/user/my-assistant`, the service is `com.claudeclaw.my-assistant`. Determine the correct service name before running service commands below.
If service already running: unload first.
- macOS: `launchctl unload ~/Library/LaunchAgents/com.claudeclaw.plist`
- Linux: `systemctl --user stop claudeclaw` (or `systemctl stop claudeclaw` if root)
Run `npx tsx setup/index.ts --step service` and parse the status block.
**If FALLBACK=wsl_no_systemd:** WSL without systemd detected. Tell user they can either enable systemd in WSL (`echo -e "[boot]\nsystemd=true" | sudo tee /etc/wsl.conf` then restart WSL) or use the generated `start-claudeclaw.sh` wrapper.
**If DOCKER_GROUP_STALE=true:** The user was added to the docker group after their session started — the systemd service can't reach the Docker socket. Ask user to run these two commands:
1. Immediate fix: `sudo setfacl -m u:$(whoami):rw /var/run/docker.sock`
2. Persistent fix (re-applies after every Docker restart):
```bash
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/socket-acl.conf << 'EOF'
[Service]
ExecStartPost=/usr/bin/setfacl -m u:USERNAME:rw /var/run/docker.sock
EOF
sudo systemctl daemon-reload
```
Replace `USERNAME` with the actual username (from `whoami`). Run the two `sudo` commands separately — the `tee` heredoc first, then `daemon-reload`. After user confirms setfacl ran, re-run the service step.
**If SERVICE_LOADED=false:**
- Read `logs/setup.log` for the error.
- macOS: check `launchctl list | grep claudeclaw`. If PID=`-` and status non-zero, read `logs/claudeclaw.error.log`.
- Linux: check `systemctl --user status claudeclaw`.
- Re-run the service step after fixing.
## 8. Verify
Run `npx tsx setup/index.ts --step verify` and parse the status block.
**If STATUS=failed, fix each:**
- SERVICE=stopped → `npm run build`, then restart: `launchctl kickstart -k gui/$(id -u)/com.claudeclaw` (macOS) or `systemctl --user restart claudeclaw` (Linux) or `bash start-claudeclaw.sh` (WSL nohup)
- SERVICE=not_found → re-run step 7
- CREDENTIALS=missing → re-run step 4
- CHANNEL_AUTH shows `not_found` for any channel → re-invoke that channel's skill (e.g. `/add-telegram`)
- REGISTERED_GROUPS=0 → re-invoke the channel skills from step 5
- MOUNT_ALLOWLIST=missing → `npx tsx setup/index.ts --step mounts -- --empty`
Tell user to test: send a message in their registered chat. Show: `tail -f logs/claudeclaw.log`
## 9. Post-Setup Audit
After verify passes, run a deeper sanity check. This catches configuration mismatches that individual steps miss.
### 9a. Bot name consistency
For Slack channels, verify ASSISTANT_NAME matches the actual Slack bot display name:
```bash
# Get actual bot name from Slack API
SLACK_BOT_TOKEN=$(grep SLACK_BOT_TOKEN .env | cut -d= -f2)
BOT_USER_ID=$(curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" "https://slack.com/api/auth.test" | python3 -c "import sys,json; print(json.load(sys.stdin).get('user_id',''))")
ACTUAL_NAME=$(curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" "https://slack.com/api/users.info?user=$BOT_USER_ID" | python3 -c "import sys,json; u=json.load(sys.stdin).get('user',{}); p=u.get('profile',{}); print(p.get('display_name') or u.get('real_name') or u.get('name',''))")
# Get configured name
CONFIGURED_NAME=$(grep ASSISTANT_NAME .env | cut -d= -f2)
echo "Slack bot name: $ACTUAL_NAME"
echo "Configured name: $CONFIGURED_NAME"
```
If they don't match (or ASSISTANT_NAME is missing):
1. Set `ASSISTANT_NAME=$ACTUAL_NAME` in `.env`
2. Update all registered groups: `sqlite3 store/messages.db "UPDATE registered_groups SET trigger_pattern = '@$ACTUAL_NAME'"`
3. Restart the service
### 9b. Service points to correct directories
```bash
# macOS
PLIST=$(ls ~/Library/LaunchAgents/com.claudeclaw.*.plist 2>/dev/null | head -1)
if [ -n "$PLIST" ]; then
WORKING_DIR=$(plutil -extract WorkingDirectory raw "$PLIST" 2>/dev/null)
CURRENT_DIR=$(pwd)
echo "Plist WorkingDirectory: $WORKING_DIR"
echo "Current project dir: $CURRENT_DIR"
fi
```
If `WorkingDirectory` doesn't match the current project directory, the service is running from the wrong place. Re-run step 7.
### 9c. No state in plugin source
In plugin mode only — verify no state leaked into the plugin code directory:
```bash
PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT}
if [ -n "$PLUGIN_DIR" ]; then
LEAKED=""
[ -f "$PLUGIN_DIR/store/messages.db" ] && LEAKED="$LEAKED store/messages.db"
[ -d "$PLUGIN_DIR/groups" ] && [ "$(ls -A $PLUGIN_DIR/groups 2>/dev/null)" ] && LEAKED="$LEAKED groups/"
[ -f "$PLUGIN_DIR/logs/claudeclaw.log" ] && LEAKED="$LEAKED logs/claudeclaw.log"
if [ -n "$LEAKED" ]; then
echo "WARNING: State found in plugin source dir: $LEAKED"
echo "This data should be in the project dir, not the plugin code."
else
echo "OK: No state in plugin source dir"
fi
fi
```
If state leaked, move it to the project dir and clean the plugin source.
### 9d. Channel activation matches config
Check that only configured channels are active in the service logs:
```bash
echo "=== Channels that should be active ==="
grep 'SLACK_BOT_TOKEN' .env >/dev/null 2>&1 && echo "Slack: configured"
[ -f store/auth/creds.json ] && echo "WhatsApp: configured"
grep 'TELEGRAM_BOT_TOKEN' .env >/dev/null 2>&1 && echo "Telegram: configured"
echo "=== Channels in service logs ==="
grep -E 'Connected to|skipping|credentials missing' logs/claudeclaw.log | tail -10
```
If a channel shows "credentials missing — skipping" that's correct for unconfigured channels. If a channel crashes or loops, that's a bug.
### 9e. Summary
Print a final summary:
```
✓ Bot name: ClaudeDev (matches Slack API)
✓ Trigger: @ClaudeDev
✓ Service: com.claudeclaw.my-assistant (running, PID 12345)
✓ WorkingDirectory: /home/user/my-assistant
✓ Channels: Slack (connected)
✓ No state in plugin source
```
If any check fails, fix it before telling the user setup is complete.
## Troubleshooting
**Service not starting:** Check `logs/claudeclaw.error.log`. Common: wrong Node path (re-run step 7), missing `.env` (step 4), missing channel credentials (re-invoke channel skill).
**Container agent fails ("Claude Code process exited with code 1"):** Ensure the container runtime is running — `open -a Docker` (macOS Docker), `container system start` (Apple Container), or `sudo systemctl start docker` (Linux). Check container logs in `groups/main/logs/container-*.log`.
**No response to messages:** Check trigger pattern. Main channel doesn't need prefix. Check DB: `npx tsx setup/index.ts --step verify`. Check `logs/claudeclaw.log`.
**Channel not connecting:** Verify the channel's credentials are set in `.env`. Channels auto-enable when their credentials are present. For WhatsApp: check `store/auth/creds.json` exists. For token-based channels: check token values in `.env`. Restart the service after any `.env` change.
**Unload service:** macOS: `launchctl unload ~/Library/LaunchAgents/com.claudeclaw.plist` | Linux: `systemctl --user stop claudeclaw`Related Skills
x-integration
X (Twitter) integration for ClaudeClaw. Post tweets, like, reply, retweet, and quote. Use for setup, testing, or troubleshooting X functionality. Triggers on "setup x", "x integration", "twitter", "post tweet", "tweet".
use-local-whisper
Use when the user wants local voice transcription instead of OpenAI Whisper API. Switches to whisper.cpp running on Apple Silicon. WhatsApp only for now. Requires voice-transcription skill to be applied first.
update-skills
Check for and apply updates to installed skill branches from upstream.
update-claudeclaw
Efficiently bring upstream ClaudeClaw updates into a customized install, with preview, selective cherry-pick, and low token usage.
uninstall
Stop and remove the ClaudeClaw background service and agents for this instance
uninstall-extension
Uninstall a ClaudeClaw extension
qodo-pr-resolver
Review and resolve PR issues with Qodo - get AI-powered code review issues and fix them interactively (GitHub, GitLab, Bitbucket, Azure DevOps)
install-extension
Install a ClaudeClaw extension (e.g., slack, triage)
get-qodo-rules
Loads org- and repo-level coding rules from Qodo before code tasks begin, ensuring all generation and modification follows team standards. Use before any code generation or modification task when rules are not already loaded. Invoke when user asks to write, edit, refactor, or review code, or when starting implementation planning.
debug
Debug container agent issues. Use when things aren't working, container fails, authentication problems, or to understand how the container system works. Covers logs, environment variables, mounts, and common issues.
customize
Add new capabilities or modify ClaudeClaw behavior. Use when user wants to add channels (Telegram, Slack, email input), change triggers, add integrations, modify the router, or make any other customizations. This is an interactive skill that asks questions to understand what the user wants.
convert-to-apple-container
Switch from Docker to Apple Container for macOS-native container isolation. Use when the user wants Apple Container instead of Docker, or is setting up on macOS and prefers the native runtime. Triggers on "apple container", "convert to apple container", "switch to apple container", or "use apple container".