Replace Claude-based link building with direct subprocess calls to
Big-Link-Man CLI. The build stage now runs ingest-cora + generate-batch
deterministically without LLM involvement.
- New clickup_runner/blm.py: BLM subprocess runner (ported from old linkbuilding.py)
- New handler="blm" in skill_map for Link Building build stage
- Add BLMConfig to config.py (blm_dir, cora_inbox, timeout)
- Add task-specific fields (Keyword, CLIFlags, etc.) to build_prompt
- Strip YAML frontmatter from skill files in read_skill_file
- Skip orphaned AutoCora results with no state DB entry
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously, results from prior runs (or the old CheddahBot system) would
be processed without context, causing "unknown" keyword in comments and
cascading errors. Now they are archived silently.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix --tier-1 -> --tier1-count in create_task_set.py and create-task-set.md skill
- Set initial Stage field when creating tasks (run_cora for most, draft for PR)
- Add Quick Reference section to clickup_runner README with stage tables
- Add Stage field docs to clickup-task-creation.md
- Remove stale xlsx_urls tests from test_claude_runner.py
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The ClickUp dropdown is named "Client", not "Customer". Updated field
lookups, prompt labels, README docs, and all tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Submits Cora SEO jobs as JSON files to the NAS queue, polls for .result
files each cycle, and updates ClickUp on success/failure. Async design:
submission and result processing happen on separate poll cycles so the
runner never blocks. Full README rewrite with troubleshooting section.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements _dispatch_claude: reads skill files, builds prompts with task
context, runs claude -p as subprocess, uploads output files to ClickUp,
copies to NAS, advances stage/status, and posts structured error comments
on failure. Includes ntfy.sh notifications and generous max_turns defaults.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New headless automation runner that replaces CheddahBot's multi-agent
system with a simpler design: poll ClickUp for tasks with "Delegate to
Claude" checkbox checked + due date <= today, route by task type + stage
through a skill map, and dispatch to Claude Code headless or AutoCora.
Module structure:
- config.py: env vars > YAML > defaults configuration
- clickup_client.py: ClickUp API client (adapted from cheddahbot/clickup.py)
with checkbox, stage dropdown, and attachment operations
- skill_map.py: task_type + stage -> SkillRoute routing dictionary
(Content Creation, On Page Optimization, Press Release, Link Building)
- state.py: minimal SQLite KV store + run log
- __main__.py: poll loop with graceful shutdown
- README.md: setup, config reference, skill map docs
Dispatch functions are stubs (Phase 2: Claude runner, Phase 3: AutoCora).
Includes system-design-spec.md that drives this rewrite.
68 new tests, all passing. Existing 347 tests unaffected.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Substring and word-overlap matching caused cross-contamination between
similar keywords (e.g. "shaft manufacturing" matching "custom shaft
manufacturing"). Now only exact matches pass immediately; non-exact
pairs are checked via OpenRouter LLM call with session-level caching.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Thread-safe active execution registry in Scheduler tracks which tool
functions are currently blocking. New get_active_tasks chat tool reads
this registry plus loop timestamps to report running tasks, durations,
loop health, and a safe-to-restart verdict.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add _CORA_ELIGIBLE_STATUSES filter so only "running cora" and "error" tasks
get matched during xlsx distribution (prevents accidental "to do" matches)
- Reduce watch_interval_minutes from 60 to 40 for faster Cora file pickup
- Add .txt output to test block generator
- Include docs, scripts, and reference files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PR Topic now only drives headline angle and awareness/news framing.
Anchor text is derived from Company Name + Keyword (ClickUp Keyword field).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add set_custom_field_smart() to auto-resolve dropdown option UUIDs
- Extend create_task with priority, assignees, time_estimate params
- Expand clickup_create_task tool and CLI script with tags, due dates, custom fields
- Add _comment_distributed_tasks to post clear ClickUp comments on Cora distribution
(e.g. "Cora XLSX moved to cora-inbox" / "content-cora-inbox")
- Remove unused _find_all_todo_tasks; simplify AutoCora sibling matching
- Add tests for set_custom_field_smart dropdown and text fields
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New create_task() and find_list_in_folder() methods on ClickUpClient,
clickup_create_task chat tool, create-task skill, and CLI script for
creating tasks in a client's Overall list with Client/Work Category fields.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces all "Customer" field lookups with "Client" to match the new
space-wide dropdown, eliminating the 20+ duplicate list-level fields.
Includes migration script that populated 400 active tasks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Content Creation tasks with a URL were incorrectly routed to the
optimization path. Now the scheduler sets content_type from Work
Category, and the tool routes on that. Chat callers fall back to
URL-based detection when content_type is empty.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The time-based 1-hour dedup window wasn't preventing repeated skip
notifications for tasks with missing fields every poll cycle. Replaced
with a permanent sent-set so each unique message only fires once per
process run. Dedup log bumped to INFO for visibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents notification spam from repeated ClickUp poll cycles finding the
same tasks with missing fields. Dedup suppresses identical messages within
a 60-min window, daily cap stops at 200 sends (under ntfy.sh 250 free
tier), and 429 responses suppress all sends for the rest of the day.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only tasks with Work Category in poll_task_types are fetched and
processed. Prevents unrecognized types (SEO Audit, AEO, etc.) from
being evaluated every poll cycle. Falls back to skill_map keys if
the list is empty.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Stale task recovery threshold 2h → 6h to prevent resetting tasks while Cora is still running
- Add rotating file logger (WARNING+) to logs/cheddahbot.log for debugging
- Silence httpx/httpcore INFO spam from terminal
- Switch watch folder paths from Z: drive letters to UNC paths to avoid intermittent mount drops
- Fix test_db tests to add messages so list_conversations includes them
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New NtfyNotifier subscribes to NotificationBus and routes notifications
to ntfy.sh topics based on category + message pattern matching. Two
channels configured: human_action (task completed, Cora ready, etc.)
and errors (failures, missing fields). HTTP posts fire in daemon threads
to avoid blocking the notification bus lock.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a ClickUp task with a URL arrives at create_content, route it to the
new optimization pipeline instead of the outline-gate Phase 1/Phase 2 flow.
The pipeline runs 8 steps via the execution brain (scrape, deficit analysis,
entity filtering, template writing, test block generation, readability
rewrite, validation, surgical instructions doc) and uploads deliverables
(test_block.html, optimization_instructions.md, validation_report.json)
directly to ClickUp as attachments.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New watcher thread scans Z:/Cora-For-Human for post-macro Cora xlsx files,
matches them to ClickUp tasks by keyword, and copies to the appropriate
pipeline inbox (Z:/cora-inbox for Link Building, Z:/content-cora-inbox for
Content/OPO). Fixes issue where shared Cora reports left one pipeline's
tasks stuck in automation underway forever.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove all KV store reads/writes from task pipeline code. ClickUp is now
the single source of truth for task state. File location (processed/
subfolder) tracks file processing state. Loop timestamps use in-memory
dict on Scheduler.
Source changes:
- scheduler.py: Remove KV dedup, fallback sync path, docx extraction;
tools own their ClickUp sync; in-memory timestamps
- press_release.py: Remove KV state writes, log-only _set_status
- linkbuilding.py: Remove KV state writes, processed/ subfolder check
- content_creation.py: Phase detection via ClickUp API status, remove
KV phase/state tracking, _update_kv_state removed
- clickup_tool.py: Rewrite to query ClickUp API directly
- ui.py: Pipeline status polling is now a no-op
Test changes:
- test_scheduler.py: Remove KV dedup tests, remove fallback path test,
verify ClickUp API calls instead of KV state
- test_content_creation.py: Mock _get_clickup_client for phase detection,
verify ClickUp sync calls instead of KV assertions
- test_linkbuilding.py: Remove KV status test, verify ClickUp API calls
- test_clickup_tools.py: Rewrite for API-backed tools
- test_scheduler_helpers.py: Test in-memory timestamps
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace single-day task filter with multi-pass sweep when no explicit
target_date: (1) due today, (2) overdue + current month tag, (3) last
month tag, (4) look-ahead 2 days. Deduplicate across passes.
Remove KV store from submit (dedup by job file existence) and result
poller (scan results/ folder directly, move to processed/ after handling).
Scheduler auto-submit no longer passes explicit target_date.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Content tasks now trigger from Cora xlsx files dropped in Z:/content-cora-inbox/
instead of auto-firing from ClickUp polling. The watcher fuzzy-matches files to
ClickUp tasks and auto-detects content type from URL presence (optimization vs
new content). Adds cli_flags support for service page hints.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 1 researches competitors and generates an outline via the execution brain,
saves it to a network/local path, and pauses for human review. Phase 2 picks up
the approved outline and writes full SEO-optimized content. ClickUp integration
maps "On Page Optimization" and "Content Creation" work categories, with
"outline approved" added to poll_statuses for automatic Phase 2 triggering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Automates Cora SEO report workflow: queries ClickUp for qualifying tasks,
submits jobs to a shared folder queue, polls for results, and updates task
statuses. Includes two tools (submit_autocora_jobs, poll_autocora_results),
a scheduler polling loop, and 30 tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tasks now show "automation underway" when the bot picks them up and "error"
on failure, replacing the old "in progress" / "to do" fallbacks that were
invisible on Bryan's ClickUp board. Folder watcher also syncs ClickUp status
on match, missing IMSURL, pipeline failure, success, and exceptions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove placeholder URL fallback from ingest-cora args. Add early
validation in run_cora_backlinks and folder watcher — if IMSURL is
empty, block the task with a notification instead of running with a
fake URL. Update tests to pass money_site_url and add missing-URL test.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ClickUp "Client" custom field was deleted; switch all references to
"Customer" across config, tools, tests, and docs. Refine Overview tab:
rename Due Soon to Up Next (today/tomorrow, fallback next 5), expand
This Month to include both month tag and due-date-in-month matches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Ruff format: consistent dict/call wrapping in agent.py, db.py,
skills.py, delegate.py
- Replace clickup_approve_task/clickup_decline_task with
clickup_reset_task/clickup_reset_all (simpler state machine)
- Add kv_delete() method to Database
- Add due_date and field filter tests to test_clickup.py
- Update test_clickup_tools.py for new reset tools
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove f-prefix from strings with no placeholders
- Use list unpacking instead of concatenation
- Fix import sorting in test file
- Remove unused Path import
- Use contextlib.suppress instead of try/except/pass
- Wrap long lines to stay under 100 chars
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ClickUpClient.create_custom_field() for POST /list/{id}/field
- 40+ tests covering output parsers, CLI arg builder, pipeline,
ClickUp state machine, and folder scanning
- All tests mock subprocess.run, never call Big-Link-Man
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New linkbuilder agent that handles ClickUp "Link Building" tasks.
For each keyword/company, generates three content pieces via the
execution brain: a guest article (500-700 words), a directory
listing, and a social media post — each with proper SEO anchor
text and backlinks. Integrates with ClickUp for status updates,
comments, and file attachments.
- cheddahbot/tools/linkbuilding.py: build_links tool with full pipeline
- skills/linkbuilding.md: skill prompt for SEO content generation
- config.yaml: linkbuilder agent config + Link Building skill_map entry
- tests/test_linkbuilding.py: 36 tests covering helpers, prompts,
pipeline, file output, error handling, and ClickUp sync
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add sidebar layout with agent selector (Radio), conversation history
(gr.render), and BrowserState for localStorage session persistence.
Conversations tagged by agent_name for per-agent history filtering.
Sidebar auto-closes on mobile viewports via JS. 11 new tests (135 total).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove unused modules that were never called at startup:
- cheddahbot/skills/__init__.py (dead @skill decorator system)
- cheddahbot/providers/__init__.py (empty placeholder)
- cheddahbot/tools/build_skill.py (depends on dead skills system)
- cheddahbot/tools/build_tool.py (security risk: generates arbitrary Python)
Also fix all pre-existing ruff lint errors across the codebase:
- Fix import sorting, unused imports, line length violations
- Fix type comparisons (use `is` instead of `==`)
- Fix implicit Optional types (dict -> dict | None)
- Fix unused variables, ambiguous variable names
- Apply ruff format for consistent style
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a press release task completes, docx file paths are extracted from
the tool output and uploaded as attachments to the ClickUp task. The
completion comment now includes an attachment count note.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds PressAdvantageClient API wrapper and submit_press_release tool that
posts finished press releases to PA as drafts. Auto-constructs SEO links
(brand+keyword → IMSURL, company name → SocialURL/GBP/homepage) with
fuzzy anchor matching and warnings when phrases can't be found. The PR
writing prompt now requests anchor text phrases and validates them after
generation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Press releases now auto-generate .docx files alongside .txt for native
Google Docs import. New email_file chat tool sends files via Gmail SMTP
with app password auth, auto-converting .txt to .docx before sending.
Also includes Press Advantage API config and submit_press_release tool.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>