CheddahBot/clickup_runner/README.md

149 lines
4.0 KiB
Markdown

# ClickUp Runner
Headless background service that polls ClickUp for tasks with the
"Delegate to Claude" checkbox checked, routes them through a skill map
based on task type + stage, runs Claude Code headless, and posts results
back to ClickUp.
## Quick Start
```bash
# Set required env vars (or put them in .env at repo root)
export CLICKUP_API_TOKEN="pk_..."
export CLICKUP_SPACE_ID="..."
# Run the runner
uv run python -m clickup_runner
```
## How It Works
1. Every 720 seconds, polls all "Overall" lists in the ClickUp space
2. Finds tasks where:
- "Delegate to Claude" checkbox is checked
- Due date is today or earlier
3. Reads the task's Work Category and Stage fields
4. Looks up the skill route in `skill_map.py`
5. Dispatches to either:
- **AutoCora handler** (for `run_cora` stage): submits a Cora job to the NAS queue
- **Claude Code handler**: runs `claude -p` with the skill file as system prompt
6. On success: advances Stage, sets next status, posts comment, attaches output files
7. On error: sets Error checkbox, posts error comment with fix instructions
8. Always unchecks "Delegate to Claude" after processing
## Configuration
Config is loaded from `clickup_runner.yaml` at the repo root (optional),
with env var overrides.
### clickup_runner.yaml
```yaml
clickup:
space_id: "your_space_id"
task_type_field_name: "Work Category"
delegate_field_name: "Delegate to Claude"
stage_field_name: "Stage"
error_field_name: "Error"
ai_working_status: "ai working"
review_status: "review"
autocora:
jobs_dir: "//PennQnap1/SHARE1/AutoCora/jobs"
results_dir: "//PennQnap1/SHARE1/AutoCora/results"
xlsx_dir: "//PennQnap1/SHARE1/Cora72-for-macro"
poll_interval_seconds: 120
nas:
generated_dir: "//PennQnap1/SHARE1/generated"
runner:
poll_interval_seconds: 720
claude_timeout_seconds: 2700
max_turns_default: 10
```
### Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| `CLICKUP_API_TOKEN` | Yes | ClickUp API token |
| `CLICKUP_SPACE_ID` | Yes | ClickUp space to poll |
| `NTFY_ERROR_TOPIC` | No | ntfy.sh topic for error notifications |
| `NTFY_SUCCESS_TOPIC` | No | ntfy.sh topic for success notifications |
## ClickUp Custom Fields Required
These must exist in your ClickUp space:
| Field | Type | Purpose |
|-------|------|---------|
| Delegate to Claude | Checkbox | Trigger -- checked = process this task |
| Stage | Dropdown | Pipeline position (run_cora, outline, draft, etc.) |
| Error | Checkbox | Flagged when processing fails |
| Work Category | Dropdown | Task type (Content Creation, Press Release, etc.) |
## Skill Map
The routing table lives in `skill_map.py`. Each task type has a sequence
of stages, and each stage maps to either an AutoCora job or a Claude Code
skill file.
### Content Creation
```
run_cora -> outline -> draft -> final
```
### On Page Optimization
```
run_cora -> outline -> draft -> hidden div -> final
```
### Press Release
```
draft -> final
```
### Link Building
```
run_cora -> build -> final
```
## Adding a New Task Type
1. Add an entry to `SKILL_MAP` in `skill_map.py`
2. Write the skill `.md` file(s) in `skills/`
3. Add the Work Category value in ClickUp
4. Add the Stage dropdown values in ClickUp
## Statuses
| Status | Owner | Meaning |
|--------|-------|---------|
| To Do | Nobody | Not started |
| In Progress | Human | Human is working on it |
| Needs Input | Human | Blocked, needs info |
| AI Working | Claude | Runner is processing |
| Review | Human | Output ready for human review |
| Client Review | Client | Sent to client |
| Complete | Nobody | Done |
## Logs
- Console output: INFO level
- File log: `logs/clickup_runner.log` (DEBUG level)
- Run history: `data/clickup_runner.db` (run_log table)
## Tests
```bash
# Unit tests only (no credentials needed)
uv run pytest tests/test_clickup_runner/ -m "not integration"
# Full suite (needs CLICKUP_API_TOKEN)
uv run pytest tests/test_clickup_runner/
# Specific test
uv run pytest tests/test_clickup_runner/test_skill_map.py -v
```