No description
Find a file
2026-02-20 15:20:23 +02:00
src Final commit probably 2026-02-20 15:20:23 +02:00
.gitignore Functionality fuckery 2026-02-02 03:20:45 +02:00
.oxfmtrc.json Lots more! 2026-02-02 00:15:24 +02:00
.oxlintrc.json brave! 2026-02-04 02:40:42 +02:00
bun.lock Final commit probably 2026-02-20 15:20:23 +02:00
bunfig.toml Hyper formatting pass 2026-02-03 21:36:56 +02:00
CLAUDE.md Fix things :3 2026-02-08 01:53:57 +02:00
package.json Final commit probably 2026-02-20 15:20:23 +02:00
README.md make some changés 2026-02-05 11:07:45 +02:00
tsconfig.json Initialize TS 2026-02-01 22:20:30 +02:00

CireilClaw

A Discord bot powered by a Large Language Model (LLM) that functions as a personal assistant. It provides conversational AI capabilities with tool-based interactions, allowing users to interact through Discord messages in both private DMs and guild channels.

Features

  • Discord Integration: Responds to mentions in configured guilds and DMs from the owner

  • LLM-powered Conversations: Uses @mariozechner/pi-ai for flexible LLM provider/model support

  • Slash Commands:

    • /clear - Clear current session history and opened files (owner only)
    • /close <file> - Close an opened file (owner only, with autocomplete)
  • Tool-based Actions: The AI can execute various tools:

    • attachment - Fetch/view image attachments (png, jpg, jpeg, webp, ≤7MB)
    • brave-search - Web search using Brave Search API (requires API key)
    • close-file - Remove file from opened files list
    • exec - Execute sandboxed commands
    • list-open-files - List all currently opened files
    • no-reply - End the turn without responding
    • open-file - Open file to include in system prompt (with offset/limit support)
    • react - Add emoji reactions to messages
    • reply - Send Discord messages (with markdown splitting for long content)
    • weather - Get weather information via OpenWeather API (requires API key)
    • write - Write files with diff-based verification (using diff-match-patch)
  • Session Management: Persistent conversation history per channel with SQLite storage

    • Sliding window (~30 messages) with automatic squashing
    • Thread context walking to collect reply chains
  • Sandboxed Execution: Uses Bubblewrap (bwrap) for secure command execution with configurable modes

  • Memory System: Uses personality/core files (SOUL.md, IDENTITY.md, USER.md, MEMORY.md)

  • Rate Limit Handling: User-friendly messages with server-respected retry delays

  • Markdown Splitting: Preserves code blocks when splitting messages >2000 characters

Requirements

  • Linux - Uses Bubblewrap (bwrap) for sandboxing
    • NixOS - Automatically resolves tool dependencies via Nix store
    • Generic Linux - Uses system-installed tools from /usr, /bin, /lib
  • Bun - JavaScript runtime
  • Node.js 20+ (via Bun)
  • Bubblewrap - Required for sandboxing (bwrap command must be available)

Installation

# Clone the repository
git clone https://git.cutie.zone/lyssieth/cireilclaw
cd cireilclaw

# Install dependencies
bun install

Configuration

Create a configuration directory at ~/.cireilclaw/ with the following structure:

~/.cireilclaw/
├── config.toml      # Configuration file
├── CORE.md          # Core instructions
├── memories/        # Memory files directory
│   ├── SOUL.md
│   ├── IDENTITY.md
│   ├── USER.md
│   └── MEMORY.md
├── home/            # Sandbox home directory
└── skills/          # Read-only skills directory

config.toml

[discord]
token = "your-bot-token"
ownerId = "your-user-id"
allowedGuilds = ["guild-id-1", "guild-id-2"]
applicationId = "your-application-id"

[llm]
apiBase = "https://api.example.com/v1"
apiKey = "optional-api-key"
modelName = "provider/model-name"
# Optional: provider (auto-detected from modelName)
# provider = "openai"
# Optional: additional model parameters
# parameters = { temperature = 0.7 }

[sandbox]
# Sandbox mode: "nix" (NixOS) or "generic-linux" (other distros)
# Default: "nix"
mode = "generic-linux"

# Optional integrations
[integrations.brave]
apiKey = "your-brave-api-key"  # Enables brave-search tool

[integrations.openweather]
apiKey = "your-openweather-api-key"  # Enables weather tool

Sandbox Modes:

  • nix - Uses nix-store to resolve dependencies and creates isolated /bin with symlinks (NixOS only)
  • generic-linux - Binds system directories (/usr, /lib, etc.) and uses system-installed tools

Note: NixOS mode provides better isolation by only binding exact paths needed, while generic-linux mode binds broader system directories for compatibility.

The sessions.db SQLite database will be created automatically on first run.

Usage

# Run the bot
bun run dev

# Or run directly
bun src/index.ts

Development

# Run linter
bun run lint

# Format code
bun run fmt

Sandboxed Commands

The bot can execute the following commands in a sandboxed environment:

Shell:

  • bash

File viewing/searching:

  • cat, rg, fd, ls, head, tail, wc

Text processing:

  • sort, uniq, cut, awk, sed, tr, diff

File operations:

  • mkdir, rm, mv, cp, touch, chmod

File info:

  • file, du

Network:

  • curl

System info:

  • date, time, env, uptime

Linting:

  • markdownlint-cli2

Runtime:

  • bun

Project Structure

src/
├── index.ts           # Main entry point
├── util.ts            # Utilities (sandbox path mapping, allowed commands)
├── commands/
│   ├── index.ts       # Slash command registry
│   ├── clear.ts       # /clear command handler
│   └── close.ts       # /close command handler + autocomplete
├── config/
│   └── config.ts      # Configuration loader (TOML-based)
├── core/
│   ├── log.ts         # Pino logger setup
│   ├── event-bus.ts   # Event-driven architecture
│   └── event-set.ts   # Typed event definitions
└── llm/
    ├── engine.ts      # LLM provider abstraction and tool definitions
    ├── harness.ts     # Main orchestration (Discord, sessions, turns)
    ├── workspace.ts   # Memory file reading
    ├── markdown.ts    # Markdown splitting for Discord limits
    ├── sandbox.ts     # Sandboxed command execution (Bubblewrap)
    └── tools/
        ├── index.ts   # Tool handler registry
        ├── types.ts   # TypeScript types
        ├── attachment.ts
        ├── brave-search.ts
        ├── close-file.ts
        ├── exec.ts
        ├── list-open-files.ts
        ├── no-reply.ts
        ├── open-file.ts
        ├── react.ts
        ├── reply.ts
        ├── weather.ts
        └── write.ts

Events

The event bus handles the following events:

  • session-message - New user message in a session
  • tool-call - LLM requested a tool call
  • tool-result - Tool execution completed
  • llm-message - LLM streaming message
  • message-updated - Discord message was edited
  • message-deleted - Discord message was deleted
  • heartbeat - Periodic heartbeat (every ~8 hours)
  • shutdown - Graceful shutdown

Dependencies

Runtime:

  • @mariozechner/pi-ai - LLM provider abstraction layer
  • oceanic.js - Discord API library
  • pino + pino-princess - Logging
  • smol-toml - TOML configuration parsing
  • ulid - Unique ID generation
  • zod - Runtime type validation
  • @sinclair/typebox - Tool parameter schemas
  • diff-match-patch-es - Diff generation for write tool
  • openweather-api-node - Weather data API client

Dev:

  • bun - JavaScript runtime
  • oxfmt - Code formatter
  • oxlint - Fast linter (type-aware)
  • typescript - TypeScript compiler

License

Apache-2.0