Commit Graph

56 Commits (40aca81e16cc855d613f317286e7d3a377de125f)

Author SHA1 Message Date
PeninsulaInd 40aca81e16 Add create_custom_field to ClickUp client and link building test suite
- 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>
2026-02-19 20:05:54 -06:00
PeninsulaInd 2d5ed29c0d Add link building tool module with pipeline orchestration
- run_link_building: dispatcher that routes to correct pipeline by LB Method
- run_cora_backlinks: full pipeline (ingest-cora → generate-batch) with ClickUp sync
- blm_ingest_cora: standalone ingest tool
- blm_generate_batch: standalone generate tool
- scan_cora_folder: utility to inspect watch folder contents
- setup_linkbuilding_fields: one-time ClickUp field creation
- Private helpers for subprocess execution, output parsing, fuzzy matching

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:04:02 -06:00
PeninsulaInd e2dca938a1 Add LinkBuildingConfig and link_builder agent to config
- New LinkBuildingConfig dataclass (blm_dir, watch_folder, interval, ratio)
- YAML loading block and BLM_DIR env var override in load_config()
- Link Building skill_map entry with field mappings in config.yaml
- link_building section in config.yaml
- link_builder agent definition in agents section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:01:55 -06:00
PeninsulaInd 0becf1dd89 Revert "Add link building agent with content generation pipeline"
This reverts commit 8a98b37725.
2026-02-19 18:38:51 -06:00
PeninsulaInd 8077ac5ab6 Revert "Update CLAUDE.md with link building agent documentation"
This reverts commit 2344770143.
2026-02-19 18:38:51 -06:00
PeninsulaInd 2344770143 Update CLAUDE.md with link building agent documentation
Add linkbuilder agent to architecture diagram, document the
Link Building skill_map entry, add test_linkbuilding.py to
test catalog, update test count to 187.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 11:52:57 -06:00
PeninsulaInd 8a98b37725 Add link building agent with content generation pipeline
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>
2026-02-19 11:52:06 -06:00
PeninsulaInd 1cce14b39f Document autostart behavior to prevent restart loops
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 09:05:33 -06:00
PeninsulaInd deae147795 Hide clickup_task_id from LLM tool schema to prevent hallucination
Removed clickup_task_id from write_press_releases function signature
so the LLM cannot see or fabricate a task ID. The parameter is now
passed through ctx by the ToolRegistry — the scheduler sets it in
args, and execute() moves it into the ctx dict before filtering.
Only system-injected task IDs can reach the tool.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 16:38:11 -06:00
PeninsulaInd 082ca6ba44 Fix PR task flow: add ClickUp status updates, comments, and attachments
The press release tool now handles its own ClickUp sync lifecycle when
a clickup_task_id is provided — sets status to "in progress" with a
starting comment, uploads docx attachments after creation, then sets
status to "internal review" with a completion comment. The scheduler
now passes clickup_task_id to tools and defers to tool-level sync when
detected, falling back to scheduler-level sync for other tools.
ToolRegistry.execute() now filters args to accepted params to prevent
TypeError when extra keys (like clickup_task_id) are passed to tools
that don't accept them.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 16:36:45 -06:00
PeninsulaInd 0f2274e6f1 Phase 4: UI — Agent selector, conversation history, chat persistence
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>
2026-02-17 11:23:50 -06:00
PeninsulaInd c311ae5909 Add Multi-Agent Configuration reference to CLAUDE.md
Comprehensive section covering AgentConfig fields, how to add a new
agent, how agents interact (delegation, execution brain, memory
scoping), and key files reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:33:43 -06:00
PeninsulaInd d376420025 Merge refactor/multi-agent-framework
Multi-agent architecture with markdown skills, memory scoping,
cross-agent delegation, and foundation cleanup (thread safety,
file attachments, proper tool message roles, shell approval).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:18:10 -06:00
PeninsulaInd 8a21990ba4 Update CLAUDE.md for multi-agent architecture
Add AgentRegistry, AgentConfig, delegate_to_agent, memory scoping,
and skills.py to architecture diagram, key files, and conventions.
Update test count to 124.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:14:53 -06:00
PeninsulaInd e5e9442e3d 3.6: Add delegate_to_agent tool for cross-agent delegation
New tool in delegate.py routes tasks to named agents via
agent.respond_to_prompt(). Includes thread-local depth counter
(max 3) to prevent infinite A->B->A delegation loops. Extended
ctx injection in ToolRegistry to include agent_registry. Wired
agent_registry into ToolRegistry from __main__.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:13:32 -06:00
PeninsulaInd 9d4d12e232 3.5: Wire multi-agent startup in __main__.py
Loop over config.agents to create per-agent LLM (when model override set),
Agent, MemorySystem (with scope), and register in AgentRegistry. Shared
ToolRegistry and SkillRegistry are wired to all agents. Scheduler and UI
use the default agent.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:12:08 -06:00
PeninsulaInd 883fee36a3 3.4: Add per-agent memory scoping
MemorySystem now accepts optional scope parameter. When set:
- Memory files go to memory/{scope}/ subdirectory
- Fallback search covers both scoped and shared directories

Unscoped agents (scope="") use the shared memory/ root directory.
This enables agents to have private memory while still searching
shared knowledge.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:09:31 -06:00
PeninsulaInd 86511d5a0f 3.3: Modify Agent and ToolRegistry for multi-agent
Agent changes:
- Accept optional AgentConfig in __init__
- Add name property
- Filter tools via agent_config.tools whitelist in respond()
- Use agent-specific personality file when configured
- Pass agent name to skills registry for filtering

ToolRegistry changes:
- get_tools_schema() accepts filter_names parameter
- get_tools_description() accepts filter_names parameter
- When filter_names is None, all tools are returned (backward compat)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:08:16 -06:00
PeninsulaInd 537e3bd528 3.2: Create AgentRegistry
New file cheddahbot/agent_registry.py. Holds multiple Agent instances
keyed by name with methods: register(), get(), list_agents(), and
default property. First registered agent is the default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:06:56 -06:00
PeninsulaInd 6c2c28e9b0 3.1: Create AgentConfig dataclass and multi-agent config
New AgentConfig dataclass in config.py with fields:
- name, display_name, personality_file, model
- tools (whitelist), skills (filter), memory_scope

Loaded from config.yaml under agents: key. Defaults to single
agent for backward compatibility when section is omitted.

config.yaml now includes 4 agent configs: default, writer,
researcher, ops — each with appropriate tool/skill whitelists.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:06:12 -06:00
PeninsulaInd d05b589651 2.5: Update CLAUDE.md with skills.py and skill format docs
- Add cheddahbot/skills.py to Key Files table
- Update skills/ description to mention YAML frontmatter
- Add skills format to Conventions section
- Fix ctx type annotation in docs (dict -> dict | None)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:04:54 -06:00
PeninsulaInd b18855f068 2.5: Add tools and agents fields to skill frontmatter
Both press release skill files now include:
- tools: lists which tool functions they relate to
- agents: [writer, default] for future multi-agent filtering

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:04:11 -06:00
PeninsulaInd 724ccfebd6 2.4: Strip frontmatter in press_release.py _load_skill()
The _load_skill() function now strips YAML frontmatter (--- ... ---)
before returning skill content. This prevents the execution brain
from receiving metadata intended for the skill registry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:03:22 -06:00
PeninsulaInd 5311731855 2.3: Wire skills into system prompt
- router.py: build_system_prompt() gets skills_context parameter,
  injected between memory and tools sections
- agent.py: Agent gets set_skills_registry(), calls it in respond()
  to get skills prompt section
- __main__.py: Creates SkillRegistry from skills_dir, wires to agent

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:02:34 -06:00
PeninsulaInd c651ba22b7 2.2: Create cheddahbot/skills.py — markdown skill registry
New module (not package) that discovers .md files with YAML frontmatter
in the skills/ directory. Provides:
- SkillDef dataclass: name, description, content, tools, agents, file_path
- SkillRegistry: discovers skills, filters by agent, builds prompt sections
- _parse_frontmatter(): splits YAML frontmatter from markdown body
- get_prompt_section(agent_name): builds system prompt injection
- get_body(name): returns skill content without frontmatter

Files without frontmatter (data files) are automatically skipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:01:17 -06:00
PeninsulaInd 4a646373b6 1.5: Fix tool results — use role:tool with tool_call_id
Previously tool results were injected as role:user messages which
confuses some models. Now the live agent loop uses proper OpenAI
function-calling format:
- Assistant messages include tool_calls array with IDs
- Tool results use role:tool with matching tool_call_id

History replay in router.py is unchanged (no tool_call_ids in DB).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:00:21 -06:00
PeninsulaInd 202a5e99e4 1.4: Wire require_approval check for shell commands
When config.shell.require_approval is True, run_command now refuses
execution and directs the user to delegate_task instead. The execution
brain (Claude Code CLI) has its own approval controls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:59:27 -06:00
PeninsulaInd ed751d843b 1.3: Fix files parameter in agent.py — attachments now visible to LLM
Previously respond() accepted files but silently dropped them.
Now when files are attached:
- Images are base64-encoded as image_url content parts
- Text files are read and inlined as text content parts
- The last user message is converted to multipart format

Follows the same encoding pattern used in tools/image.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:58:44 -06:00
PeninsulaInd 9002fc08d2 1.2: Fix thread safety in memory.py embedding DB
Replace 4 standalone sqlite3.connect()/conn.close() pairs with a
thread-local _embed_conn property, matching the pattern in db.py.
Adds WAL mode for better concurrent read/write performance.

This prevents potential collisions between scheduler threads and
Gradio request threads accessing the embedding database.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:57:41 -06:00
PeninsulaInd 0bef1e71b3 1.1: Delete dead code and fix all lint errors
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>
2026-02-17 09:56:36 -06:00
PeninsulaInd a7171673fc Add clickup_task_id param to write_press_releases for chat-triggered sync
When a press release is triggered via chat with a ClickUp task ID, the
tool now uploads .docx attachments, posts a result comment, and updates
task status — matching what the scheduler does automatically. ClickUp
sync is wrapped in try/except so failures don't lose PR results.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 21:42:41 -06:00
PeninsulaInd 46bc38106e Add retry logic to ClickUp API writes and fix review status
- Add _retry() helper to ClickUpClient (3 attempts, exponential backoff,
  only retries 5xx/transport errors)
- Apply retry to update_task_status, add_comment, upload_attachment
- Fix review_status from "review" to "internal review" in config and defaults
- Update SOUL.md personality and USER.md profile

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 20:52:39 -06:00
PeninsulaInd cf1faceab1 Route specialized tools directly instead of delegating to execution brain
The LLM was delegating write_press_releases to the execution brain
(Claude Code CLI subprocess), bypassing the Python tool's orchestration,
skill prompts, and pipeline status updates. Add an exception to the
system prompt so specialized tools are called directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 18:18:00 -06:00
PeninsulaInd 76c0711704 Fix scheduler breaking DB encapsulation for one-time task disabling
Add Database.disable_task() public method and replace direct _conn
access in scheduler._run_due_tasks().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 18:09:38 -06:00
PeninsulaInd ff3114b515 Add .docx attachment uploads to ClickUp tasks after press release generation
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>
2026-02-16 18:04:23 -06:00
PeninsulaInd 388c800bce Remove voice chat, conversation history, and settings UI sections
Strip unused UI components: voice chat accordion, conversation history
panel, and settings accordion. Removes associated event handlers and
helper functions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 18:01:57 -06:00
PeninsulaInd 712829a610 Optimize NotificationBus subscribe cursor and update CLAUDE.md
Replace inefficient two-query approach (fetch up to 10k rows to find max ID)
with a single SELECT MAX(id) query. Update CLAUDE.md test count (51 → 118)
and add 3 missing test file descriptions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 18:01:18 -06:00
PeninsulaInd 20708e6033 Fix execution brain tool permissions in non-interactive mode
Add --allowedTools flag to Claude Code CLI subprocess so tools are
pre-approved and don't prompt for permission in pipe mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:39:21 -06:00
PeninsulaInd 5e9cef5e39 Add submit_press_release tool with Press Advantage API integration
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>
2026-02-16 17:37:41 -06:00
PeninsulaInd 274163508f Add email_file and write_press_releases to tool docs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:18:53 -06:00
PeninsulaInd 8f6e218221 Add document export (.docx) and email delivery feature
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>
2026-02-16 17:00:54 -06:00
PeninsulaInd 7864ec6f17 Add pipeline status box to show PR tool progress in the UI
The press release pipeline takes 2-4 minutes per run with no feedback.
This adds a DB-polled status box (gr.Timer every 3s) that shows the
current step (e.g. "Step 3/4: Writing press release 1/2 — headline...")
and auto-hides when the pipeline completes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:41:33 -06:00
PeninsulaInd 7153e65ae6 Add clickup_query_tasks tool and Press Advantage API integration plan
New tool queries ClickUp API live for tasks, with optional status and
task_type filters. Fixes the execution brain instantiation bug by
providing a proper @tool wrapper around ClickUpClient.

Also saves the Press Advantage API integration plan for future work
once API access is restored.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 13:21:04 -06:00
PeninsulaInd 019bf0ee3c Use Work Category field for ClickUp skill mapping
The real workspace uses "Work Category" (not "Task Type") to identify
task types like Press Release. Also update field_mapping to use "Client"
instead of "Company" to match actual custom field names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 09:52:35 -06:00
PeninsulaInd 121d38a6c4 Add uv.lock for reproducible dependency resolution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 07:38:51 -06:00
PeninsulaInd fa064be7c9 Add test suite for ClickUp integration APIs
51 tests covering the core API surfaces:
- ClickUpTask parsing (dropdown resolution, status normalization, fallbacks)
- ClickUpClient HTTP layer (mocked with respx, graceful error handling)
- Database kv_scan and notifications methods
- NotificationBus pub/sub (independent cursors, fault isolation)
- Chat tools state machine (approve/decline transitions, guards)

Also adds pyproject.toml with modern Python tooling (uv, pytest, ruff,
respx) and proper test/coverage configuration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 07:34:34 -06:00
PeninsulaInd 7864ca2461 Wire NotificationBus into main and Gradio UI
Create NotificationBus in __main__.py and inject into scheduler and UI.
Gradio subscribes as the "gradio" listener with a 10-second polling
timer that displays notifications in a banner above the chatbot.
ClickUp status shown in the header bar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:29:33 -06:00
PeninsulaInd a67e714045 Add ClickUp polling loop to scheduler
Third daemon thread polls ClickUp every 20 minutes, discovers new tasks,
maps Task Type to skills via config, and auto-executes or queues for
approval. On completion updates ClickUp status + comments with results.
Recovers orphaned executing tasks on startup. Pushes all events through
the NotificationBus for UI-agnostic delivery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:28:35 -06:00
PeninsulaInd e02f5a5cb3 Add ClickUp chat tools for task management
Four chat-facing tools: clickup_list_tasks (list/filter tracked tasks),
clickup_task_status (detailed state view), clickup_approve_task and
clickup_decline_task (approval flow for tasks awaiting permission).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:27:34 -06:00
PeninsulaInd ba89f61bc4 Add UI-agnostic notification bus
Pub/sub NotificationBus backed by DB persistence. Any interface
(Gradio, Discord, Slack) subscribes as a listener with independent
read cursors. Supports both push callbacks and poll-based consumption.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:27:02 -06:00