Files
Aetheel/README.md
tanmay11k 82c2640481 feat: openclaw-style secrets (env.vars + \) and per-task model routing
- 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
2026-02-20 23:49:05 -05:00

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>