Commit Graph

145 Commits (19f6ee94c60e341ed85114bc944ea67e6d1a778f)

Author SHA1 Message Date
PeninsulaInd 19f6ee94c6 Skip orphaned AutoCora results that have no matching state DB entry
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>
2026-04-09 11:00:27 -05:00
PeninsulaInd e0c19705b1 Add company name alias matching to PR pipeline
PR skill now matches ClickUp Client names against Aliases field in
companies.md and uses the canonical ## heading as the company name.
Fixes issue where PRs used ClickUp dropdown names (e.g. "Elasto Valve
Rubber (EVR)") instead of the correct company name ("EVR Products").
Added James Eagen Sons stub entry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 10:49:39 -05:00
PeninsulaInd 80535d6c9e Add client delivery pipeline: Google Drive upload + Gmail drafts + reply tracking
Automates the PR delivery workflow: uploads .docx to Google Drive as Google Docs,
creates Gmail drafts with template-based emails and Ref: CU-<task_id> tracking tags,
and polls for client replies to update ClickUp tasks. Includes contact directory
with alias support, email template system, and manual CLI scripts for retries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 10:26:17 -05:00
PeninsulaInd e0388b1f6f Fix --tier1-count CLI flag + set Stage on task creation + update docs
- 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>
2026-04-09 10:17:52 -05:00
PeninsulaInd e4c7bc8e02 Add create_task_set CLI script + update company directory
New script replaces inline task creation commands with a proper CLI.
Supports all task types (NEW/OPT/LINKS/PR) with validation, dependencies,
per-type tag/date overrides, and custom fields.

Updated companies.md: renamed RPM Mechanical to RPM Industrial Rubber Parts,
added Royal Purple Industrial entry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 09:40:31 -05:00
PeninsulaInd 935ab2d772 Add task set creation skill + ClickUp dependency support
Add add_dependency() to ClickUpClient and clickup_add_dependency chat tool
for setting "blocked by" relationships between tasks. New create-task-set
skill enables bundled task creation (LINKS, PR, NEW, OPT) with correct
fields, time estimates, due date offsets, and automatic dependencies.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 15:23:53 -05:00
PeninsulaInd 99b000f25a Add word-overlap gate to _fuzzy_keyword_match to avoid unnecessary LLM calls
LLM plural check was firing for every non-exact keyword pair (e.g. "insert molding"
vs "cement plant lubrication"), causing timeouts and wasted API calls. Now requires
keywords to share all but one word before escalating to the LLM.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 09:58:18 -05:00
PeninsulaInd bba634a63e Download ClickUp attachments to work dir before running Claude
- Added ClickUpClient.download_attachment() for fetching attachment files
- Runner now downloads all task attachments to the temp work dir before
  dispatching to claude -p. Claude reads local files instead of URLs.
- build_prompt() now lists local filenames, not ClickUp attachment URLs
- _collect_output_files() excludes pre-existing attachments so they
  don't get re-uploaded back to ClickUp
- Removed optimizer script steps from content_draft.md -- the outline
  stage already handles Cora parsing, draft just follows the outline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:49:05 -05:00
PeninsulaInd 7679467bf8 Add content_draft.md skill + tighten entity correlation to -0.199
- New skills/content_draft.md: reads outline, writes full content draft
  with Cora-driven variation/entity/LSI optimization, generates meta tags
  (keyword | company | related searches format, 400-500 char description)
- Changed entity correlation threshold from -0.19 to -0.199 in
  cora_parser.py and all referencing docs
- Updated content_outline.md to match new threshold

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 12:34:56 -05:00
PeninsulaInd 9550d31190 Rewrite content_outline.md to single-file format
Clean editable outline on top (headings, word counts, section briefs),
writer's reference data on bottom (variation map, entity checklist,
top 20 LSI terms, entity rules). One file instead of two -- easier to
review on mobile via ClickUp attachments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 11:04:08 -05:00
PeninsulaInd cf9d4da7c0 Add content_outline.md skill -- two-file version (outline + data)
First pass at the content outline skill for clickup_runner. Parses Cora
xlsx via cora_parser.py scripts, researches competitors, builds structured
outline with per-section word counts and variation placement. Produces
two output files: clean outline and Cora data reference.

May be reworked to single-file format after testing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 17:05:20 -05:00
PeninsulaInd cd0fea094c Rewrite PR skill for clickup_runner autonomous pipeline
- Rewrote skills/press_release_prompt.md for headless claude -p execution:
  generates 7 headlines, self-judges top 2, writes TWO complete press
  releases with different angles, generates JSON-LD schema for each
- Output: 5 files named by headline (e.g. "Company Headline Here.txt/.json")
- Merged schema generation from press-release-schema.md into single skill
- Added "Introduces" to headline tone trigger words
- Removed --bare flag from claude_runner.py (breaks OAuth auth)
- Documented headline tone trigger words in clickup-task-creation.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:24:36 -05:00
PeninsulaInd b287d759a1 Fix ClickUp field name: Customer -> Client
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>
2026-03-30 10:26:32 -05:00
PeninsulaInd 645b9cfbef Add AutoCora job submission + result polling -- Phase 3
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>
2026-03-30 10:17:42 -05:00
PeninsulaInd b19e221b8f Add Claude Code runner -- Phase 2: claude -p subprocess + ClickUp integration
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>
2026-03-30 09:34:54 -05:00
PeninsulaInd 74c1971f70 Add clickup_runner module -- Phase 1: skeleton + ClickUp polling
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>
2026-03-30 09:14:22 -05:00
PeninsulaInd dcfabc2261 Fix NoneType crash in LLM plural check when OpenRouter returns null content
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:30:36 -05:00
PeninsulaInd 74d20a406a Replace Gradio UI with HTMX + FastAPI frontend
New lightweight web UI with dark theme, SSE-streamed chat, and live
dashboard. Gradio moved to /old for transition. Adds jinja2,
python-multipart, sse-starlette deps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:30:03 -05:00
PeninsulaInd 6e7e2b2320 Add configurable per-task timeouts (env vars, config.yaml, defaults)
Execution brain timeout bumped from 15 min to 45 min default to avoid
content writing timeouts. BLM stays at 30 min. Both configurable via
CHEDDAH_TIMEOUT_EXECUTION_BRAIN / CHEDDAH_TIMEOUT_BLM env vars or
config.yaml timeouts section.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:52:04 -05:00
PeninsulaInd bdb4c9490a Filter Cora entities by Best of Both correlation threshold (<= -0.19)
Entities without a strong enough ranking correlation were being included
in outlines and optimization. Now cora_parser.get_entities() filters out
entities with Best of Both > -0.19 (or None). Threshold is configurable
in OPTIMIZATION_RULES and documented in skill.md optimization rules table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:38:32 -05:00
PeninsulaInd c12c655220 Pass statuses to ClickUp API for task matching and reduce watcher interval
Server-side filter tasks by _CORA_ELIGIBLE_STATUSES in _match_xlsx_to_clickup,
_match_xlsx_to_content_task, and _distribute_cora_file instead of fetching all
tasks and filtering client-side. Reduce watcher interval from 40m to 10m.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 19:33:32 -05:00
PeninsulaInd fdafa42122 Strip all emoji and unicode from runtime strings
Replace emoji prefixes in ClickUp comments and notifications with
plain ASCII tags ([FAILED], [DONE], [WARNING], [STARTED], [OUTLINE]).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 18:59:41 -05:00
PeninsulaInd 305b3161c4 Replace unicode arrows with ASCII in log/output strings
Windows cp1252 console encoding can't handle → (U+2192), causing
UnicodeEncodeError in logging. Replaced with -> in all runtime strings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 18:56:48 -05:00
PeninsulaInd 48d2e47835 Replace fuzzy keyword matching with exact match + LLM plural check
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>
2026-03-18 18:53:24 -05:00
PeninsulaInd b857d3cb8c Fix missing ClickUp comments on error status transitions and add pipeline error audit log
- File handler now captures DEBUG+ (was WARNING) for full pipeline visibility
- Add ClickUp comments at every error status transition (missing IMSURL, pipeline crash, content crash)
- Content watcher exception now also sets error status (was silently failing)
- Cora distributor resets matched error tasks to "running cora" when new XLSX arrives
- Add dedicated logs/pipeline_errors.log for tool-handled errors (audit trail)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 18:28:48 -05:00
PeninsulaInd e8df7a9750 Add get_active_tasks tool to show what's running before restart
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>
2026-03-18 17:04:19 -05:00
PeninsulaInd eae55fd714 Reduce scheduler log noise and update loop timing docs
- Move repetitive "Skipping task", "ClickUp task skipped", and "AutoCora
  result" messages from INFO to DEBUG level
- Update task-pipeline-flows.md: folder watchers now 40m, add cora_distribute loop

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 13:20:38 -05:00
PeninsulaInd 5cb15756fc Filter Cora distribution to eligible statuses and reduce poll interval to 40m
- 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>
2026-03-18 12:29:02 -05:00
PeninsulaInd ad7094e8a5 Separate PR Topic (angle) from Keyword (anchor text) in press release pipeline
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>
2026-03-17 10:51:10 -05:00
PeninsulaInd f60928f3fa Clarify notification and ClickUp comment messages
- "pipeline completed" → descriptive messages for link building and content
- "ClickUp task completed" → "{task} done — ran {tool} successfully"
- "Cora report completed" → "Cora report generated — ready for you to look at it"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 18:14:23 -05:00
PeninsulaInd fb4498b978 Enhance ClickUp task creation, smart field setting, and Cora distribution comments
- 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>
2026-03-11 18:06:03 -05:00
PeninsulaInd 0d5450fb65 Add ClickUp task creation via chat tool, skill, and CLI script
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>
2026-03-11 12:19:54 -05:00
PeninsulaInd 6250918e5e Migrate ClickUp Customer field to space-level Client field
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>
2026-03-09 12:23:14 -05:00
PeninsulaInd 85d9fc7a1f Route create_content by content_type instead of URL presence
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>
2026-03-08 20:58:07 -05:00
PeninsulaInd 3ed7f2bbdd Direct Phase 2 content saves to network share instead of working/
Compute the final-content.html save path upfront (network share with
local fallback) and pass it in the Phase 2 prompt so the execution
brain writes directly to the share. Summary still saved separately
as final-content.md via _save_content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:52:55 -05:00
PeninsulaInd 7344781e73 Fix clickup_task_status not reaching tool ctx
The tool registry only forwarded clickup_task_id from args to ctx,
so clickup_task_status was silently filtered out. Phase 2 detection
in create_content never saw the original "outline approved" status.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:23:32 -05:00
PeninsulaInd b4f1ddfced Fix Phase 2 detection: pass original task status to create_content
The scheduler sets status to "automation underway" before the tool runs,
so create_content's API re-fetch never saw "outline approved". Now the
scheduler passes the pre-change status via clickup_task_status arg.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:18:12 -05:00
PeninsulaInd a3eacbd0e5 Add status-aware auto_execute gate for Content Creation Phase 2
The scheduler's blanket auto_execute check was blocking "outline approved"
Content Creation tasks from reaching Phase 2. Now checks
auto_execute_on_status for status-specific overrides. Also adds
trigger_hint to skip log messages for easier debugging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:05:50 -05:00
PeninsulaInd 8f2ec48e10 Increase CLI timeout to 15min, fix result file reprocessing, and save outlines directly
- Bump Claude Code subprocess timeout from 5 to 15 minutes for longer content tasks
- Fix scheduler result file loop: unlink source if already exists in processed/ dir
- Pass outline save path to execution brain so it writes directly to network share

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 14:38:48 -05:00
PeninsulaInd af67ae166d Fix ntfy dedup: make duplicate suppression permanent for process lifetime
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>
2026-03-08 14:22:27 -05:00
PeninsulaInd 9102657c15 Add dedup, daily cap, and 429 backoff to ntfy notifier
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>
2026-03-07 17:32:52 -06:00
PeninsulaInd 1e26969ff8 Add explicit poll_task_types allowlist to filter ClickUp polling
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>
2026-03-05 19:28:42 -06:00
PeninsulaInd ca73689099 Add /api/system/briefing/force endpoint to trigger morning briefing on demand
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:30:46 -06:00
PeninsulaInd 6b5d0ac71e Add daily morning briefing via ntfy push notifications
Sends a summary at 6:30 AM weekdays / 8:00 AM weekends (Central) with
Cora reports needing action, outlines to approve, PRs to review, and
errors — grouped by customer. Cora tasks cross-reference network share
folders to show file pipeline status. No LLM API credits burned.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:15:49 -06:00
PeninsulaInd 45ab4c1b33 Fix task looping: increase stale recovery to 6h, add file logging, use UNC paths
- 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>
2026-03-04 21:41:46 -06:00
PeninsulaInd 83c7c378e5 Add ntfy.sh push notifications for alerts and errors
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>
2026-03-04 11:07:51 -06:00
PeninsulaInd 813dd4cb01 Wire Phase 3 test block pipeline into automated optimization flow
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>
2026-03-03 15:49:49 -06:00
PeninsulaInd 236b64c11c Add Cora report distribution watcher to route xlsx to pipeline inboxes
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>
2026-03-03 13:07:03 -06:00
PeninsulaInd 84c81b6df4 Default PR headlines to awareness framing, only allow announcement language for actual news
- Added _is_actual_news() detection based on PR Topic field signals
  (e.g. "Actual News", "New Product", "Launch")
- Headline generator defaults to awareness verbs (Highlights, Reinforces,
  Delivers) and bans announcement verbs (Announces, Launches, Expands)
- Judge prompt disqualifies fabricated events for non-news topics
- Body writer prompt explicitly forbids inventing expansions, milestones,
  or demand claims — frames as existing capabilities
- Updated skill file to match awareness-by-default approach

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:54:06 -06:00
PeninsulaInd d3b778bdb5 Add openpyxl dependency for xlsx file handling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 17:26:07 -06:00