added readme and install script
This commit is contained in:
11
.env.example
11
.env.example
@@ -32,3 +32,14 @@ OPENCODE_TIMEOUT=120
|
||||
|
||||
# --- Logging -----------------------------------------------------------------
|
||||
LOG_LEVEL=INFO
|
||||
|
||||
# --- Claude Code Runtime (alternative to OpenCode) --------------------------
|
||||
# Use --claude flag to switch: python main.py --claude
|
||||
# CLAUDE_MODEL=claude-sonnet-4-20250514
|
||||
# CLAUDE_TIMEOUT=120
|
||||
# CLAUDE_MAX_TURNS=3
|
||||
# CLAUDE_NO_TOOLS=true
|
||||
|
||||
# --- Memory System -----------------------------------------------------------
|
||||
# AETHEEL_WORKSPACE=~/.aetheel/workspace
|
||||
# AETHEEL_MEMORY_DB=~/.aetheel/memory.db
|
||||
|
||||
249
README.md
249
README.md
@@ -0,0 +1,249 @@
|
||||
<p align="center">
|
||||
<h1 align="center">⚔️ Aetheel</h1>
|
||||
<p align="center">
|
||||
<strong>A personal AI assistant that lives in Slack — with persistent memory, dual runtimes, and zero cloud dependencies.</strong>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="#quick-start">Quick Start</a> •
|
||||
<a href="#features">Features</a> •
|
||||
<a href="#architecture">Architecture</a> •
|
||||
<a href="#configuration">Configuration</a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### One-line install
|
||||
|
||||
```bash
|
||||
curl -fsSL http://10.0.0.59:3051/tanmay/Aetheel/raw/branch/main/install.sh | sh
|
||||
```
|
||||
|
||||
This will clone the repo, set up a Python virtual environment, install dependencies, and walk you through configuration.
|
||||
|
||||
### Manual install
|
||||
|
||||
```bash
|
||||
git clone http://10.0.0.59:3051/tanmay/Aetheel.git
|
||||
cd Aetheel
|
||||
uv sync # or: pip install -r requirements.txt
|
||||
cp .env.example .env
|
||||
# Edit .env with your Slack tokens
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
```bash
|
||||
# Default — OpenCode runtime
|
||||
uv run python main.py
|
||||
|
||||
# Claude Code runtime
|
||||
uv run python main.py --claude
|
||||
|
||||
# Test mode (echo handler, no AI)
|
||||
uv run python main.py --test
|
||||
|
||||
# Custom model
|
||||
uv run python main.py --model anthropic/claude-sonnet-4-20250514
|
||||
|
||||
# Debug logging
|
||||
uv run python main.py --log DEBUG
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### 🧠 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 over all memory files
|
||||
- **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** — Memory re-indexes when you edit `.md` files
|
||||
|
||||
### 🤖 Dual AI Runtimes
|
||||
| Runtime | Flag | System Prompt | Session Continuity |
|
||||
|---------|------|---------------|--------------------|
|
||||
| **OpenCode** (default) | `--cli` / `--sdk` | XML-injected into message | `--continue --session <id>` |
|
||||
| **Claude Code** | `--claude` | Native `--system-prompt` flag | `--continue --session-id <id>` |
|
||||
|
||||
Both return the same `AgentResponse` — zero code changes needed to switch.
|
||||
|
||||
### 💬 Slack Integration
|
||||
- **Socket Mode** — no public URL or webhook needed
|
||||
- **DMs + @mentions** — responds in both
|
||||
- **Thread isolation** — each thread gets its own AI session
|
||||
- **Chunked replies** — auto-splits long responses at Slack's 4000-char limit
|
||||
|
||||
### ⏰ Action Tags
|
||||
The AI can perform actions by including tags in its response:
|
||||
|
||||
```
|
||||
[ACTION:remind|2|Time to drink water! 💧]
|
||||
```
|
||||
|
||||
The system strips the tag from the visible response and schedules the action.
|
||||
|
||||
### 🔒 Local-First
|
||||
- Embeddings run locally (no OpenAI/Gemini API for memory)
|
||||
- Memory stored in `~/.aetheel/` — your data stays on your machine
|
||||
- Only the AI runtime (OpenCode/Claude) makes external API calls
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌──────────────┐
|
||||
│ Slack │ Socket Mode (no public URL)
|
||||
│ Workspace │
|
||||
└──────┬───────┘
|
||||
│ Events (DM, @mention)
|
||||
▼
|
||||
┌──────────────┐ ┌──────────────────┐
|
||||
│ Slack │────▶│ main.py │
|
||||
│ Adapter │ │ (ai_handler) │
|
||||
└──────────────┘ └────────┬─────────┘
|
||||
│
|
||||
┌─────────┴─────────┐
|
||||
▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ Memory │ │ AI Runtime │
|
||||
│ Manager │ │ (OpenCode │
|
||||
│ │ │ or Claude) │
|
||||
│ • SOUL.md │ │ │
|
||||
│ • USER.md │ │ subprocess │
|
||||
│ • MEMORY.md │ │ execution │
|
||||
│ • search │ └──────────────┘
|
||||
│ • session │
|
||||
│ logs │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
aetheel/
|
||||
├── main.py # Entry point — handler, memory init, action tags
|
||||
├── adapters/
|
||||
│ └── slack_adapter.py # Slack Socket Mode adapter
|
||||
├── agent/
|
||||
│ ├── opencode_runtime.py # OpenCode CLI/SDK runtime
|
||||
│ └── claude_runtime.py # Claude Code CLI runtime
|
||||
├── memory/
|
||||
│ ├── manager.py # MemoryManager — sync, search, identity files
|
||||
│ ├── embeddings.py # Local embeddings via fastembed
|
||||
│ ├── hybrid.py # Hybrid search (vector + BM25)
|
||||
│ ├── schema.py # SQLite schema (files, chunks, FTS5)
|
||||
│ ├── internal.py # Hashing, chunking, file discovery
|
||||
│ └── types.py # Config, result types
|
||||
├── docs/
|
||||
│ ├── memory-system.md # Memory architecture docs
|
||||
│ ├── opencode-setup.md # OpenCode install & config guide
|
||||
│ ├── slack-setup.md # Slack app setup guide
|
||||
│ └── opencode-integration-summary.md
|
||||
├── .env.example # Template for secrets
|
||||
├── pyproject.toml # Dependencies (uv/pip)
|
||||
└── install.sh # One-click installer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Required: Slack Tokens
|
||||
|
||||
| Variable | Where to get it |
|
||||
|----------|----------------|
|
||||
| `SLACK_BOT_TOKEN` | [api.slack.com/apps](https://api.slack.com/apps) → OAuth & Permissions → Bot Token (`xoxb-...`) |
|
||||
| `SLACK_APP_TOKEN` | [api.slack.com/apps](https://api.slack.com/apps) → Basic Info → App-Level Tokens (`xapp-...`) |
|
||||
|
||||
See [`docs/slack-setup.md`](docs/slack-setup.md) for full Slack app creation instructions.
|
||||
|
||||
### AI Runtime
|
||||
|
||||
#### OpenCode (default)
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `OPENCODE_MODE` | `cli` | `cli` (subprocess) or `sdk` (server API) |
|
||||
| `OPENCODE_MODEL` | auto | Model, e.g. `anthropic/claude-sonnet-4-20250514` |
|
||||
| `OPENCODE_TIMEOUT` | `120` | CLI timeout in seconds |
|
||||
| `OPENCODE_SERVER_URL` | `http://localhost:4096` | SDK mode server URL |
|
||||
| `OPENCODE_WORKSPACE` | `.` | Working directory for OpenCode |
|
||||
|
||||
#### Claude Code (`--claude`)
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `CLAUDE_MODEL` | auto | Model, e.g. `claude-sonnet-4-20250514` |
|
||||
| `CLAUDE_TIMEOUT` | `120` | CLI timeout in seconds |
|
||||
| `CLAUDE_MAX_TURNS` | `3` | Max agentic tool-use turns |
|
||||
| `CLAUDE_NO_TOOLS` | `true` | Disable tools for pure chat |
|
||||
|
||||
### Memory System
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `AETHEEL_WORKSPACE` | `~/.aetheel/workspace` | Path to memory files (SOUL.md, etc.) |
|
||||
| `AETHEEL_MEMORY_DB` | `~/.aetheel/memory.db` | SQLite database path |
|
||||
|
||||
### General
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
|
||||
|
||||
---
|
||||
|
||||
## Memory Files
|
||||
|
||||
Aetheel auto-creates three identity files in `~/.aetheel/workspace/`:
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SOUL.md` | Personality, values, communication style |
|
||||
| `USER.md` | User preferences, context, background |
|
||||
| `MEMORY.md` | Long-term notes, facts, things to remember |
|
||||
|
||||
Edit these files directly — changes are picked up automatically via file watching.
|
||||
|
||||
Session logs are saved to `~/.aetheel/workspace/daily/YYYY-MM-DD.md` and indexed for search.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Python 3.14+** (managed via [uv](https://docs.astral.sh/uv/))
|
||||
- **Slack workspace** with bot + app tokens
|
||||
- **One of:**
|
||||
- [OpenCode](https://opencode.ai) CLI — `curl -fsSL https://opencode.ai/install | bash`
|
||||
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) — `npm install -g @anthropic-ai/claude-code`
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# Run tests
|
||||
uv run python test_memory.py # Memory system smoke test
|
||||
uv run python test_slack.py # Slack adapter unit tests
|
||||
|
||||
# Check help
|
||||
uv run python main.py --help
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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>
|
||||
|
||||
244
install.sh
Executable file
244
install.sh
Executable file
@@ -0,0 +1,244 @@
|
||||
#!/usr/bin/env sh
|
||||
# =============================================================================
|
||||
# Aetheel — One-Click Installer
|
||||
# =============================================================================
|
||||
# Usage:
|
||||
# curl -fsSL http://10.0.0.59:3051/tanmay/Aetheel/raw/branch/main/install.sh | sh
|
||||
#
|
||||
# What this script does:
|
||||
# 1. Checks prerequisites (git, python/uv)
|
||||
# 2. Clones the repo
|
||||
# 3. Sets up Python environment & installs dependencies
|
||||
# 4. Creates .env from template
|
||||
# 5. Walks you through token configuration
|
||||
# 6. Optionally starts the bot
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Colors & Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
info() { printf "${BLUE}ℹ${NC} %s\n" "$1"; }
|
||||
success() { printf "${GREEN}✓${NC} %s\n" "$1"; }
|
||||
warn() { printf "${YELLOW}⚠${NC} %s\n" "$1"; }
|
||||
error() { printf "${RED}✗${NC} %s\n" "$1"; }
|
||||
step() { printf "\n${BOLD}${CYAN}▸ %s${NC}\n" "$1"; }
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Banner
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
printf "\n"
|
||||
printf "${BOLD}${CYAN}"
|
||||
printf " ╔══════════════════════════════════════════╗\n"
|
||||
printf " ║ ║\n"
|
||||
printf " ║ ⚔️ Aetheel Installer ║\n"
|
||||
printf " ║ Personal AI for Slack ║\n"
|
||||
printf " ║ ║\n"
|
||||
printf " ╚══════════════════════════════════════════╝\n"
|
||||
printf "${NC}\n"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. Check Prerequisites
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
step "Checking prerequisites"
|
||||
|
||||
# Git
|
||||
if command -v git >/dev/null 2>&1; then
|
||||
success "git $(git --version | awk '{print $3}')"
|
||||
else
|
||||
error "git is not installed"
|
||||
printf " Install: https://git-scm.com/downloads\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Python / uv
|
||||
HAS_UV=false
|
||||
HAS_PYTHON=false
|
||||
|
||||
if command -v uv >/dev/null 2>&1; then
|
||||
success "uv $(uv --version 2>/dev/null | head -1)"
|
||||
HAS_UV=true
|
||||
elif command -v python3 >/dev/null 2>&1; then
|
||||
PY_VER=$(python3 --version 2>&1 | awk '{print $2}')
|
||||
success "python3 ${PY_VER}"
|
||||
HAS_PYTHON=true
|
||||
elif command -v python >/dev/null 2>&1; then
|
||||
PY_VER=$(python --version 2>&1 | awk '{print $2}')
|
||||
success "python ${PY_VER}"
|
||||
HAS_PYTHON=true
|
||||
else
|
||||
error "Neither uv nor python3 found"
|
||||
printf " Install uv (recommended): ${BOLD}curl -LsSf https://astral.sh/uv/install.sh | sh${NC}\n"
|
||||
printf " Or install Python 3.14+: https://python.org/downloads\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# AI Runtime (optional check)
|
||||
if command -v opencode >/dev/null 2>&1; then
|
||||
success "opencode CLI found"
|
||||
elif command -v claude >/dev/null 2>&1; then
|
||||
success "claude CLI found"
|
||||
else
|
||||
warn "No AI runtime found (opencode or claude)"
|
||||
printf " You'll need one of:\n"
|
||||
printf " • OpenCode: curl -fsSL https://opencode.ai/install | bash\n"
|
||||
printf " • Claude Code: npm install -g @anthropic-ai/claude-code\n"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Choose Install Directory
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
step "Setting up Aetheel"
|
||||
|
||||
INSTALL_DIR="${AETHEEL_DIR:-$HOME/aetheel}"
|
||||
|
||||
if [ -d "$INSTALL_DIR" ]; then
|
||||
warn "Directory already exists: $INSTALL_DIR"
|
||||
printf " Pulling latest changes...\n"
|
||||
cd "$INSTALL_DIR"
|
||||
git pull --ff-only 2>/dev/null || warn "Could not pull (you may have local changes)"
|
||||
else
|
||||
info "Cloning into $INSTALL_DIR"
|
||||
git clone http://10.0.0.59:3051/tanmay/Aetheel.git "$INSTALL_DIR"
|
||||
cd "$INSTALL_DIR"
|
||||
success "Repository cloned"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. Install Dependencies
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
step "Installing dependencies"
|
||||
|
||||
if [ "$HAS_UV" = true ]; then
|
||||
info "Using uv for dependency management"
|
||||
uv sync 2>&1 | tail -5
|
||||
success "Dependencies installed via uv"
|
||||
else
|
||||
info "Using pip for dependency management"
|
||||
python3 -m venv .venv 2>/dev/null || python -m venv .venv
|
||||
. .venv/bin/activate
|
||||
pip install -r requirements.txt 2>&1 | tail -3
|
||||
success "Dependencies installed via pip"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4. Configure .env
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
step "Configuration"
|
||||
|
||||
if [ -f .env ]; then
|
||||
warn ".env already exists — skipping token setup"
|
||||
info "Edit $INSTALL_DIR/.env to update your tokens"
|
||||
else
|
||||
cp .env.example .env
|
||||
success "Created .env from template"
|
||||
|
||||
printf "\n"
|
||||
printf " ${BOLD}You need two Slack tokens to proceed:${NC}\n"
|
||||
printf " 1. Bot Token (xoxb-...) — OAuth & Permissions page\n"
|
||||
printf " 2. App Token (xapp-...) — Basic Information → App-Level Tokens\n"
|
||||
printf "\n"
|
||||
printf " See: ${CYAN}docs/slack-setup.md${NC} for full instructions\n"
|
||||
printf "\n"
|
||||
|
||||
# Interactive token entry
|
||||
printf " ${BOLD}Enter your Slack Bot Token${NC} (xoxb-...) or press Enter to skip: "
|
||||
read -r BOT_TOKEN
|
||||
if [ -n "$BOT_TOKEN" ]; then
|
||||
if command -v sed >/dev/null 2>&1; then
|
||||
sed -i.bak "s|SLACK_BOT_TOKEN=.*|SLACK_BOT_TOKEN=${BOT_TOKEN}|" .env
|
||||
rm -f .env.bak
|
||||
success "Bot token saved"
|
||||
fi
|
||||
else
|
||||
warn "Skipped — edit .env manually before starting"
|
||||
fi
|
||||
|
||||
printf " ${BOLD}Enter your Slack App Token${NC} (xapp-...) or press Enter to skip: "
|
||||
read -r APP_TOKEN
|
||||
if [ -n "$APP_TOKEN" ]; then
|
||||
if command -v sed >/dev/null 2>&1; then
|
||||
sed -i.bak "s|SLACK_APP_TOKEN=.*|SLACK_APP_TOKEN=${APP_TOKEN}|" .env
|
||||
rm -f .env.bak
|
||||
success "App token saved"
|
||||
fi
|
||||
else
|
||||
warn "Skipped — edit .env manually before starting"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5. Create Data Directories
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
step "Setting up data directories"
|
||||
|
||||
mkdir -p "$HOME/.aetheel/workspace/daily"
|
||||
success "Created ~/.aetheel/workspace/"
|
||||
info "Identity files (SOUL.md, USER.md, MEMORY.md) will be auto-generated on first run"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 6. Done!
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
printf "\n"
|
||||
printf "${BOLD}${GREEN}"
|
||||
printf " ╔══════════════════════════════════════════╗\n"
|
||||
printf " ║ ║\n"
|
||||
printf " ║ ✅ Aetheel is ready! ║\n"
|
||||
printf " ║ ║\n"
|
||||
printf " ╚══════════════════════════════════════════╝\n"
|
||||
printf "${NC}\n"
|
||||
|
||||
printf " ${BOLD}To start Aetheel:${NC}\n"
|
||||
printf "\n"
|
||||
printf " cd %s\n" "$INSTALL_DIR"
|
||||
|
||||
if [ "$HAS_UV" = true ]; then
|
||||
printf " uv run python main.py\n"
|
||||
else
|
||||
printf " source .venv/bin/activate\n"
|
||||
printf " python main.py\n"
|
||||
fi
|
||||
|
||||
printf "\n"
|
||||
printf " ${BOLD}Other commands:${NC}\n"
|
||||
printf " --claude Use Claude Code instead of OpenCode\n"
|
||||
printf " --test Echo mode (no AI, for testing Slack)\n"
|
||||
printf " --help Show all options\n"
|
||||
printf "\n"
|
||||
printf " ${BOLD}Files:${NC}\n"
|
||||
printf " Config: %s/.env\n" "$INSTALL_DIR"
|
||||
printf " Memory: ~/.aetheel/workspace/\n"
|
||||
printf " Docs: %s/docs/\n" "$INSTALL_DIR"
|
||||
printf "\n"
|
||||
|
||||
# Offer to start
|
||||
printf " ${BOLD}Start Aetheel now?${NC} [y/N] "
|
||||
read -r START_NOW
|
||||
if [ "$START_NOW" = "y" ] || [ "$START_NOW" = "Y" ]; then
|
||||
printf "\n"
|
||||
info "Starting Aetheel..."
|
||||
if [ "$HAS_UV" = true ]; then
|
||||
exec uv run python main.py
|
||||
else
|
||||
exec python main.py
|
||||
fi
|
||||
fi
|
||||
|
||||
printf "\n"
|
||||
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "aetheel"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
description = "A personal AI assistant that lives in Slack — with persistent memory, dual runtimes, and zero cloud dependencies."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.14"
|
||||
dependencies = [
|
||||
|
||||
Reference in New Issue
Block a user