CheddahBot/CLAUDE.md

7.0 KiB

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)
    ↓
AgentRegistry (agent_registry.py)
  ├── default agent ← AgentConfig (config.py)
  ├── writer agent
  ├── researcher agent
  └── ops agent
    ↓
Agent (agent.py) ← Memory (memory.py, 4-layer, per-agent scoping)
    ↓                ← Skills (skills.py, markdown skills with frontmatter)
LLM Adapter (llm.py)
  ├── Chat brain: OpenRouter / Ollama / LM Studio (per-agent model override)
  └── Execution brain: Claude Code CLI (subprocess)
    ↓
Tool Registry (tools/__init__.py) ← auto-discovers tools in tools/
  ├── delegate_task → execution brain
  └── delegate_to_agent → cross-agent delegation (depth-limited)
    ↓
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

# Run the app
uv run python -m cheddahbot

# Run tests (124 tests)
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, multi-agent wiring
cheddahbot/agent.py Core agentic loop (chat + tool execution)
cheddahbot/agent_registry.py Multi-agent registry (named agents, default)
cheddahbot/llm.py Two-brain LLM adapter
cheddahbot/config.py Config + AgentConfig dataclasses
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 + scoping
cheddahbot/router.py System prompt builder
cheddahbot/skills.py Markdown skill registry (discovers skills/*.md)
cheddahbot/ui.py Gradio web interface
cheddahbot/tools/ Tool modules (auto-discovered)
cheddahbot/tools/delegate.py delegate_task + delegate_to_agent tools
config.yaml Runtime configuration (incl. agents section)
identity/SOUL.md Agent personality
identity/USER.md User profile
skills/ Markdown skill files with YAML frontmatter

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 = None to get config, db, agent, memory, agent_registry injected
  • Skills: .md files in skills/ with YAML frontmatter (name, description, tools, agents). Files without frontmatter are data files (skipped by registry)
  • Multi-agent: Configure agents in config.yaml under agents: key. Each agent has name, display_name, model (override), tools (whitelist), memory_scope. First agent is the default. Use delegate_to_agent tool for cross-agent delegation (depth limit: 3).
  • Memory scoping: Agents with memory_scope set use memory/{scope}/ subdirectory. Empty scope = shared memory/ root. Fallback search checks both scoped and shared directories.
  • 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 attachments: ClickUpClient.upload_attachment() uses module-level httpx.post() (not the shared client) for multipart uploads

ClickUp Skill Mapping

The scheduler maps ClickUp Work Category → tool name via config.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 (+ attachments uploaded)

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.pykv_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
  • test_scheduler_helpers.py_extract_docx_paths regex extraction from tool output

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