- Replace python-dotenv with config.json env.vars block + \ substitution - Add models section for per-task model routing (heartbeat, subagent, default) - Heartbeat/subagent tasks can use different models/providers than main chat - Remove python-dotenv from dependencies - Update all docs to reflect new config approach - Reorganize docs into project/ and research/ subdirectories
418 lines
16 KiB
Markdown
418 lines
16 KiB
Markdown
<p align="center">
|
|
<img src="static/logo.jpeg" alt="Aetheel Logo" width="180" />
|
|
<h1 align="center">Aetheel</h1>
|
|
<p align="center">
|
|
<strong>A personal AI assistant that lives in your chat — with persistent memory, dual runtimes, auto-failover, and zero cloud dependencies.</strong>
|
|
</p>
|
|
<p align="center">
|
|
<a href="#quick-start">Quick Start</a> •
|
|
<a href="#features">Features</a> •
|
|
<a href="#chat-commands">Commands</a> •
|
|
<a href="#architecture">Architecture</a> •
|
|
<a href="#configuration">Configuration</a> •
|
|
<a href="#docs">Docs</a>
|
|
</p>
|
|
</p>
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### One-line install
|
|
|
|
```bash
|
|
# If repo is public:
|
|
curl -fsSL http://10.0.0.59:3051/tanmay/Aetheel/raw/branch/main/install.sh | bash
|
|
|
|
# If repo is private (clone first):
|
|
git clone http://10.0.0.59:3051/tanmay/Aetheel.git && cd Aetheel && bash install.sh
|
|
```
|
|
|
|
The interactive installer handles everything:
|
|
- Checks prerequisites (Python 3.12+, uv)
|
|
- Installs dependencies
|
|
- Detects or installs AI runtimes (OpenCode / Claude Code)
|
|
- Walks you through token setup for Slack, Discord, Telegram
|
|
- Installs the `aetheel` shell command
|
|
- Sets up a background service (launchd on macOS, systemd on Linux)
|
|
|
|
### After install
|
|
|
|
```bash
|
|
aetheel start # Start the bot
|
|
aetheel stop # Stop the background service
|
|
aetheel restart # Restart the service
|
|
aetheel status # Check status
|
|
aetheel logs # Tail live logs
|
|
aetheel setup # Re-run setup wizard
|
|
aetheel update # Pull latest + update deps
|
|
aetheel doctor # Run diagnostics
|
|
aetheel config # Edit config.json
|
|
aetheel help # All options
|
|
```
|
|
|
|
### Manual install
|
|
|
|
```bash
|
|
git clone http://10.0.0.59:3051/tanmay/Aetheel.git
|
|
cd Aetheel
|
|
uv sync # or: pip install -r requirements.txt
|
|
uv run python main.py # start (edit ~/.aetheel/config.json for tokens)
|
|
```
|
|
|
|
Everything is config-driven — no flags required. See [Configuration](#configuration).
|
|
|
|
---
|
|
|
|
## Features
|
|
|
|
### 💬 Multi-Channel
|
|
|
|
| Channel | Connection | Auth | Setup |
|
|
|---------|-----------|------|-------|
|
|
| Slack | Socket Mode (no public URL) | Bot + App tokens | [docs/project/slack-setup.md](docs/project/slack-setup.md) |
|
|
| Discord | Gateway (no public URL) | Bot token | [docs/project/discord-setup.md](docs/project/discord-setup.md) |
|
|
| Telegram | Bot API polling | Bot token | @BotFather |
|
|
| WebChat | HTTP + WebSocket on localhost | None (localhost only) | Config: `webchat.enabled: true` |
|
|
| Webhooks | HTTP POST endpoints | Bearer token | Config: `webhooks.enabled: true` |
|
|
|
|
All adapters are config-driven. Set a token in `config.json` → `env.vars` and the adapter auto-enables — no flags needed.
|
|
|
|
### 🤖 Dual AI Runtimes with Live Switching
|
|
|
|
| Runtime | Engine | Providers | Session Continuity |
|
|
|---------|--------|-----------|-------------------|
|
|
| OpenCode | `opencode` | Anthropic, OpenAI, Google, any | `--continue --session` |
|
|
| Claude Code | `claude` | Anthropic | `--continue --session-id` |
|
|
|
|
Switch engines, models, and providers live from chat — no restart needed:
|
|
|
|
```
|
|
engine claude
|
|
model claude-sonnet-4-20250514
|
|
|
|
engine opencode
|
|
model openai/gpt-4o
|
|
provider openai
|
|
```
|
|
|
|
### 🔄 Auto-Failover & Usage Tracking
|
|
|
|
When a rate limit or quota error is detected:
|
|
|
|
1. You get notified in the channel
|
|
2. Aetheel automatically switches to the other engine and retries
|
|
3. If failover succeeds, the response is delivered seamlessly
|
|
|
|
Claude Code returns per-request cost (`cost_usd`), which is tracked and viewable via the `usage` command. Rate limit hits and failover counts are also tracked.
|
|
|
|
### 🧠 Persistent Memory System
|
|
|
|
- **Identity files** — `SOUL.md` (personality), `USER.md` (user profile), `MEMORY.md` (long-term notes)
|
|
- **Hybrid search** — 0.7 vector + 0.3 BM25 keyword scoring
|
|
- **Local embeddings** — fastembed (ONNX, BAAI/bge-small-en-v1.5, 384-dim), zero API calls
|
|
- **SQLite storage** — FTS5 full-text search + JSON vector embeddings
|
|
- **Session logs** — Conversations auto-saved to `daily/YYYY-MM-DD.md`
|
|
- **File watching** — Auto re-indexes when `.md` files change
|
|
|
|
### ⏰ Scheduler & Action Tags
|
|
|
|
The AI can trigger actions by including tags in its response:
|
|
|
|
| Tag | Effect |
|
|
|-----|--------|
|
|
| `[ACTION:remind\|5\|Drink water!]` | One-shot reminder in 5 minutes |
|
|
| `[ACTION:cron\|0 9 * * *\|Good morning!]` | Recurring cron job |
|
|
| `[ACTION:spawn\|Research Python 3.14]` | Background subagent task |
|
|
|
|
Jobs are persisted in SQLite and survive restarts.
|
|
|
|
### 🔧 More
|
|
|
|
- **Skills** — Teach the AI domain-specific behavior via `SKILL.md` files
|
|
- **Hooks** — Event-driven lifecycle hooks (startup, shutdown, commands)
|
|
- **Heartbeat** — Periodic proactive tasks via `HEARTBEAT.md`
|
|
- **Subagents** — Background AI tasks with results sent back to the channel
|
|
- **MCP Servers** — Extend the agent with external tool servers
|
|
- **WebChat** — Browser-based chat UI at `http://localhost:8080`
|
|
- **Webhooks** — HTTP endpoints for external systems to trigger the agent
|
|
|
|
### 🔒 Local-First
|
|
|
|
- Embeddings run locally (no API calls for memory)
|
|
- All data stored in `~/.aetheel/` — your data stays on your machine
|
|
- Only the AI runtime makes external API calls
|
|
|
|
---
|
|
|
|
## Chat Commands
|
|
|
|
Type these as regular messages in any channel or DM. No `/` prefix needed.
|
|
|
|
> In Slack channels, Slack intercepts `/` as native slash commands. Use the prefix-free form (e.g. `engine claude` not `/engine claude`). In DMs and other adapters, both forms work.
|
|
|
|
### General
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `status` | Bot status, engine, model, sessions |
|
|
| `help` | All available commands |
|
|
| `time` | Server time |
|
|
| `sessions` | Active session count |
|
|
| `reload` | Reload config and skills |
|
|
| `subagents` | List active background tasks |
|
|
|
|
### Runtime (live, no restart)
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `engine` | Show current engine |
|
|
| `engine opencode` | Switch to OpenCode |
|
|
| `engine claude` | Switch to Claude Code |
|
|
| `model` | Show current model |
|
|
| `model <name>` | Switch model |
|
|
| `provider` | Show current provider (OpenCode only) |
|
|
| `provider <name>` | Switch provider |
|
|
| `usage` | LLM usage stats, costs, rate limits |
|
|
|
|
### Config
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `config` | Config summary |
|
|
| `config show` | Full config.json |
|
|
| `config set <key> <value>` | Edit config (e.g. `config set runtime.timeout_seconds 300`) |
|
|
|
|
### Scheduler
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `cron list` | List scheduled jobs |
|
|
| `cron remove <id>` | Remove a job |
|
|
|
|
See [docs/project/commands.md](docs/project/commands.md) for the full reference including terminal commands.
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|
│ Slack │ │ Discord │ │ Telegram │ │ WebChat │
|
|
│ (Socket) │ │ (Gateway) │ │ (Polling) │ │ (WebSocket) │
|
|
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘
|
|
│ │ │ │
|
|
└────────────────┴────────────────┴────────────────┘
|
|
│
|
|
┌───────────┴───────────┐
|
|
│ main.py │
|
|
│ (ai_handler) │
|
|
│ │
|
|
│ • Command routing │
|
|
│ • Action tag parsing │
|
|
│ • Usage tracking │
|
|
│ • Auto-failover │
|
|
└───┬──────────┬────────┘
|
|
│ │
|
|
┌─────────┴──┐ ┌───┴──────────┐
|
|
│ Memory │ │ AI Runtime │
|
|
│ Manager │ │ │
|
|
│ │ │ OpenCode ◄──►│ Auto-failover
|
|
│ • SOUL.md │ │ Claude ◄──►│
|
|
│ • search │ │ │
|
|
│ • logs │ │ subprocess │
|
|
└────────────┘ └──────────────┘
|
|
│
|
|
┌─────┴──────┐
|
|
│ Scheduler │ Skills, Hooks, Heartbeat,
|
|
│ Subagents │ Webhooks, MCP Servers
|
|
└────────────┘
|
|
```
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
aetheel/
|
|
├── main.py # Entry point, command routing, failover
|
|
├── config.py # Config loading (config.json with env.vars + ${VAR})
|
|
├── cli.py # Click CLI (aetheel command)
|
|
├── install.sh # Interactive installer + setup wizard
|
|
├── adapters/
|
|
│ ├── base.py # BaseAdapter + IncomingMessage
|
|
│ ├── slack_adapter.py # Slack Socket Mode
|
|
│ ├── discord_adapter.py # Discord Gateway
|
|
│ ├── telegram_adapter.py # Telegram Bot API
|
|
│ └── webchat_adapter.py # Browser WebSocket chat
|
|
├── agent/
|
|
│ ├── opencode_runtime.py # OpenCode CLI/SDK + rate limit detection
|
|
│ ├── claude_runtime.py # Claude Code CLI + usage extraction
|
|
│ └── subagent.py # Background subagent manager
|
|
├── memory/
|
|
│ ├── manager.py # Sync, search, identity files, session logs
|
|
│ ├── embeddings.py # Local embeddings (fastembed)
|
|
│ ├── hybrid.py # Hybrid search (vector + BM25)
|
|
│ ├── schema.py # SQLite schema
|
|
│ ├── internal.py # Hashing, chunking, file discovery
|
|
│ └── types.py # Config and result types
|
|
├── scheduler/
|
|
│ ├── scheduler.py # APScheduler with SQLite persistence
|
|
│ └── store.py # Job store
|
|
├── skills/ # Skill discovery and context injection
|
|
├── hooks/ # Lifecycle hook system
|
|
├── heartbeat/ # Periodic proactive tasks
|
|
├── webhooks/ # HTTP webhook receiver
|
|
├── static/
|
|
│ └── chat.html # WebChat browser UI
|
|
├── docs/
|
|
│ ├── project/ # Aetheel documentation
|
|
│ │ ├── commands.md # Full command reference
|
|
│ │ ├── setup.md # Detailed setup guide
|
|
│ │ ├── configuration.md # Config deep dive
|
|
│ │ ├── features-guide.md # Feature walkthrough
|
|
│ │ ├── memory-system.md # Memory architecture
|
|
│ │ ├── security-audit.md # Security audit findings
|
|
│ │ ├── slack-setup.md # Slack app creation guide
|
|
│ │ └── discord-setup.md # Discord bot setup guide
|
|
│ └── research/ # External project research & comparisons
|
|
├── tests/ # Test suite
|
|
├── .env.example # Legacy secrets template (migration notes)
|
|
└── pyproject.toml # Dependencies
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
All settings and secrets live in `~/.aetheel/config.json`. Secrets go in the `env.vars` block and are referenced via `${VAR}` syntax.
|
|
|
|
The install script writes the config file during setup. You can also edit from chat using `config set`.
|
|
|
|
### Config File
|
|
|
|
```jsonc
|
|
{
|
|
"env": {
|
|
"vars": {
|
|
"SLACK_BOT_TOKEN": "xoxb-...",
|
|
"SLACK_APP_TOKEN": "xapp-...",
|
|
"DISCORD_BOT_TOKEN": "",
|
|
"TELEGRAM_BOT_TOKEN": "",
|
|
"ANTHROPIC_API_KEY": ""
|
|
}
|
|
},
|
|
"runtime": {
|
|
"engine": "opencode", // "opencode" or "claude"
|
|
"mode": "cli", // "cli" or "sdk"
|
|
"model": null, // e.g. "anthropic/claude-sonnet-4-20250514"
|
|
"provider": null, // e.g. "anthropic", "openai", "google"
|
|
"timeout_seconds": 120
|
|
},
|
|
"claude": {
|
|
"model": null, // e.g. "claude-sonnet-4-20250514"
|
|
"max_turns": 3,
|
|
"no_tools": false
|
|
},
|
|
"slack": { "enabled": true, "bot_token": "${SLACK_BOT_TOKEN}", "app_token": "${SLACK_APP_TOKEN}" },
|
|
"telegram": { "enabled": false, "bot_token": "${TELEGRAM_BOT_TOKEN}" },
|
|
"discord": { "enabled": false, "bot_token": "${DISCORD_BOT_TOKEN}", "listen_channels": [] },
|
|
"webchat": { "enabled": false, "port": 8080, "host": "127.0.0.1" },
|
|
"webhooks": { "enabled": false, "port": 8090, "token": "" },
|
|
"memory": { "workspace": "~/.aetheel/workspace", "db_path": "~/.aetheel/memory.db" },
|
|
"heartbeat": { "enabled": true, "default_channel": "slack" },
|
|
"models": { "heartbeat": null, "subagent": null, "default": null },
|
|
"hooks": { "enabled": true },
|
|
"mcp": { "servers": {} }
|
|
}
|
|
```
|
|
|
|
Adapters auto-enable when their token is set in `env.vars`, even without `enabled: true`.
|
|
|
|
### Environment Variable Overrides
|
|
|
|
Process env vars override everything. Useful for CI, Docker, or systemd:
|
|
|
|
| Variable | Overrides |
|
|
|----------|-----------|
|
|
| `AETHEEL_ENGINE` | `runtime.engine` |
|
|
| `OPENCODE_MODE` | `runtime.mode` |
|
|
| `OPENCODE_MODEL` | `runtime.model` |
|
|
| `OPENCODE_PROVIDER` | `runtime.provider` |
|
|
| `CLAUDE_MODEL` | `claude.model` |
|
|
| `CLAUDE_TIMEOUT` | `claude.timeout_seconds` |
|
|
| `CLAUDE_MAX_TURNS` | `claude.max_turns` |
|
|
| `LOG_LEVEL` | `log_level` |
|
|
|
|
---
|
|
|
|
## Memory Files
|
|
|
|
Auto-created in `~/.aetheel/workspace/` (or personalized during setup):
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `SOUL.md` | Personality, values, communication style |
|
|
| `USER.md` | User preferences, context, background |
|
|
| `MEMORY.md` | Long-term notes, facts, things to remember |
|
|
|
|
All agents share the same identity files — the main agent and any background subagents it spawns all read from the same `SOUL.md`, `USER.md`, and `MEMORY.md`. This is by design: subagents are workers for the same assistant, not separate personalities.
|
|
|
|
The installer lets you choose a personality preset (default, professional, casual, or custom) and fills in `USER.md` with your name, role, timezone, and preferences interactively.
|
|
|
|
Edit these files directly anytime — changes are picked up automatically via file watching.
|
|
|
|
Session logs: `~/.aetheel/workspace/daily/YYYY-MM-DD.md`
|
|
|
|
---
|
|
|
|
## Prerequisites
|
|
|
|
- Python 3.12+ (managed via [uv](https://docs.astral.sh/uv/))
|
|
- At least one chat platform token (Slack, Discord, Telegram, or WebChat)
|
|
- At least one AI runtime:
|
|
- [OpenCode](https://opencode.ai) — `curl -fsSL https://opencode.ai/install | bash`
|
|
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) — `npm install -g @anthropic-ai/claude-code`
|
|
|
|
The installer handles all of this interactively.
|
|
|
|
---
|
|
|
|
## Development
|
|
|
|
```bash
|
|
# Run full test suite
|
|
uv run python test_all.py
|
|
|
|
# Run pytest
|
|
uv run python -m pytest tests/ -v
|
|
|
|
# Diagnostics
|
|
uv run python cli.py doctor
|
|
```
|
|
|
|
---
|
|
|
|
## Docs
|
|
|
|
| Document | Description |
|
|
|----------|-------------|
|
|
| [commands.md](docs/project/commands.md) | Full command reference (chat + terminal) |
|
|
| [setup.md](docs/project/setup.md) | Detailed setup guide |
|
|
| [configuration.md](docs/project/configuration.md) | Config deep dive |
|
|
| [security-audit.md](docs/project/security-audit.md) | Security audit findings |
|
|
| [memory-system.md](docs/project/memory-system.md) | Memory architecture |
|
|
| [features-guide.md](docs/project/features-guide.md) | Feature walkthrough |
|
|
| [slack-setup.md](docs/project/slack-setup.md) | Slack app creation |
|
|
| [discord-setup.md](docs/project/discord-setup.md) | Discord bot setup |
|
|
|
|
---
|
|
|
|
## Inspired By
|
|
|
|
Built with inspiration from [OpenClaw](https://github.com/nichochar/openclaw) — a TypeScript AI agent framework. Aetheel reimplements the core concepts (memory, hybrid search, session management) in Python with a local-first philosophy.
|
|
|
|
---
|
|
|
|
<p align="center">
|
|
<sub>Made with ❤️ and a lot of Claude</sub>
|
|
</p>
|