@misbahsy/clawkit-lite
v0.1.0
Published
Minimal agent kit — any provider, any channel, any skills
Readme
ClawKit Lite
Minimal agent kit — any provider, any channel, any skills.
ClawKit Lite is a ~1,000-line kit for building conversational AI agents. Clone it, pick your channel (Telegram, WhatsApp, ...), pick your provider (Claude, OpenAI Codex, Pi, ...), add skills, and run. No Docker, no framework overhead — just a message bus with pluggable parts.
[Channel] → message in → [Runtime] → [Provider] → response → [Channel]
↑
[Skills]
(instructions + MCP tools)Quick Start
git clone https://github.com/misbahsy/ClawKit-lite.git
cd ClawKit-lite
npm install
# Option A: Interactive setup via Claude Code
claude
# then type: /setup
# Option B: Manual setup
cp .env.example .env
# Edit .env with your API keys and tokens
# Edit clawkit.config.ts to pick your channel + provider
npm install grammy # for Telegram
npm install @anthropic-ai/claude-agent-sdk # for Claude
npm run devHow It Works
Three Pluggable Interfaces
Everything in ClawKit Lite implements one of three interfaces:
// Channel — produces messages, sends responses
interface Channel {
name: string;
connect(): Promise<void>;
disconnect(): Promise<void>;
onMessage(cb: (msg: IncomingMessage) => void): void;
sendMessage(to: string, text: string): Promise<void>;
setTyping?(to: string, isTyping: boolean): Promise<void>;
}
// Provider — takes a prompt, returns streamed responses
interface Provider {
name: string;
run(params: {
prompt: string;
systemPrompt: string;
sessionId?: string;
mcpServers?: Record<string, McpServerConfig>;
}): AsyncIterable<ProviderEvent>;
}
// Skill — instructions + optional MCP server
interface Skill {
name: string;
instructions: string; // loaded from SKILL.md
mcpServer?: McpServerConfig; // optional tool server
}Configuration
All configuration lives in a single file — clawkit.config.ts:
import { telegram } from "./src/channels/telegram.js";
import { claude } from "./src/providers/claude.js";
export default {
name: "my-agent",
channel: telegram({ token: process.env.TELEGRAM_BOT_TOKEN! }),
provider: claude({ model: "claude-sonnet-4-20250514" }),
skills: ["./src/skills/scheduler"],
systemPrompt: "./workspace/CLAUDE.md",
};To switch to WhatsApp + OpenAI Codex, change two imports:
import { whatsapp } from "./src/channels/whatsapp.js";
import { codex } from "./src/providers/codex.js";
export default {
name: "my-agent",
channel: whatsapp({ storePath: "./store/whatsapp-auth" }),
provider: codex({ model: "codex-mini-latest" }),
skills: ["./src/skills/scheduler"],
systemPrompt: "./workspace/CLAUDE.md",
};Environment Variables
Secrets go in .env (gitignored), never in config files:
# Channel tokens
TELEGRAM_BOT_TOKEN=your-bot-token-here
# WHATSAPP_STORE_PATH=./store
# Provider keys
ANTHROPIC_API_KEY=your-key-here
# OPENAI_API_KEY=your-key-here
# PI_API_KEY=your-key-here
# PI_SERVER_URL=http://localhost:8080Channels
Telegram
Uses grammy. Requires a bot token from @BotFather.
npm install grammyimport { telegram } from "./src/channels/telegram.js";
telegram({ token: process.env.TELEGRAM_BOT_TOKEN! })Features:
- Polling-based (no webhook setup needed)
- Automatic message chunking (4096 char limit)
- Typing indicators
- Group chat support
- Outgoing message queue with retry on disconnect
Uses Baileys. Authenticates via QR code scan.
npm install baileys @hapi/boom pino qrcode-terminalimport { whatsapp } from "./src/channels/whatsapp.js";
whatsapp({ storePath: "./store/whatsapp-auth" })Features:
- QR code authentication (displayed in terminal)
- Session persistence (survives restarts)
- LID-to-phone JID translation
- Exponential backoff reconnection (up to 30s)
- Markdown-to-WhatsApp formatting conversion
- Typing/presence indicators
- Group chat support
Adding a Custom Channel
Create src/channels/my-channel.ts:
import type { Channel } from "../types.js";
export function myChannel(config: { /* your config */ }): Channel {
return {
name: "my-channel",
async connect() { /* connect to service */ },
async disconnect() { /* cleanup */ },
onMessage(cb) { /* wire up message listener, call cb() */ },
async sendMessage(to, text) { /* send response */ },
async setTyping(to, isTyping) { /* optional typing indicator */ },
};
}Providers
All providers are agent SDKs — full coding agent runtimes, not raw LLM APIs. They handle tool use, file access, and bash execution natively.
Claude (Agent SDK)
Uses @anthropic-ai/claude-agent-sdk. The same SDK that powers Claude Code.
npm install @anthropic-ai/claude-agent-sdkimport { claude } from "./src/providers/claude.js";
claude({
model: "claude-sonnet-4-20250514", // default
maxTurns: 10, // max agent turns per message
permissionMode: "bypassPermissions", // autonomous operation
cwd: "/path/to/workspace", // optional working directory
})Features:
- Session resume (conversations persist across messages)
- MCP server passthrough (skill tools available to agent)
- Built-in tools: Bash, Read, Write, Edit, Glob, Grep, WebSearch
- Auth:
ANTHROPIC_API_KEYenv var orclaude login(OAuth)
OpenAI Codex CLI
Uses @openai/codex. OpenAI's agent with built-in sandboxed execution.
npm install @openai/codeximport { codex } from "./src/providers/codex.js";
codex({
model: "codex-mini-latest", // default
})Features:
- Single-call execution (prompt in, response out)
- Built-in sandbox for bash
- Flexible response parsing
- Auth:
OPENAI_API_KEYenv var
Pi Agent
HTTP-based streaming agent used by OpenClaw. Supports self-hosted or cloud Pi servers.
npm install @mariozechner/pi-agent-coreimport { pi } from "./src/providers/pi.js";
pi({
model: "pi-default",
baseUrl: "http://localhost:8080", // Pi server URL
maxTokens: 4096,
modelFailover: ["fallback-model"], // try these if primary fails
compactionThreshold: 100, // summarize after N messages
})Features:
- Server-sent events (SSE) streaming
- Model failover (automatic fallback)
- Session compaction (summarizes old messages)
- Auth:
PI_API_KEYandPI_SERVER_URLenv vars
Adding a Custom Provider
Create src/providers/my-provider.ts:
import type { Provider, ProviderEvent } from "../types.js";
export function myProvider(config: { /* your config */ }): Provider {
return {
name: "my-provider",
async *run({ prompt, systemPrompt, sessionId, mcpServers }) {
// Call your agent SDK here
const response = await callMyAgent(prompt);
yield { type: "text", text: response };
yield { type: "done", sessionId: "new-session-id" };
},
};
}Skills
Skills extend your agent with instructions and tools. Each skill is a directory with:
src/skills/my-skill/
├── SKILL.md # Instructions the agent reads (added to system prompt)
└── server.ts # Optional MCP server providing toolsBuilt-in: Scheduler
Schedule recurring tasks with cron expressions.
src/skills/scheduler/
├── SKILL.md # Tells agent how to use scheduling tools
└── server.ts # MCP server: schedule_task, list_tasksExample interactions:
- "Remind me every morning at 9am to check email" → creates cron job
0 9 * * * - "Every Friday at 5pm, send a weekly summary" → creates cron job
0 17 * * 5 - "What tasks are scheduled?" → lists all active tasks
Adding a Custom Skill
Create the directory:
mkdir -p src/skills/my-skillWrite instructions in
SKILL.md:## My Skill You can do X, Y, Z. ### Available tools - **my_tool**: Does something useful - `param1`: DescriptionOptionally create an MCP server in
server.ts:import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; const server = new McpServer({ name: "my-skill", version: "1.0.0" }); server.tool("my_tool", "Does something useful", { param1: z.string().describe("Description"), }, async ({ param1 }) => { return { content: [{ type: "text", text: `Result: ${param1}` }] }; }); const transport = new StdioServerTransport(); server.connect(transport);Register in config:
skills: ["./src/skills/scheduler", "./src/skills/my-skill"],Restart:
npm run dev
Project Structure
clawkit-lite/
├── src/
│ ├── index.ts # Entry point
│ ├── runtime.ts # Message bus (channel → provider → channel)
│ ├── types.ts # Channel, Provider, Skill interfaces
│ ├── config.ts # Load .env + config file
│ ├── db.ts # SQLite: messages, sessions, tasks
│ ├── channels/
│ │ ├── telegram.ts # Telegram adapter (grammy)
│ │ └── whatsapp.ts # WhatsApp adapter (baileys)
│ ├── providers/
│ │ ├── claude.ts # Claude Agent SDK adapter
│ │ ├── codex.ts # OpenAI Codex CLI adapter
│ │ └── pi.ts # Pi Agent adapter
│ └── skills/
│ └── scheduler/
│ ├── SKILL.md # Scheduling instructions
│ └── server.ts # MCP server: schedule_task, list_tasks
├── workspace/
│ └── CLAUDE.md # System prompt (agent identity + rules)
├── setup/
│ ├── bootstrap.sh # Environment checks
│ └── index.ts # Setup step runner
├── tests/
│ ├── helpers.ts # Mock channel, provider, message factories
│ ├── db.test.ts # Database layer tests
│ └── runtime.test.ts # Runtime integration tests
├── store/ # Auth state, SQLite database (gitignored)
├── clawkit.config.ts # User configuration
├── .env.example # Environment variable template
├── .env # Your secrets (gitignored)
├── package.json
└── tsconfig.jsonRuntime Details
Message Bus
The runtime (src/runtime.ts) handles:
- Skill loading — reads
SKILL.mdfiles, detects MCP servers - System prompt building — concatenates
workspace/CLAUDE.md+ skill instructions - Message routing — channel message in → provider → response back to channel
- Conversation history — loads last 30 messages from SQLite for context
- Session persistence — saves/restores provider session IDs per sender
- Per-sender queue — ensures one agent turn per sender at a time (concurrent across senders)
- Scheduled tasks — polls cron-based tasks every 60s, executes due tasks via provider
- Graceful shutdown — cleans up intervals, disconnects channel
Database
SQLite via better-sqlite3 with WAL mode. Three tables:
| Table | Purpose |
|-------|---------|
| messages | Conversation history per session (sender/group) |
| sessions | Maps senders to provider session IDs |
| tasks | Scheduled tasks (prompt, cron, target, last_run) |
Stored at ./store/clawkit.db (gitignored).
Dependencies
Always installed (core):
better-sqlite3 — message/session/task storage
cron-parser — scheduled task expressions
dotenv — environment variable loadingInstall per channel (pick one):
grammy — Telegram
baileys @hapi/boom pino qrcode-terminal — WhatsAppInstall per provider (pick one):
@anthropic-ai/claude-agent-sdk — Claude Code
@openai/codex — OpenAI Codex CLI
@mariozechner/pi-agent-core — Pi AgentInstall if skills use MCP:
@modelcontextprotocol/sdk zod — MCP server implementationBase install: 3 core deps + 1 channel + 1 provider = ~4-5 packages.
Commands
npm run dev # Run with tsx (development, auto-loads .ts)
npm run build # Compile TypeScript to dist/
npm start # Run compiled version (production)
npm test # Run testsInteractive Setup
If you have Claude Code installed, the /setup skill provides a guided wizard:
claude
# type: /setupThe wizard will:
- Check your environment (Node.js 20+, dependencies)
- Ask which channel you want (Telegram / WhatsApp)
- Ask which provider you want (Claude / Codex / Pi)
- Walk you through authentication (bot token, QR code, API keys)
- Ask for your agent's name
- Generate
clawkit.config.tsand.env - Install the right dependencies
- Optionally set up a background service (launchd/systemd)
- Verify everything works
How It Compares
| | Full ClawKit | ClawKit Lite | Official Nanoclaw | |-|-------------|-------------|-------------------| | Code | ~5k lines + registry | ~1,000 lines | ~6,900 lines | | Provider | Multi (typed interfaces) | Multi (swap one file) | Claude only | | Channels | Multi (typed interfaces) | Multi (swap one file) | WA + Telegram hardcoded | | Extensibility | Component categories | Skills + adapter swap | SKILL.md only | | Docker | No | No | Required | | Philosophy | Framework | Kit | Opinionated app |
Testing
npm test31 tests covering:
- Database: message CRUD, session persistence, task management
- Runtime: message flow, typing indicators, history context, session resume, error handling (yielded + thrown), streaming, per-sender queue serialization, group messages, skill loading, MCP server detection, system prompt building, config variations
License
MIT
