CheddahBot/CLAUDE.md

135 lines
5.5 KiB
Markdown

# CLAUDE.md
## Project Overview
CheddahBot is a personal AI assistant for Bryan's SEO/AI agency and general life. It has a two-brain architecture: a **chat brain** (OpenRouter/Ollama/LM Studio) for conversational UI, and an **execution brain** (Claude Code CLI) for autonomous tasks like press releases, file operations, and shell commands among others.
The bot polls ClickUp for tasks, maps them to skills, and auto-executes or asks permission — then reports results back to ClickUp and the chat UI.
## Coding Workflow Rules - while we are working on building/changing the code
- Before making any changes, explain WHAT you plan to change and WHY
- Wait for my approval before editing files UNLESS I TELL YOU I AM GOING AWAY FOR A BIT - then you can use your judgement but commit the code at every big change.
- After making changes, provide a brief summary of every file modified and what changed
- If you encounter a problem during implementation, STOP and explain it instead of trying to fix it silently
- Never refactor, rename, or reorganize code beyond what was explicitly asked for
## Architecture
```
Gradio UI (ui.py)
Agent (agent.py) ← Memory (memory.py, 4-layer: identity/long-term/daily/semantic)
LLM Adapter (llm.py)
├── Chat brain: OpenRouter / Ollama / LM Studio
└── Execution brain: Claude Code CLI (subprocess)
Tool Registry (tools/__init__.py) ← auto-discovers tools in tools/
Scheduler (scheduler.py)
├── Poll loop: cron-based scheduled tasks
├── Heartbeat: periodic checklist from HEARTBEAT.md
└── ClickUp loop: polls ClickUp → maps to skills → executes
NotificationBus (notifications.py) → Gradio / future Discord / Slack
```
## Commands
```bash
# Run the app
uv run python -m cheddahbot
# Run tests (118 tests, ~3s)
uv run pytest
# Run tests verbose
uv run pytest -v --no-cov
# Run only integration tests (requires live ClickUp API token)
uv run pytest -m integration
# Lint
uv run ruff check .
# Format
uv run ruff format .
# Add a dependency
uv add <package>
# Add a dev/test dependency
uv add --group test <package>
```
## Key Files
| File | Purpose |
|------|---------|
| `cheddahbot/__main__.py` | Entry point, wires all components |
| `cheddahbot/agent.py` | Core agentic loop (chat + tool execution) |
| `cheddahbot/llm.py` | Two-brain LLM adapter |
| `cheddahbot/config.py` | Dataclass config (env → YAML → defaults) |
| `cheddahbot/db.py` | SQLite persistence (WAL, thread-safe) |
| `cheddahbot/scheduler.py` | Three daemon threads: poll, heartbeat, ClickUp |
| `cheddahbot/clickup.py` | ClickUp REST API v2 client (httpx) |
| `cheddahbot/notifications.py` | UI-agnostic pub/sub notification bus |
| `cheddahbot/memory.py` | 4-layer memory with semantic search |
| `cheddahbot/router.py` | System prompt builder |
| `cheddahbot/ui.py` | Gradio web interface |
| `cheddahbot/tools/` | Tool modules (auto-discovered) |
| `config.yaml` | Runtime configuration |
| `identity/SOUL.md` | Agent personality |
| `identity/USER.md` | User profile |
| `skills/` | Prompt templates for tools (press releases, etc.) |
## Conventions
- **Config precedence**: env vars > config.yaml > dataclass defaults
- **ClickUp env vars**: `CLICKUP_API_TOKEN`, `CLICKUP_WORKSPACE_ID`, `CLICKUP_SPACE_ID`
- **Tool registration**: Use the `@tool("name", "description", category="cat")` decorator in any file under `cheddahbot/tools/` — auto-discovered on startup
- **Tool context**: Tools can accept `ctx: dict = None` to get `config`, `db`, `agent`, `memory` injected
- **Database**: SQLite with WAL mode, thread-local connections via `threading.local()`
- **KV store**: Task state stored as JSON at `clickup:task:{id}:state` keys
- **ClickUp field mapping**: `Work Category` field (not `Task Type`) identifies task types like "Press Release", "Link Building". The `Client` field (not `Company`) holds the client name.
- **Notifications**: All scheduler events go through `NotificationBus.push()`, never directly to a UI
- **Tests**: Use `respx` to mock httpx calls, `tmp_db` fixture for isolated SQLite instances
## ClickUp Skill Mapping
The scheduler maps ClickUp `Work Category` → tool name via `config.yaml`:
```yaml
skill_map:
"Press Release":
tool: "write_press_releases"
auto_execute: true
field_mapping:
topic: "task_name" # uses ClickUp task name
company_name: "Client" # looks up "Client" custom field
```
Task lifecycle: `to do` → discovered → approved/awaiting_approval → executing → completed/failed
## Testing
Tests live in `tests/` and use pytest. All tests run offline with mocked APIs.
- `test_clickup.py` — API response parsing + HTTP client (respx mocks)
- `test_db.py``kv_scan` and notifications table methods
- `test_notifications.py` — NotificationBus pub/sub behavior
- `test_clickup_tools.py` — Chat tool state machine (approve/decline)
- `test_email.py` — EmailClient SMTP send + attachments (mocked)
- `test_docx_export.py` — Plain text → .docx formatting and file creation
- `test_press_advantage.py` — Press Advantage API client, company parsing, link building, submit tool
Fixtures in `conftest.py`: `tmp_db` (fresh SQLite), `sample_clickup_task_data` (realistic API response).
## Don't
- Don't edit `.env` — it contains secrets
- Don't manually activate venvs — use `uv run`
- Don't add to `requirements.txt` — use `uv add` (pyproject.toml)
- Don't call tools directly from UI code — go through `NotificationBus` for scheduler events
- Don't store ClickUp state outside of `kv_store` — it's the single source of truth