Skip to content

johny/clawlet

Repository files navigation

Clawlet

Clawlet is a small self-hosted AI assistant. It runs a fast reply path for chat, an async deep worker for tool-backed tasks, and a periodic consolidation loop for schedules and memory.

It is intentionally compact: 10 TypeScript source files, SQLite state, a file-backed message queue, and one Docker service.

Full design notes: docs/SPEC.md

Features

  • Fast chat triage with cheap model calls and heuristic replies for simple greetings or cancellations.
  • Async deep work with file, shell, search, and web-fetch tools.
  • SQLite memory split into episodic messages, semantic facts, personality, agenda, work log, meta, and schedules.
  • File queue under data/queue, so pending and processed messages are inspectable with normal shell tools.
  • Scheduled tasks using 5-field cron expressions.
  • Single-file dashboard with chat, agenda, memory, work log, and schedule views.
  • Docker-first deployment with persistent data volume.

Requirements

  • Node.js 20+ for local development. Node.js 22 is recommended.
  • Docker and Docker Compose for containerized use.
  • An OpenRouter API key.

Quick Start

Clone the repository and create local configuration:

git clone <repo-url>
cd clawlet
cp .env.example .env

Edit .env and set OPENROUTER_API_KEY.

Docker

docker compose up -d --build

Open http://localhost:3000.

Data is stored in the clawlet-data Docker volume. Config is mounted read-only from ./config.

Useful Docker commands:

docker compose logs -f
docker compose down
docker compose down -v

Local Development

npm install
npm run dev

Open http://localhost:3000. Local state is written to ./data.

Configuration

Copy .env.example to .env:

OPENROUTER_API_KEY=sk-or-...
CLAWLET_MODEL=anthropic/claude-sonnet-4
CLAWLET_FAST_MODEL=meta-llama/llama-3.1-8b-instruct
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
CLAWLET_URL=http://localhost:3000

PORT=3000
DB_PATH=./data/clawlet.db
QUEUE_DIR=./data/queue
PERSONALITY_PATH=./config/personality.yaml
RULES_PATH=./config/rules.yaml

Behavior is controlled by config/rules.yaml. These fields can also be overridden with environment variables:

Rule Env var
active_hours CLAWLET_ACTIVE_HOURS
think_interval_minutes CLAWLET_THINK_INTERVAL
max_daily_tokens CLAWLET_MAX_TOKENS
working_memory_cap CLAWLET_MEMORY_CAP
deep_work_timeout_minutes CLAWLET_DEEP_TIMEOUT
confidence_decay_cycles CLAWLET_DECAY_CYCLES
confidence_decay_rate CLAWLET_DECAY_RATE
confidence_archive_below CLAWLET_ARCHIVE_BELOW

config/personality.yaml defines the assistant name, tone, interests, values, quirks, and hard behavioral constraints. Personality entries are seeded into SQLite on first startup.

Dashboard

The dashboard is served at / and connects over WebSocket.

Tab Purpose
Chat Send messages and receive replies
Agenda View pending, active, blocked, done, and cancelled tasks
Memory Inspect semantic facts and confidence
Thinking Follow deep-worker work log events
Schedules Create, toggle, and delete scheduled tasks

Security Model

Clawlet is designed for trusted, self-hosted use. The deep worker can read files, write files, execute shell commands, search local paths, and fetch HTTP(S) URLs. Do not expose it directly to the public internet without adding authentication, network controls, and tool sandboxing appropriate for your environment.

API

All endpoints are served on PORT, default 3000.

Method Path Description
POST /api/chat Enqueue a chat message. Body: {"message":"...","channel":"dashboard"}
GET /api/stats Memory, agenda, and token counters
GET /api/memory Semantic facts
GET /api/personality Personality rows
GET /api/agenda Agenda items
GET /api/worklog/:id Work log for one agenda item
GET /api/schedules Schedules
POST /api/schedules Create a schedule
PUT /api/schedules/:id Update a schedule
DELETE /api/schedules/:id Delete a schedule
PATCH /api/schedules/:id/toggle Enable or disable a schedule
POST /api/schedules/parse Ask the fast model to parse natural language into cron

WebSocket events are JSON objects with type, data, and time.

Event Data
snapshot Current agenda and schedules on connect
reply Assistant reply
status Deep-worker state change
thought Consolidation thought
worklog Deep-worker step output

Architecture

chat request
  -> file queue
  -> fast path
     -> immediate reply
     -> optional agenda item
  -> deep worker
     -> tools
     -> async reply

consolidation loop
  -> due schedules
  -> fact extraction
  -> confidence decay
  -> episodic compaction
  -> agenda review
  -> personality reflection

Source layout:

src/
├── agent.ts      Fast path, deep worker, consolidation
├── memory.ts     SQLite schema, memory helpers, JSONL audit log
├── schedule.ts   Cron schedules
├── agenda.ts     Working memory and work logs
├── queue.ts      File-backed message queue
├── server.ts     Express, API, WebSocket wiring
├── llm.ts        OpenRouter client
├── tools.ts      Deep-worker tools
├── types.ts      Shared types
└── index.ts      Startup

Development

npm run typecheck
npm run lint
npm test
npm run build

Run a single test:

npx vitest run src/schedule.test.ts
npx vitest run -t "creates a schedule"

Current source budget:

Metric Current
Runtime source files 10
Runtime source lines ~1,500
Runtime dependencies 8

Publishing Checklist

  • Replace <repo-url> in this README after creating the GitHub repository.
  • Confirm .env, data/, dist/, coverage/, and node_modules/ are untracked.
  • Run npm run typecheck && npm run lint && npm test && npm run build.
  • Build the image with docker compose build.
  • Add repository owner details to LICENSE if desired.

License

MIT

About

A small self-hosted AI assistant running in a loop

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages