A an agent framework with a central gateway architecture. Clotho runs a local server that manages agent sessions, tool execution, and model routing. Interact with it through the terminal REPL, Discord, scheduled jobs, or build your own client against the REST/WebSocket API.
Requires Python 3.12+ and pipx.
pipx install git+https://github.com/superkosat/clotho.git
clotho setup # generate auth tokenclotho # starts gateway + REPLConfigure a model profile before chatting:
/profile add
Profile name: anthropic
Provider: anthropic
Model: claude-haiku-4-5-20251001
API Key: sk-ant-...
/profile default anthropic
Model profiles
| Command | Description |
|---|---|
/profiles |
List all profiles |
/profile add |
Add a new profile (interactive) |
/profile use <name> |
Switch profile for this session |
/profile default <name> |
Set default profile for new sessions |
Chats
| Command | Description |
|---|---|
/chats |
List all saved chat sessions |
/chat new |
Create and switch to a new chat |
/chat <id> |
Resume an existing chat |
Permissions
| Command | Description |
|---|---|
/permissions |
Show current permission config |
/permission mode <mode> |
Set mode: interactive, autonomous, readonly |
/permission set <tool> <level> |
Override a tool: allow, ask, deny |
/permission clear <tool> |
Remove a tool override |
Streaming
| Command | Description |
|---|---|
/stream |
Show current streaming status |
/stream on / /stream off |
Toggle response streaming on or off |
Streaming is enabled by default. When on, responses render incrementally as tokens arrive. When off, the full response is delivered after the model finishes.
Context
| Command | Description |
|---|---|
/context |
Show context window usage |
/compact |
Summarize old turns to free context space |
Sandbox
| Command | Description |
|---|---|
/sandbox |
Show sandbox status |
/sandbox on / /sandbox off |
Enable or disable sandboxing |
/sandbox build |
Build the Docker sandbox image |
Channels
| Command | Description |
|---|---|
/setup |
Configure a messaging channel (Discord, ...) |
Clotho supports three providers via named profiles:
| Provider | Value |
|---|---|
| Anthropic | anthropic |
| OpenAI (or compatible) | openai |
| Ollama (local) | ollama |
Profiles are stored in ~/.clotho/profiles.json.
- interactive (default) β asks for approval before every tool call
- autonomous β auto-approves all tools
- readonly β denies all tools except
read
Per-tool overrides apply on top of the active mode.
When enabled, bash commands run inside a Docker container with:
- Read-only root filesystem
- No network access
- 512MB RAM / 1 CPU limit
- Workspace mounted at
/workspace
Docker must be running. Build the image once before enabling:
clotho sandbox buildSandbox is disabled by default.
Clotho will discover and load skill descriptions into the system prompt if they are located under ~/.clotho/skills/ with a SKILL.md file:
~/.clotho/skills/
commit/
SKILL.md
review-pr/
SKILL.md
SKILL.md starts with YAML frontmatter declaring the skill's name and description. The rest of the file contains instructions that the agent reads on demand when it determines the skill applies.
---
name: commit
description: Stage and commit changes with a conventional commit message.
---
<instructions for the agent to follow>Only the frontmatter metadata is injected into the system prompt. The full instructions stay on disk and are loaded by the agent when a skill matches the user's request.
Clotho can connect to external MCP (Model Context Protocol) servers at startup, adding their tools to every agent session. Tools from MCP servers are available alongside the built-in bash, read, write, and edit tools β the model sees them all the same way.
Add servers under "mcp" in ~/.clotho/config.json:
{
"mcp": {
"servers": {
"filesystem": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]
},
"github": {
"transport": "streamable_http",
"url": "https://api.githubcopilot.com/mcp/",
"auth": {
"type": "token",
"token_env": "GITHUB_TOKEN"
}
}
}
}
}Each server has a key (e.g. "filesystem") that becomes the tool name prefix. A tool named list_directory on the filesystem server becomes filesystem__list_directory in Clotho. Set "tool_prefix": "" to disable prefixing, or "tool_prefix": "fs" for a custom prefix.
stdio β spawns a local subprocess:
| Field | Required | Description |
|---|---|---|
transport |
yes | "stdio" |
command |
yes | Executable to run (e.g. npx, python) |
args |
no | Arguments passed to the process |
env |
no | Extra environment variables for the subprocess |
streamable_http β connects to a remote server:
| Field | Required | Description |
|---|---|---|
transport |
yes | "streamable_http" |
url |
yes | Server endpoint URL |
auth |
no | Authentication config (see below) |
No auth β omit auth entirely. Suitable for local stdio servers.
Static token β reads a bearer token from an environment variable:
"auth": {
"type": "token",
"token_env": "GITHUB_TOKEN"
}OAuth β full Authorization Code flow with PKCE. Requires interactive authorization before first use (see below):
"auth": {
"type": "oauth",
"scopes": ["tools:read", "tools:execute"]
}Note: The gateway is headless β it cannot run an OAuth browser flow at startup. OAuth servers require stored credentials from a prior
/mcp authsession. Servers whose tokens are missing or expired are skipped gracefully at startup.
For OAuth servers, authorize once from the REPL before starting the gateway:
/mcp auth <server>
This opens the browser, completes the OAuth flow, and stores tokens in ~/.clotho/mcp/tokens/<server>.json. The gateway reads these tokens on subsequent starts β no browser interaction needed after the first time. Tokens are refreshed automatically; re-run /mcp auth if a server becomes unauthorized.
| Command | Description |
|---|---|
/mcp |
List configured MCP servers |
/mcp auth <server> |
Authorize an OAuth server interactively |
| Field | Default | Description |
|---|---|---|
enabled |
true |
Set to false to skip without removing the entry |
tool_prefix |
server key | Prefix for tool names ("" to disable) |
If a server fails to connect at startup, Clotho logs the error and continues β the remaining servers and built-in tools are unaffected.
Clotho can connect to Discord as a bot, letting you interact with the agent through DMs or server channels. The bridge is a standalone process that connects to a running gateway.
clotho run -d # start gateway in background
clotho-discord # connect to Discord- Create a Discord application at discord.com/developers/applications
- Add a bot under the Bot tab; enable Message Content Intent
- Copy the bot token
- Generate an invite URL under OAuth2 > URL Generator β select the
botscope with permissions: Read Messages, Send Messages, Read Message History - Invite the bot to your server
Create ~/.clotho/discord/config.toml:
[gateway]
host = "localhost"
port = 8000
# token falls back to ~/.clotho/config.json if omitted
[discord]
bot_token = "..." # required β from Developer Portal
session_mode = "user" # "user" (per-user context) or "channel" (shared context)
tool_approval = "auto_allow" # "auto_allow" or "auto_deny"
mention_only = true # require @mention in servers (DMs always respond)
chunk_limit = 1900
allowed_guild_ids = ["*"] # ["*"] = all, [] = deny all, or specific IDs
allowed_channel_ids = ["*"] # same format
stop_codeword = "!stop" # cancel current session
stopall_codeword = "!stopall" # cancel all sessions globallyThe bridge handles Discord attachments automatically:
| Type | Extensions | Behavior |
|---|---|---|
| Images | png, jpg, jpeg, gif, webp | Sent as base64 content blocks to the model |
| Audio | ogg, mp3, wav, m4a, flac | Saved to temp file; agent transcribes via whisper skill |
| Text/code | txt, md, csv, json, py, js, ... | Inlined as code blocks (up to 100 KB) |
| Binary | everything else | Noted with metadata; contents not included |
The agent can add reactions to the user's message by including {{react:emoji}} directives in its response. The directive is stripped from the text and applied as a Discord reaction.
Jobs run agent prompts on a cron schedule and deliver responses to Discord channels or DMs.
Define jobs as YAML files in ~/.clotho/jobs/:
name: daily-standup
enabled: true
trigger:
type: cron
expression: "0 9 * * 1-5" # 9 AM weekdays (5-field cron)
prompt: "Generate a daily standup report."
delivery:
- type: discord_channel
channel_id: "123456789"
- type: discord_dm
user_id: "987654321"The scheduler loads jobs on gateway startup and re-scans the jobs directory for changes. Each job maintains its own persistent chat session so context accumulates across runs.
Long conversations are automatically compacted when the context window reaches 75% capacity. Old turns are summarized by the model while the most recent exchanges are preserved verbatim. You can also trigger compaction manually with /compact.
clotho # start REPL (default)
clotho "your prompt here" # start REPL with an initial prompt
clotho -p "prompt" # print mode β send prompt, print response, exit
echo "prompt" | clotho -p # print mode from stdin
clotho -p "prompt" --chat ID # print mode into an existing chat
clotho -p "prompt" --timeout 60
clotho run -d # start gateway as detached background process
clotho run --port 9000 # custom port
clotho setup # generate auth token
clotho setup --force # regenerate token
clotho sandbox build # build Docker sandbox imagePrint mode (-p) sends a single prompt and writes the raw response to stdout with no formatting β suitable for piping and scripts. Tool requests are auto-approved (gateway permission policy still applies). Default timeout is 300 seconds.
All config and persisted data lives in ~/.clotho/:
| Path | Contents |
|---|---|
config.json |
Permissions, sandbox settings, auth token |
profiles.json |
Model profiles |
projects/*.jsonl |
Chat history (one file per session) |
skills/*/SKILL.md |
Skill definitions |
discord/config.toml |
Discord bridge configuration |
discord/sessions.json |
Discord user/channel β chat ID mapping |
jobs/*.yaml |
Scheduled job definitions |
scheduler/jobs.sqlite |
APScheduler job state |
mcp/tokens/*.json |
OAuth tokens for MCP servers (one file per server) |
