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>
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>
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>
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>
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>
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 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>
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
Add kv_scan() for prefix-based key-value lookups (used by ClickUp task
state tracking). Add notifications table with add_notification() and
get_notifications_after() for the UI-agnostic notification bus.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ClickUpConfig dataclass with env var loading (CLICKUP_API_TOKEN,
CLICKUP_WORKSPACE_ID, CLICKUP_SPACE_ID). Thin httpx client wrapping
ClickUp v2 API for task listing, status updates, and comments. Skill
mapping config in config.yaml maps Task Type custom fields to tools.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements write_press_releases tool that generates 7 headlines via chat
brain, AI-judges the best 2, writes 2 full press releases via execution
brain, and generates JSON-LD schemas via Sonnet with WebSearch. Saves all
output files to data/generated/press_releases/.
Also adds tools/model pass-through in agent and LLM layers, fixes Windows
command line length limit by piping prompts via stdin, and updates model
references to current versions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Agent: deduplicate tool calls across iterations, reduce max iterations
10→5, add system prompt instructions to prevent re-calling tools
- Router: preserve tool name in history messages, add anti-loop and
delegate_task instructions to system prompt
- Memory: auto_flush now deletes flushed messages from DB so conversations
don't get re-summarized repeatedly, skip tool results in summaries
- DB: add delete_messages() method, include message id in get_messages()
- Scheduler: stop logging routine heartbeat checks to daily log
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Chat brain uses OpenAI-compatible APIs (OpenRouter/Ollama/LM Studio) for
all UI conversations, giving full control over system prompts so the
Cheddah personality works correctly. Execution brain uses Claude Code CLI
for heartbeat, scheduled tasks, and delegated system-level work.
- Split llm.py: chat() routes through OpenAI-compat only, new execute()
calls Claude CLI with Bash/Read/Edit/Write/Glob/Grep tools
- Add chat_model config field (default: openai/gpt-4o-mini)
- Add delegate_task tool bridging chat brain to execution brain
- Scheduler/heartbeat now use execute_task() for real CLI power
- UI dropdown shows chat-only models with custom value support
- Updated model list to current OpenRouter top models (Feb 2026)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Multi-model AI assistant with Gradio UI, persistent memory, 15+ tools,
and meta-tools for runtime tool creation. Routes Claude models through
Claude Code SDK (Max subscription), cloud models through OpenRouter,
and local models through Ollama/LM Studio.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>