Claude
Skills
Sign in
Back

nanoclaw-ai-assistant

Included with Lifetime
$97 forever

```markdown

Writing & Docs

What this skill does

```markdown
---
name: nanoclaw-ai-assistant
description: Lightweight containerized AI assistant built on Anthropic's Agent SDK with multi-channel messaging (WhatsApp, Telegram, Slack, Discord, Gmail), memory, and scheduled jobs
triggers:
  - set up nanoclaw
  - add a messaging channel to nanoclaw
  - create a scheduled task in nanoclaw
  - how do I customize my nanoclaw assistant
  - debug nanoclaw not responding
  - add telegram to nanoclaw
  - configure nanoclaw docker sandboxes
  - nanoclaw agent skills
---

# NanoClaw AI Assistant

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.

NanoClaw is a lightweight, containerized AI assistant that runs Claude agents in isolated Linux containers (Docker or Apple Container). It connects to WhatsApp, Telegram, Slack, Discord, and Gmail, supports per-group memory via `CLAUDE.md` files, scheduled jobs, and is built directly on Anthropic's Agent SDK. The entire codebase is intentionally small (~handful of files) so you can read, understand, and customize it completely.

---

## Installation

### Prerequisites

- macOS or Linux
- Node.js 20+
- [Claude Code](https://claude.ai/download) (`claude` CLI)
- Docker Desktop **or** Apple Container (macOS)

### Quick Start

```bash
# Fork and clone
gh repo fork qwibitai/nanoclaw --clone
cd nanoclaw

# Open Claude Code — it handles everything else
claude
```

Then inside the `claude` prompt:

```
/setup
```

Claude Code installs dependencies, authenticates, configures containers, and registers services automatically.

### Docker Sandboxes (Recommended — macOS Apple Silicon)

```bash
curl -fsSL https://nanoclaw.dev/install-docker-sandboxes.sh | bash
```

**Windows (WSL):**

```bash
curl -fsSL https://nanoclaw.dev/install-docker-sandboxes-windows.sh | bash
```

---

## Environment Configuration

NanoClaw uses a `.env` file in the project root. Never commit this file.

```bash
# Required
ANTHROPIC_API_KEY=your_anthropic_api_key

# Optional: use a custom/compatible model endpoint
ANTHROPIC_BASE_URL=https://your-api-endpoint.com
ANTHROPIC_AUTH_TOKEN=your_token_here

# Optional: override the trigger word (default: @Andy)
TRIGGER_WORD=@Andy
```

---

## Architecture Overview

```
Channels --> SQLite --> Polling loop --> Container (Claude Agent SDK) --> Response
```

**Single Node.js process.** Key source files:

| File | Purpose |
|---|---|
| `src/index.ts` | Orchestrator: state, message loop, agent invocation |
| `src/channels/registry.ts` | Channel self-registration at startup |
| `src/ipc.ts` | IPC watcher and task processing |
| `src/router.ts` | Message formatting and outbound routing |
| `src/group-queue.ts` | Per-group queue with global concurrency limit |
| `src/container-runner.ts` | Spawns streaming agent containers |
| `src/task-scheduler.ts` | Runs scheduled tasks |
| `src/db.ts` | SQLite operations (messages, groups, sessions, state) |
| `groups/*/CLAUDE.md` | Per-group persistent memory |

---

## Claude Code Skills (In-Prompt Commands)

These are typed inside the `claude` CLI, **not** your terminal:

```
/setup                        # Full first-time setup
/add-whatsapp                 # Add WhatsApp channel
/add-telegram                 # Add Telegram channel
/add-gmail                    # Add Gmail integration
/customize                    # Guided customization wizard
/convert-to-apple-container   # Switch from Docker to Apple Container (macOS)
/debug                        # Diagnose issues
/clear                        # Compact conversation context (if skill installed)
```

---

## Adding Messaging Channels

Channels self-register at startup when credentials are present. Use skills to add them:

```
# Inside claude prompt:
/add-whatsapp
/add-telegram
/add-gmail
```

Each skill modifies the codebase and adds the necessary credential prompts. After running a skill, credentials are stored in `.env` and the channel activates on next startup.

### Channel File Structure

A channel lives in `src/channels/` and self-registers via the registry:

```typescript
// src/channels/registry.ts — how channels register themselves
import { ChannelRegistry } from './registry';

export interface Channel {
  name: string;
  poll(): Promise<IncomingMessage[]>;
  send(groupId: string, text: string): Promise<void>;
}

// Each channel file calls this at module load time
ChannelRegistry.register(myChannel);
```

Example channel skeleton (e.g. for a custom channel):

```typescript
// src/channels/my-channel.ts
import { ChannelRegistry } from './registry';
import type { Channel, IncomingMessage } from './types';

const myChannel: Channel = {
  name: 'my-channel',

  async poll(): Promise<IncomingMessage[]> {
    // Return new messages since last poll
    // Each message needs: { groupId, senderId, text, timestamp }
    if (!process.env.MY_CHANNEL_TOKEN) return [];
    // ... fetch logic
    return [];
  },

  async send(groupId: string, text: string): Promise<void> {
    // Send text back to the group/user
    // ...
  },
};

ChannelRegistry.register(myChannel);
```

---

## Talking to Your Assistant

Use the trigger word (default `@Andy`) from any connected channel:

```
@Andy what's on my calendar today?
@Andy summarize the last week of git commits in this repo
@Andy send me a Hacker News AI briefing every Monday at 8am
@Andy review docs/README.md and suggest improvements
```

### Main Channel (Self-Chat = Admin)

Your private self-chat is the admin channel. Use it to manage groups and tasks:

```
@Andy list all scheduled tasks
@Andy pause the Monday briefing task
@Andy show me all active groups
@Andy join the "Engineering" Slack group
```

---

## Scheduled Tasks

Tell the assistant to set up recurring jobs in natural language:

```
@Andy every weekday at 9am, send me a sales pipeline summary
@Andy every Friday at 5pm, review git history and update the README if there's drift
@Andy on the 1st of each month, generate an expense report from my receipts folder
```

Tasks are stored in SQLite and managed by `src/task-scheduler.ts`. They run Claude in a container and can message you back with results.

### Viewing and Managing Tasks via Code

```typescript
// src/db.ts — task operations (simplified)
import Database from 'better-sqlite3';
const db = new Database('nanoclaw.db');

// List all scheduled tasks
const tasks = db.prepare('SELECT * FROM scheduled_tasks WHERE active = 1').all();

// Pause a task
db.prepare('UPDATE scheduled_tasks SET active = 0 WHERE id = ?').run(taskId);
```

---

## Per-Group Memory

Each group has its own isolated `CLAUDE.md` at `groups/<group-id>/CLAUDE.md`. The agent reads this file at the start of every conversation in that group.

```markdown
<!-- groups/family-chat/CLAUDE.md -->
# Family Chat Context

- This is the family group. Keep responses warm and casual.
- Dad prefers bullet points.
- Weekly summary every Sunday at 6pm.
- Has access to: /mnt/shared/family-photos
```

To update memory, just tell the assistant:

```
@Andy remember that in this group, always respond in Spanish
@Andy update your memory: this group is for engineering standup, be concise
```

---

## Container Isolation

Every agent invocation spawns a fresh container. Only explicitly mounted directories are accessible — no access to the host filesystem by default.

```typescript
// src/container-runner.ts — simplified spawn logic
import { spawn } from 'child_process';

export async function runAgentInContainer(opts: {
  groupId: string;
  prompt: string;
  mounts: string[];   // e.g. ['~/Documents/work:/mnt/work:ro']
}) {
  const mountArgs = opts.mounts.flatMap(m => ['-v', m]);

  const proc = spawn('docker', [
    'run', '--rm',
    ...mountArgs,
    '-e', `ANTHROPIC_API_KEY=${process.env.ANTHROPIC_API_KEY}`,
    'nanoclaw-agent',
    '--prompt', opts.prompt,
  ]);

  // Stream output back via IPC filesystem watcher
}
```

To give an agent access to a folder, tell it (or modify `groups/<id>/CLAUDE.md`):

```
@Andy you now have access to my Obsidian vault at ~/Docume

Related in Writing & Docs