npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@corebot/core

v0.3.0

Published

Lightweight but capable TypeScript bot architecture.

Readme

Corebot

Node CI npm license

Lightweight but capable TypeScript bot architecture. Single-process by default, tool- and skill-driven, MCP-ready, and safe-by-default.

Reliability Positioning

Corebot is optimized for the single-host reliable AI bot track:

  • one process, one local SQLite, one workspace
  • durable queue + retries + dead-letter replay
  • idempotent publish and inbound execution ledger
  • restart-safe recovery for stale in-flight work
  • observability and audit trail built into runtime

If your target is: "a bot that keeps running correctly on one machine under real failures", this repo is designed for that.

Delivery Semantics (What Is Guaranteed)

| Scenario | Semantics | Mechanism | | ----------------------------------- | ----------------------------------------- | ------------------------------------------------------- | | Inbound/outbound enqueue | At-least-once enqueue attempt | Durable message_queue + retry | | Duplicate publish (same message id) | Deduplicated enqueue | message_dedupe unique key | | Inbound re-processing after crash | Effectively-once runtime side effect | inbound_executions ledger + deterministic outbound id | | Tool execution retries | At-least-once execution attempt | Bus retry / dead-letter policy | | Scheduled task dispatch | At-least-once dispatch attempt | Scheduler emits synthetic inbound + retry path | | Heartbeat alerts | Suppressed if pure ACK / recent duplicate | ackToken gate + delivery dedupe window |

Notes:

  • "Effectively-once" here means duplicate deliveries are neutralized by idempotency guards inside Corebot; external side effects still need idempotent tool design.
  • Queue dead-letter is an explicit stop condition, not silent drop.

Failure Model and Recovery

Corebot handles the following failure classes by default:

  1. Process crash during message handling Result: stale processing messages are recovered on restart and re-queued.
  2. LLM/tool transient failure Result: exponential retry until maxAttempts, then dead-letter with error reason.
  3. Duplicate inbound/outbound publish Result: dedupe key collapses duplicates to one queue record.
  4. Router crash after runtime completed Result: inbound ledger serves cached result; runtime/tools are not re-executed.
  5. Queue overload Result: overload backoff and configurable queue caps; overflow goes to dead-letter.
  6. Schema migration failure Result: startup stops and reports pre-migration backup path for restore.

Production Baseline (Single Host)

Use this as the minimum reliable baseline:

{
  "storeFullMessages": true,
  "bus": {
    "maxAttempts": 5,
    "processingTimeoutMs": 120000,
    "maxPendingInbound": 5000,
    "maxPendingOutbound": 5000
  },
  "observability": {
    "enabled": true,
    "http": { "enabled": true, "host": "127.0.0.1", "port": 3210 }
  },
  "slo": {
    "enabled": true
  }
}

Also recommended:

  • persist both data/ and workspace/
  • enable webhook auth if webhook channel is exposed
  • set COREBOT_MCP_ALLOWED_SERVERS / COREBOT_MCP_ALLOWED_TOOLS in production

Features

  • Agent runtime with tool-calling loop
  • Built-in tools (fs, shell, web, memory, messaging, tasks, skills)
  • Skills via SKILL.md (progressive loading)
  • MCP client integration (tools injected dynamically)
  • SQLite storage for chats, messages, summaries, and tasks
  • Scheduler with cron | interval | once
  • Agent heartbeat loop with debounce wake, ack suppression, and duplicate-delivery guard
  • CLI channel for local usage (other channels stubbed)
  • Isolated tool runtime for high-risk tools (shell.exec, web.fetch, fs.write)
  • Durable queue with idempotent publish (retry/dead-letter/replay + dedupe by message id)
  • Inbound execution ledger to avoid duplicate runtime/tool execution on re-queued messages
  • Queue backpressure + per-chat rate limit (overflow to DLQ + overload backoff)
  • Observability endpoints (/health/*, /metrics, /status) and SLO monitor
  • Webhook channel (inbound POST + outbound pull API + optional token auth)
  • Migration safety with pre-migration backups and migration history
  • Persistent audit events for tool execution, denials, and errors

CLI and SDK

  • CLI: corebot (or pnpm run dev / pnpm run start)
  • SDK: import from @corebot/core and manage lifecycle via createCorebotApp()
  • CLI flags: corebot --help, corebot --version, corebot preflight
import { createCorebotApp, loadConfig } from "@corebot/core";

const app = await createCorebotApp({ config: loadConfig() });
await app.start();
// ...
await app.stop();

Quick Start

pnpm install --frozen-lockfile
export OPENAI_API_KEY=YOUR_KEY
pnpm run dev

Type in the CLI prompt to chat. Use /exit to quit.

Package Manager and Lockfile Policy

  • Use pnpm only (packageManager is pinned in package.json).
  • Commit both pnpm-lock.yaml and pnpm-workspace.yaml.
  • Install with pnpm install --frozen-lockfile in local reproducible runs, CI, and Docker.
  • Keep build-script approvals explicit in pnpm-workspace.yaml (onlyBuiltDependencies).
  • If a newly added dependency needs lifecycle scripts, run pnpm approve-builds and commit the updated policy file.

Example Commands

# Build + run production bundle locally
pnpm run build
node dist/bin.js

# Use a custom workspace/data directory
COREBOT_WORKSPACE=./workspace COREBOT_DATA_DIR=./data pnpm run dev

# Enable shell tool with executable allowlist
COREBOT_ALLOW_SHELL=true COREBOT_SHELL_ALLOWLIST="ls,git" pnpm run dev

# Enable web.search (Brave Search API)
BRAVE_API_KEY=YOUR_KEY COREBOT_ALLOWED_ENV=BRAVE_API_KEY pnpm run dev

# Restrict web.fetch to specific hosts/domains
COREBOT_WEB_ALLOWLIST="example.com,api.example.com" pnpm run dev

# Restrict web.fetch ports
COREBOT_WEB_ALLOWED_PORTS="443,8443" COREBOT_WEB_BLOCKED_PORTS="8080" pnpm run dev

# Isolate multiple high-risk tools in worker process
COREBOT_ISOLATION_TOOLS="shell.exec,web.fetch,fs.write" pnpm run dev

# Enable observability HTTP endpoints
COREBOT_OBS_HTTP_ENABLED=true COREBOT_OBS_HTTP_PORT=3210 pnpm run dev

# Enable webhook channel
COREBOT_WEBHOOK_ENABLED=true COREBOT_WEBHOOK_AUTH_TOKEN=YOUR_TOKEN pnpm run dev

# Manual database backup / restore
pnpm run ops:db:backup -- --db data/bot.sqlite
pnpm run ops:db:restore -- --db data/bot.sqlite --from data/backups/manual-xxxx.sqlite --force

# Validate startup config and MCP file before deployment
corebot preflight
corebot preflight --mcp-config ./path/to/.mcp.json

CLI queue ops:

  • /dlq list [inbound|outbound|all] [limit]
  • /dlq replay <queueId|inbound|outbound|all> [limit]

Example prompts (in CLI):

  • “Schedule a daily summary at 9am.”
  • “Save a short memory about my preferences.”
  • “List available skills.”

Configuration

You can configure via config.json or environment variables.

config.json (example)

{
  "workspaceDir": "workspace",
  "dataDir": "data",
  "sqlitePath": "data/bot.sqlite",
  "logLevel": "info",
  "provider": {
    "type": "openai",
    "baseUrl": "https://api.openai.com/v1",
    "model": "gpt-4o-mini",
    "temperature": 0.2,
    "timeoutMs": 60000,
    "maxInputTokens": 128000,
    "reserveOutputTokens": 4096
  },
  "historyMaxMessages": 30,
  "storeFullMessages": false,
  "maxToolIterations": 8,
  "maxToolOutputChars": 50000,
  "skillsDir": "workspace/skills",
  "mcpConfigPath": ".mcp.json",
  "mcpSync": {
    "failureBackoffBaseMs": 1000,
    "failureBackoffMaxMs": 60000,
    "openCircuitAfterFailures": 5,
    "circuitResetMs": 30000
  },
  "heartbeat": {
    "enabled": false,
    "intervalMs": 300000,
    "wakeDebounceMs": 250,
    "wakeRetryMs": 1000,
    "promptPath": "HEARTBEAT.md",
    "activeHours": "",
    "skipWhenInboundBusy": true,
    "ackToken": "HEARTBEAT_OK",
    "suppressAck": true,
    "dedupeWindowMs": 86400000,
    "maxDispatchPerRun": 20
  },
  "scheduler": { "tickMs": 60000 },
  "bus": {
    "pollMs": 1000,
    "batchSize": 50,
    "maxAttempts": 5,
    "retryBackoffMs": 1000,
    "maxRetryBackoffMs": 60000,
    "processingTimeoutMs": 120000,
    "maxPendingInbound": 5000,
    "maxPendingOutbound": 5000,
    "overloadPendingThreshold": 2000,
    "overloadBackoffMs": 500,
    "perChatRateLimitWindowMs": 60000,
    "perChatRateLimitMax": 120
  },
  "observability": {
    "enabled": true,
    "reportIntervalMs": 30000,
    "http": { "enabled": true, "host": "127.0.0.1", "port": 3210 }
  },
  "slo": {
    "enabled": true,
    "alertCooldownMs": 60000,
    "maxPendingQueue": 2000,
    "maxDeadLetterQueue": 20,
    "maxToolFailureRate": 0.2,
    "maxSchedulerDelayMs": 60000,
    "maxMcpFailureRate": 0.3
  },
  "isolation": {
    "enabled": true,
    "toolNames": ["shell.exec"],
    "workerTimeoutMs": 30000,
    "maxWorkerOutputChars": 250000,
    "maxConcurrentWorkers": 4,
    "openCircuitAfterFailures": 5,
    "circuitResetMs": 30000
  },
  "allowShell": false,
  "allowedShellCommands": [],
  "allowedEnv": [],
  "allowedWebDomains": [],
  "allowedWebPorts": [],
  "blockedWebPorts": [],
  "allowedMcpServers": [],
  "allowedMcpTools": [],
  "adminBootstrapKey": "",
  "adminBootstrapSingleUse": true,
  "adminBootstrapMaxAttempts": 5,
  "adminBootstrapLockoutMinutes": 15,
  "webhook": {
    "enabled": false,
    "host": "0.0.0.0",
    "port": 8788,
    "path": "/webhook",
    "authToken": "",
    "maxBodyBytes": 1000000
  },
  "cli": { "enabled": true }
}

Environment variables

  • OPENAI_API_KEY
  • OPENAI_BASE_URL
  • OPENAI_MODEL
  • OPENAI_TEMPERATURE
  • OPENAI_TIMEOUT_MS (deprecated alias for COREBOT_PROVIDER_TIMEOUT_MS)
  • COREBOT_PROVIDER_TIMEOUT_MS
  • COREBOT_PROVIDER_MAX_INPUT_TOKENS
  • COREBOT_PROVIDER_RESERVE_OUTPUT_TOKENS
  • COREBOT_WORKSPACE
  • COREBOT_DATA_DIR
  • COREBOT_SQLITE_PATH
  • COREBOT_LOG_LEVEL
  • COREBOT_HISTORY_MAX
  • COREBOT_STORE_FULL
  • COREBOT_MAX_TOOL_ITER
  • COREBOT_MAX_TOOL_OUTPUT
  • COREBOT_SKILLS_DIR
  • COREBOT_MCP_CONFIG
  • COREBOT_MCP_SYNC_BACKOFF_BASE_MS
  • COREBOT_MCP_SYNC_BACKOFF_MAX_MS
  • COREBOT_MCP_SYNC_OPEN_CIRCUIT_AFTER_FAILURES
  • COREBOT_MCP_SYNC_CIRCUIT_RESET_MS
  • COREBOT_HEARTBEAT_ENABLED
  • COREBOT_HEARTBEAT_INTERVAL_MS
  • COREBOT_HEARTBEAT_WAKE_DEBOUNCE_MS
  • COREBOT_HEARTBEAT_WAKE_RETRY_MS
  • COREBOT_HEARTBEAT_PROMPT_PATH
  • COREBOT_HEARTBEAT_ACTIVE_HOURS
  • COREBOT_HEARTBEAT_SKIP_WHEN_INBOUND_BUSY
  • COREBOT_HEARTBEAT_ACK_TOKEN
  • COREBOT_HEARTBEAT_SUPPRESS_ACK
  • COREBOT_HEARTBEAT_DEDUPE_WINDOW_MS
  • COREBOT_HEARTBEAT_MAX_DISPATCH_PER_RUN
  • COREBOT_ISOLATION_ENABLED
  • COREBOT_ISOLATION_TOOLS
  • COREBOT_ISOLATION_WORKER_TIMEOUT_MS
  • COREBOT_ISOLATION_MAX_WORKER_OUTPUT_CHARS
  • COREBOT_ISOLATION_MAX_CONCURRENT_WORKERS
  • COREBOT_ISOLATION_OPEN_CIRCUIT_AFTER_FAILURES
  • COREBOT_ISOLATION_CIRCUIT_RESET_MS
  • COREBOT_ALLOW_SHELL
  • COREBOT_SHELL_ALLOWLIST
  • COREBOT_ALLOWED_ENV
  • COREBOT_WEB_ALLOWLIST
  • COREBOT_WEB_ALLOWED_PORTS
  • COREBOT_WEB_BLOCKED_PORTS
  • COREBOT_BUS_POLL_MS
  • COREBOT_BUS_BATCH_SIZE
  • COREBOT_BUS_MAX_ATTEMPTS
  • COREBOT_BUS_RETRY_BACKOFF_MS
  • COREBOT_BUS_MAX_RETRY_BACKOFF_MS
  • COREBOT_BUS_PROCESSING_TIMEOUT_MS
  • COREBOT_BUS_MAX_PENDING_INBOUND
  • COREBOT_BUS_MAX_PENDING_OUTBOUND
  • COREBOT_BUS_OVERLOAD_PENDING_THRESHOLD
  • COREBOT_BUS_OVERLOAD_BACKOFF_MS
  • COREBOT_BUS_CHAT_RATE_WINDOW_MS
  • COREBOT_BUS_CHAT_RATE_MAX
  • COREBOT_OBS_ENABLED
  • COREBOT_OBS_REPORT_MS
  • COREBOT_OBS_HTTP_ENABLED
  • COREBOT_OBS_HTTP_HOST
  • COREBOT_OBS_HTTP_PORT
  • COREBOT_SLO_ENABLED
  • COREBOT_SLO_ALERT_COOLDOWN_MS
  • COREBOT_SLO_MAX_PENDING_QUEUE
  • COREBOT_SLO_MAX_DEAD_LETTER_QUEUE
  • COREBOT_SLO_MAX_TOOL_FAILURE_RATE
  • COREBOT_SLO_MAX_SCHEDULER_DELAY_MS
  • COREBOT_SLO_MAX_MCP_FAILURE_RATE
  • COREBOT_SLO_ALERT_WEBHOOK_URL
  • COREBOT_MCP_ALLOWED_SERVERS
  • COREBOT_MCP_ALLOWED_TOOLS
  • COREBOT_ADMIN_BOOTSTRAP_KEY
  • COREBOT_ADMIN_BOOTSTRAP_SINGLE_USE
  • COREBOT_ADMIN_BOOTSTRAP_MAX_ATTEMPTS
  • COREBOT_ADMIN_BOOTSTRAP_LOCKOUT_MINUTES
  • COREBOT_WEBHOOK_ENABLED
  • COREBOT_WEBHOOK_HOST
  • COREBOT_WEBHOOK_PORT
  • COREBOT_WEBHOOK_PATH
  • COREBOT_WEBHOOK_AUTH_TOKEN
  • COREBOT_WEBHOOK_MAX_BODY_BYTES

Notes:

  • COREBOT_ALLOWED_ENV is used by tools that explicitly gate env access (for example web.search) and by isolated shell.exec workers.
  • COREBOT_SHELL_ALLOWLIST matches executable names (for example ls,git), not full command prefixes.
  • COREBOT_WEB_ALLOWLIST restricts web.fetch target hosts (exact host or subdomain match).
  • COREBOT_WEB_ALLOWED_PORTS and COREBOT_WEB_BLOCKED_PORTS provide port allow/deny controls for web.fetch.
  • COREBOT_ISOLATION_TOOLS defaults to shell.exec; add web.fetch and/or fs.write to isolate network and file-write execution as well.
  • COREBOT_ISOLATION_MAX_CONCURRENT_WORKERS caps simultaneous isolated workers (default 4).
  • COREBOT_ISOLATION_OPEN_CIRCUIT_AFTER_FAILURES and COREBOT_ISOLATION_CIRCUIT_RESET_MS control per-tool circuit breaker for repeated worker failures.
  • Default policy denies non-admin fs.write to protected paths (skills/, IDENTITY.md, TOOLS.md, USER.md, .mcp.json).
  • COREBOT_MCP_ALLOWED_SERVERS and COREBOT_MCP_ALLOWED_TOOLS act as allowlists when set; empty lists allow all discovered MCP servers/tools.
  • COREBOT_MCP_SYNC_* controls MCP auto-sync retry backoff and temporary circuit-open window after repeated failures.
  • COREBOT_PROVIDER_TIMEOUT_MS bounds each LLM request; timeout errors enter normal retry/dead-letter flow.
  • COREBOT_PROVIDER_MAX_INPUT_TOKENS and COREBOT_PROVIDER_RESERVE_OUTPUT_TOKENS enforce prompt budgeting before each LLM turn.
  • COREBOT_HEARTBEAT_ACTIVE_HOURS accepts HH:mm-HH:mm in local process time; empty means always active.
  • COREBOT_HEARTBEAT_PROMPT_PATH is resolved relative to workspaceDir and must be non-empty to dispatch heartbeat turns.
  • COREBOT_WEBHOOK_AUTH_TOKEN can be sent via Authorization: Bearer <token> or x-corebot-token.
  • COREBOT_ADMIN_BOOTSTRAP_SINGLE_USE=true invalidates bootstrap elevation after first successful use.
  • COREBOT_ADMIN_BOOTSTRAP_MAX_ATTEMPTS and COREBOT_ADMIN_BOOTSTRAP_LOCKOUT_MINUTES control invalid-key lockout policy.

Deployment Guide

  1. Build
pnpm install --frozen-lockfile
pnpm run build
  1. Run
export OPENAI_API_KEY=YOUR_KEY
node dist/bin.js
# Or directly: node dist/main.js
  1. Persist data
    Ensure data/ and workspace/ are persisted (bind mount or volume). Corebot auto-creates them if missing.

  2. Config
    Use config.json for stable configuration in production; use env vars for secrets.

Docker

Build and run using the included Dockerfile:

docker build -t corebot .
docker run -it --rm \\
  -e OPENAI_API_KEY=YOUR_KEY \\
  -v $(pwd)/data:/app/data \\
  -v $(pwd)/workspace:/app/workspace \\
  corebot

Optional: mount .mcp.json or config.json if you want MCP or custom settings:

docker run -it --rm \\
  -e OPENAI_API_KEY=YOUR_KEY \\
  -v $(pwd)/data:/app/data \\
  -v $(pwd)/workspace:/app/workspace \\
  -v $(pwd)/.mcp.json:/app/.mcp.json \\
  -v $(pwd)/config.json:/app/config.json \\
  corebot

CI Template (GitHub Actions)

name: ci
on:
  push:
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: 10
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm run build

Built-in Tools

  • fs.read, fs.write, fs.list
  • shell.exec (disabled by default)
  • web.fetch, web.search (Brave Search API)
  • memory.read, memory.write
  • message.send, chat.register, chat.set_role
  • tasks.schedule, tasks.list, tasks.update
  • skills.list, skills.read, skills.enable, skills.disable, skills.enabled
  • heartbeat.status, heartbeat.trigger, heartbeat.enable (admin only)
  • mcp.reload (admin only; force refresh MCP config and tool bindings)
  • bus.dead_letter.list, bus.dead_letter.replay (admin only)

Tool API Reference

File System

| Tool | Parameters | Description | | ---------- | ----------------------------------------------------------------------------------------- | -------------------------------------- | | fs.read | path: string | Read a text file within the workspace | | fs.write | path: string, content: string, mode?: "overwrite"\|"append" (default "overwrite") | Write a text file within the workspace | | fs.list | path?: string (default ".") | List files in a workspace directory |

Shell

| Tool | Parameters | Description | | ------------ | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | shell.exec | command: string, cwd?: string, timeoutMs?: number (default 20000, max 120000) | Execute a command. Disabled by default; requires allowShell=true. Admin only. |

Commands are tokenized and executed directly (no shell interpreter). If allowedShellCommands is non-empty, only listed executable names are permitted.

Web

| Tool | Parameters | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | | web.fetch | url: string, method?: "GET"\|"POST" (default "GET"), headers?: Record<string,string>, body?: string, timeoutMs?: number (default 15000), maxResponseChars?: number (default 200000) | Fetch a URL over HTTP | | web.search | query: string, count?: number (default 5, max 10) | Search the web using Brave Search API. Requires BRAVE_API_KEY in allowedEnv. |

Memory

| Tool | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | | memory.read | scope?: "global"\|"chat"\|"all" (default "all") | Read memory content | | memory.write | scope?: "global"\|"chat" (default "chat"), content: string, mode?: "append"\|"replace" (default "append") | Write memory. Global scope is admin only. |

Memory files: workspace/memory/MEMORY.md (global), workspace/memory/{channel}_{chatId}.md (per-chat).

Messaging

| Tool | Parameters | Description | | --------------- | ------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- | | message.send | content: string, channel?: string, chatId?: string | Send a message. Cross-chat sending is admin only. | | chat.register | channel?: string, chatId?: string, role?: "admin"\|"normal", bootstrapKey?: string | Register a chat for full message storage. See Admin Bootstrap below. | | chat.set_role | channel: string, chatId: string, role: "admin"\|"normal" | Set chat role. Admin only. |

Tasks

| Tool | Parameters | Description | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | | tasks.schedule | prompt: string, scheduleType: "cron"\|"interval"\|"once", scheduleValue: string, contextMode?: "group"\|"isolated" (default "group") | Create a scheduled task | | tasks.list | includeInactive?: boolean (default true) | List tasks for this chat | | tasks.update | taskId: string, status?: "active"\|"paused"\|"done", scheduleType?, scheduleValue?, contextMode? | Update a task. Cross-chat updates are admin only. |

scheduleValue format: cron expression for cron, milliseconds string for interval, ISO datetime for once.

Skills Management

| Tool | Parameters | Description | | ---------------- | -------------- | -------------------------------------------------- | | skills.list | (none) | List available skills with enabled status | | skills.read | name: string | Read a skill file content | | skills.enable | name: string | Enable a skill for this chat | | skills.disable | name: string | Disable a skill (always-skills cannot be disabled) | | skills.enabled | (none) | List currently enabled skill names |

Admin Tools

| Tool | Parameters | Description | | ------------------------ | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | heartbeat.status | (none) | Show heartbeat runtime status, config, and next due chats. Admin only. | | heartbeat.trigger | reason?: string, force?: boolean, channel?: string, chatId?: string | Queue an immediate heartbeat wake (optional force and target chat). Admin only. | | heartbeat.enable | enabled: boolean, reason?: string | Enable/disable runtime heartbeat loop without restart. Admin only. | | mcp.reload | reason?: string, force?: boolean (default true) | Reload MCP config and re-register tools. Set force=false to respect no-change checks and failure backoff. Admin only. | | bus.dead_letter.list | direction?: "inbound"\|"outbound", limit?: number (default 20) | List dead-letter queue entries. Admin only. | | bus.dead_letter.replay | queueId?: string, direction?: "inbound"\|"outbound", limit?: number (default 10) | Replay dead-letter entries back to pending. Admin only. |

Security Model

Roles

Corebot uses two roles: admin and normal. New chats default to normal.

Admin Bootstrap

The first admin is created through a bootstrap flow:

  1. Set COREBOT_ADMIN_BOOTSTRAP_KEY in config/env.
  2. A user calls chat.register with role=admin and bootstrapKey=<the key>.
  3. If the key matches, the chat is promoted to admin.
  4. With adminBootstrapSingleUse=true (default), the key is invalidated after first use.
  5. After adminBootstrapMaxAttempts (default 5) failed attempts, bootstrap locks for adminBootstrapLockoutMinutes (default 15).
  6. Once an admin exists, new admins can only be granted by existing admins via chat.set_role.

Permission Matrix

| Capability | Normal | Admin | | --------------------------------------- | ------ | ----- | | File read/write/list (within workspace) | Yes | Yes | | File write to protected paths | No | Yes | | Shell execution | No | Yes | | Web fetch (policy-restricted) | Yes | Yes | | Memory write (chat scope) | Yes | Yes | | Memory write (global scope) | No | Yes | | Send message (same chat) | Yes | Yes | | Send message (cross-chat) | No | Yes | | Register own chat | Yes | Yes | | Register other chats | No | Yes | | Update own tasks | Yes | Yes | | Update other chats' tasks | No | Yes | | Heartbeat control/status tools | No | Yes | | MCP tool execution | No | Yes | | MCP reload | No | Yes | | Dead-letter queue operations | No | Yes | | Set chat roles | No | Yes |

Protected Workspace Paths

Non-admin fs.write is denied for: IDENTITY.md, TOOLS.md, USER.md, .mcp.json, skills/ (and any path under it).

Memory

Corebot maintains two types of persistent memory:

  • Global memory (workspace/memory/MEMORY.md): shared across all chats. Admin-only for writes.
  • Per-chat memory (workspace/memory/{channel}_{chatId}.md): scoped to a specific chat session.

Both are automatically included in the system prompt when available, except isolated scheduled-task runs (chat memory excluded).

Conversation Compaction

When the stored message count for a chat exceeds historyMaxMessages * 2, Corebot automatically compacts:

  1. Recent messages are sent to the LLM to generate a bullet summary (max 150 words).
  2. Old messages beyond historyMaxMessages are pruned from storage.
  3. The summary is stored in conversation_state and included in future system prompts.

This keeps context manageable while preserving key facts and decisions.

Inbound Execution Ledger

To ensure idempotency when messages are re-queued (e.g., after a retry), Corebot maintains an inbound_executions table:

  • Before processing, the router checks if the inbound message was already processed.
  • If completed, the cached response is reused without re-running the LLM or tools.
  • If a previous run is stale (older than bus.processingTimeoutMs), it is reclaimed.
  • Outbound message IDs are deterministic (outbound:{channel}:{chatId}:{inboundId}), so re-processing does not create duplicate replies.

Skills

Skills live in workspace/skills/<skill-name>/SKILL.md and support frontmatter:

---
name: web-research
description: "Web search + citation formatting"
always: false
requires:
  - env: ["BRAVE_API_KEY"]
tools:
  - web.search
  - web.fetch
---

# Web Research Skill

...

New skill directories/files are discovered dynamically during message handling, so adding a skill does not require a process restart.

MCP Integration

Create .mcp.json in repo root:

{
  "servers": {
    "myserver": {
      "command": "npx",
      "args": ["@example/mcp-server"]
    }
  }
}

MCP tools are injected as: mcp__<server>__<tool>.

.mcp.json is checked and auto-synced during message handling; changes are applied without restart.
You can also force refresh manually with mcp.reload. If .mcp.json is invalid (for example malformed JSON), reload is rejected and the previous MCP tool set remains active. Each enabled server must define exactly one of command or url; args/env are only valid with command. Use corebot preflight to validate config and .mcp.json before rolling out changes. Reload attempts are tracked in telemetry (corebot_mcp_reload_*) and persisted in audit_events with reason/duration metadata.

Agent Heartbeat

Heartbeat runs as a synthetic inbound turn per chat and reuses the same router/runtime/tool stack. It supports:

  • interval scheduling per chat
  • wake coalescing (debounce)
  • inbound-busy skip/retry gate
  • ack suppression (ackToken)
  • recent duplicate suppression (dedupeWindowMs)

Behavior controls live under heartbeat.* config and are also available via admin tools heartbeat.status, heartbeat.trigger, and heartbeat.enable.

Scheduler

Tasks support:

  • cron (cron expression)
  • interval (milliseconds)
  • once (ISO datetime)

Scheduler emits synthetic inbound messages with context_mode:

  • group: include chat context
  • isolated: minimal context

Reliability Metrics to Watch

For single-host reliability, track these first:

  1. corebot_queue_pending{direction="inbound"}
  2. corebot_queue_dead_letter{direction="inbound"}
  3. corebot_tools_failure_rate
  4. corebot_scheduler_max_delay_ms
  5. corebot_mcp_failure_rate
  6. corebot_heartbeat_scope_sent_total{scope="delivery"}
  7. corebot_heartbeat_scope_skipped_total{scope="delivery"}

Fast interpretation:

  • rising inbound pending with flat throughput means handler bottleneck or provider slowdown
  • rising dead-letter means retries are exhausted and manual replay/recovery is needed
  • heartbeat sent drops to zero while skipped rises usually indicates ACK suppression or duplicate suppression dominating

Operations

  • Health endpoints:
    • GET /health/live
    • GET /health/ready
    • GET /health/startup
  • Runtime endpoints:
    • GET /metrics (Prometheus format)
    • GET /status (JSON snapshot with queue/tool/scheduler/MCP health)
  • Webhook channel:
    • POST <COREBOT_WEBHOOK_PATH> with JSON {chatId, content, senderId?, id?, createdAt?, metadata?}
    • GET <COREBOT_WEBHOOK_PATH>/outbound?chatId=<id>&limit=<n>

Detailed incident and recovery procedures are documented in RUNBOOK.md.

Workspace Layout

workspace/
  IDENTITY.md
  USER.md
  TOOLS.md
  memory/
    MEMORY.md
  skills/
    <skill-name>/SKILL.md

Roadmap

  • WhatsApp / Telegram adapters
  • Container sandbox for tools
  • Additional provider adapters
  • Multi-instance coordination and queue partitioning

Inspiration

Corebot is inspired by NanoClaw + NanoBot patterns.


For the full architecture details, see ARCHITECTURE.md. For the operations runbook, see RUNBOOK.md. For contribution guidelines, see CONTRIBUTING.md.

License

MIT