feat: config-driven architecture, install wizard, live runtime switching, usage tracking, auto-failover

Major changes:
- Config-driven adapters: all channels (Slack, Discord, Telegram, WebChat, Webhooks) controlled via config.json with enabled flags and token auto-detection, no CLI flags required
- Runtime engine field: runtime.engine selects opencode/claude from config
- Interactive install script: 8-phase setup wizard with AI runtime detection/installation, token setup, identity file personalization (personality presets), aetheel CLI command, background service (launchd/systemd)
- Live runtime switching: /engine, /model, /provider commands hot-swap the AI runtime from chat without restart, changes persisted to config.json
- Usage tracking: per-request cost extraction from Claude Code JSON output, cumulative stats via /usage command
- Auto-failover: rate limit detection on both runtimes, automatic switch to other engine on quota errors with user notification
- Chat commands work without / prefix (Slack intercepts / in channels), commands: engine, model, provider, config, usage, reload, cron, subagents, status, help
- /config set for editing config.json from chat with dotted key notation
- Security audit saved to docs/security-audit.md
- Full command reference in docs/commands.md
- Future changes doc with NanoClaw agent teams analysis
- Logo added to README and WebChat UI
- README fully rewritten with all features documented
This commit is contained in:
2026-02-18 01:07:12 -05:00
parent 41b2f9a593
commit 6d73f74e0b
41 changed files with 11363 additions and 437 deletions

326
docs/configuration.md Normal file
View File

@@ -0,0 +1,326 @@
# Configuration Guide
> How Aetheel loads its settings — config file, secrets, and CLI overrides.
---
## Table of Contents
1. [Overview](#overview)
2. [Config File](#config-file)
3. [Secrets (.env)](#secrets)
4. [CLI Overrides](#cli-overrides)
5. [Priority Order](#priority-order)
6. [Reference](#reference)
7. [Examples](#examples)
---
## Overview
Aetheel uses a two-file configuration approach:
| File | Location | Purpose |
|------|----------|---------|
| `config.json` | `~/.aetheel/config.json` | All non-secret settings (model, timeouts, channels, paths) |
| `.env` | Project root | Secrets only (tokens, passwords, API keys) |
On first run, Aetheel auto-creates `~/.aetheel/config.json` with sensible defaults. You only need to edit what you want to change.
---
## Config File
Located at `~/.aetheel/config.json`. Created automatically on first run.
### Full Default Config
```json
{
"log_level": "INFO",
"runtime": {
"mode": "cli",
"model": null,
"timeout_seconds": 120,
"server_url": "http://localhost:4096",
"format": "json"
},
"claude": {
"model": null,
"timeout_seconds": 120,
"max_turns": 3,
"no_tools": true
},
"discord": {
"listen_channels": []
},
"memory": {
"workspace": "~/.aetheel/workspace",
"db_path": "~/.aetheel/memory.db"
},
"scheduler": {
"db_path": "~/.aetheel/scheduler.db"
}
}
```
### Section: `runtime`
Controls the OpenCode AI runtime (default).
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `mode` | string | `"cli"` | `"cli"` (subprocess) or `"sdk"` (opencode serve API) |
| `model` | string\|null | `null` | Model ID, e.g. `"anthropic/claude-sonnet-4-20250514"`. Null uses OpenCode's default. |
| `timeout_seconds` | int | `120` | Max seconds to wait for a response |
| `server_url` | string | `"http://localhost:4096"` | OpenCode server URL (SDK mode only) |
| `format` | string | `"json"` | CLI output format: `"json"` (structured) or `"default"` (plain text) |
| `workspace` | string\|null | `null` | Working directory for OpenCode. Null uses current directory. |
| `provider` | string\|null | `null` | Provider override, e.g. `"anthropic"`, `"openai"` |
### Section: `claude`
Controls the Claude Code runtime (used with `--claude` flag).
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `model` | string\|null | `null` | Model ID, e.g. `"claude-sonnet-4-20250514"` |
| `timeout_seconds` | int | `120` | Max seconds to wait for a response |
| `max_turns` | int | `3` | Max agentic tool-use turns per request |
| `no_tools` | bool | `true` | Disable tools for pure conversation mode |
### Section: `discord`
Discord-specific settings (non-secret).
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `listen_channels` | list[string] | `[]` | Channel IDs where the bot responds to all messages (no @mention needed) |
### Section: `memory`
Memory system paths.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `workspace` | string | `"~/.aetheel/workspace"` | Directory for identity files (SOUL.md, USER.md, MEMORY.md) and skills |
| `db_path` | string | `"~/.aetheel/memory.db"` | SQLite database for embeddings and search index |
### Section: `scheduler`
Scheduler storage.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `db_path` | string | `"~/.aetheel/scheduler.db"` | SQLite database for persisted scheduled jobs |
### Top-level
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `log_level` | string | `"INFO"` | `"DEBUG"`, `"INFO"`, `"WARNING"`, `"ERROR"` |
---
## Secrets
Secrets live in `.env` in the project root. These are never written to `config.json`.
Copy the template:
```bash
cp .env.example .env
```
### Required (at least one adapter)
| Variable | Format | Description |
|----------|--------|-------------|
| `SLACK_BOT_TOKEN` | `xoxb-...` | Slack bot OAuth token |
| `SLACK_APP_TOKEN` | `xapp-...` | Slack app-level token (Socket Mode) |
### Optional
| Variable | Format | Description |
|----------|--------|-------------|
| `TELEGRAM_BOT_TOKEN` | string | Telegram bot token from @BotFather |
| `DISCORD_BOT_TOKEN` | string | Discord bot token from Developer Portal |
| `OPENCODE_SERVER_PASSWORD` | string | Password for `opencode serve` (SDK mode) |
| `ANTHROPIC_API_KEY` | `sk-ant-...` | Anthropic API key (Claude Code runtime) |
### Environment Variable Overrides
Any config.json setting can also be overridden via environment variables. These take priority over the config file:
| Env Variable | Overrides |
|-------------|-----------|
| `LOG_LEVEL` | `log_level` |
| `OPENCODE_MODE` | `runtime.mode` |
| `OPENCODE_MODEL` | `runtime.model` |
| `OPENCODE_TIMEOUT` | `runtime.timeout_seconds` |
| `OPENCODE_SERVER_URL` | `runtime.server_url` |
| `OPENCODE_PROVIDER` | `runtime.provider` |
| `OPENCODE_WORKSPACE` | `runtime.workspace` |
| `CLAUDE_MODEL` | `claude.model` |
| `CLAUDE_TIMEOUT` | `claude.timeout_seconds` |
| `CLAUDE_MAX_TURNS` | `claude.max_turns` |
| `CLAUDE_NO_TOOLS` | `claude.no_tools` |
| `DISCORD_LISTEN_CHANNELS` | `discord.listen_channels` (comma-separated) |
| `AETHEEL_WORKSPACE` | `memory.workspace` |
| `AETHEEL_MEMORY_DB` | `memory.db_path` |
---
## CLI Overrides
CLI arguments have the highest priority and override both config.json and environment variables.
```bash
python main.py [options]
```
| Flag | Description |
|------|-------------|
| `--model <id>` | Override model for both runtimes |
| `--claude` | Use Claude Code runtime instead of OpenCode |
| `--cli` | Force CLI mode (OpenCode) |
| `--sdk` | Force SDK mode (OpenCode) |
| `--telegram` | Enable Telegram adapter |
| `--discord` | Enable Discord adapter |
| `--test` | Use echo handler (no AI) |
| `--log <level>` | Override log level |
---
## Priority Order
When the same setting is defined in multiple places, the highest priority wins:
```
CLI arguments > Environment variables (.env) > config.json > Defaults
```
For example, if `config.json` sets `runtime.model` to `"anthropic/claude-sonnet-4-20250514"` but you run `python main.py --model openai/gpt-5.1`, the CLI argument wins.
---
## Reference
### File Locations
| File | Path | Git-tracked |
|------|------|-------------|
| Config | `~/.aetheel/config.json` | No |
| Secrets | `<project>/.env` | No (in .gitignore) |
| Memory DB | `~/.aetheel/memory.db` | No |
| Session DB | `~/.aetheel/sessions.db` | No |
| Scheduler DB | `~/.aetheel/scheduler.db` | No |
| Identity files | `~/.aetheel/workspace/SOUL.md` etc. | No |
| Session logs | `~/.aetheel/workspace/daily/` | No |
### Data Directory Structure
```
~/.aetheel/
├── config.json # Main configuration
├── memory.db # Embeddings + search index
├── sessions.db # Persistent session mappings
├── scheduler.db # Scheduled jobs
└── workspace/
├── SOUL.md # Bot personality
├── USER.md # User profile
├── MEMORY.md # Long-term memory
├── skills/ # Skill definitions
│ └── <name>/
│ └── SKILL.md
└── daily/ # Session logs
└── YYYY-MM-DD.md
```
---
## Examples
### Minimal Setup (Slack + OpenCode CLI)
`.env`:
```env
SLACK_BOT_TOKEN=xoxb-your-token
SLACK_APP_TOKEN=xapp-your-token
```
No config.json changes needed — defaults work.
```bash
python main.py
```
### Custom Model + SDK Mode
`~/.aetheel/config.json`:
```json
{
"runtime": {
"mode": "sdk",
"model": "anthropic/claude-sonnet-4-20250514",
"server_url": "http://localhost:4096"
}
}
```
Start OpenCode server first, then Aetheel:
```bash
opencode serve --port 4096
python main.py
```
### Discord with Listen Channels
`~/.aetheel/config.json`:
```json
{
"discord": {
"listen_channels": ["1234567890123456"]
}
}
```
`.env`:
```env
DISCORD_BOT_TOKEN=your-discord-token
```
```bash
python main.py --discord
```
### Multi-Channel (Slack + Discord + Telegram)
`.env`:
```env
SLACK_BOT_TOKEN=xoxb-your-token
SLACK_APP_TOKEN=xapp-your-token
DISCORD_BOT_TOKEN=your-discord-token
TELEGRAM_BOT_TOKEN=your-telegram-token
```
```bash
python main.py --discord --telegram
```
### Claude Code Runtime
`~/.aetheel/config.json`:
```json
{
"claude": {
"model": "claude-sonnet-4-20250514",
"max_turns": 5,
"no_tools": false
}
}
```
```bash
python main.py --claude
```