diff --git a/.gitignore b/.gitignore index 52d8807..7b6112d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,11 @@ venv/ dist/ build/ *.egg-info/ + +# Ralph Wiggum +logs/ralph/ +state/ +*.tmp + +# Night Nurse +logs/night-nurse.log diff --git a/.night-nurse/config.json b/.night-nurse/config.json new file mode 100644 index 0000000..271da8d --- /dev/null +++ b/.night-nurse/config.json @@ -0,0 +1,16 @@ +{ + "name": "brand-os", + "path": "/home/deploy/scty-repos/brand-os", + "agents": { + "review": "claude", + "implement": "codex" + }, + "maxIterations": 25, + "priorities": { + "sources": [ + "sentry", + "specs", + "backlog" + ] + } +} diff --git a/.night-nurse/priorities.md b/.night-nurse/priorities.md new file mode 100644 index 0000000..f48cfb7 --- /dev/null +++ b/.night-nurse/priorities.md @@ -0,0 +1,12 @@ +# Priorities + +Items listed here will be picked up by Night Nurse (highest first). + +## High Priority + + +## Medium Priority + + +## Low Priority + diff --git a/.night-nurse/state.json b/.night-nurse/state.json new file mode 100644 index 0000000..385034e --- /dev/null +++ b/.night-nurse/state.json @@ -0,0 +1,11 @@ +{ + "initialized": "2026-01-28T17:26:09Z", + "lastLearn": "2026-02-01T03:01:03Z", + "lastTreat": null, + "stats": { + "specsCompleted": 0, + "specsInProgress": 0, + "totalIterations": 0, + "learnings": 3 + } +} diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md new file mode 100644 index 0000000..096e6a1 --- /dev/null +++ b/.specify/memory/constitution.md @@ -0,0 +1,23 @@ +# Constitution - brand-os + +## Project Purpose +CLI-first brand operations toolkit - unified personas, intel, content, and publishing + +## Tech Stack +Python + +## Build & Test +```bash +# npm run build +pytest +``` + +## Principles +1. Keep changes minimal and focused +2. Don't break existing functionality +3. Add tests for new behavior + +## Boundaries +- Don't modify production data directly +- Don't commit secrets +- Don't change CI/CD without review diff --git a/logs/improve.log b/logs/improve.log new file mode 100644 index 0000000..e1db3d6 --- /dev/null +++ b/logs/improve.log @@ -0,0 +1,3 @@ +/bin/sh: 1: /home/deploy/clawd/skills/ralph-wiggum/scripts/ai-review.sh: not found +/bin/sh: 1: /home/deploy/clawd/skills/ralph-wiggum/scripts/ai-review.sh: not found +/bin/sh: 1: /home/deploy/clawd/skills/ralph-wiggum/scripts/ai-review.sh: not found diff --git a/logs/ralph.log b/logs/ralph.log new file mode 100644 index 0000000..02e9f4f --- /dev/null +++ b/logs/ralph.log @@ -0,0 +1,3 @@ +/bin/sh: 1: /home/deploy/clawd/skills/ralph-wiggum/scripts/ralph-loop-ai.sh: not found +/bin/sh: 1: /home/deploy/clawd/skills/ralph-wiggum/scripts/ralph-loop-ai.sh: not found +/bin/sh: 1: /home/deploy/clawd/skills/ralph-wiggum/scripts/ralph-loop-ai.sh: not found diff --git a/pyproject.toml b/pyproject.toml index c9a333b..7c12722 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,7 @@ publish = [ server = [ "fastapi>=0.115", "uvicorn>=0.32", + "fastmcp<3", ] email = [ "resend>=2.0", diff --git a/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/log.md b/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/log.md new file mode 100644 index 0000000..bc62bdd --- /dev/null +++ b/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/log.md @@ -0,0 +1,12 @@ +# Log: MCP Server Implementation - Complete the MCP server to expose brand operations (personas, content, intel, decisions) as tools for AI assistants using FastMCP + +## 2026-02-01 +- Spec created + +### Iteration 1 - 15:18:22 +Task: 1.1 [Task] +Result: ✓ Complete + +### Iteration 2 - 15:20:47 +Task: 1.1 [Task] +Result: ✓ Complete diff --git a/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/proposal.md b/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/proposal.md new file mode 100644 index 0000000..defd574 --- /dev/null +++ b/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/proposal.md @@ -0,0 +1,14 @@ +# Proposal: MCP Server Implementation - Complete the MCP server to expose brand operations (personas, content, intel, decisions) as tools for AI assistants using FastMCP + +## Intent + + +## Scope +**In scope:** +- + +**Out of scope:** +- + +## Approach + diff --git a/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/spec.md b/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/spec.md new file mode 100644 index 0000000..6e25190 --- /dev/null +++ b/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/spec.md @@ -0,0 +1,11 @@ +# Spec: MCP Server Implementation - Complete the MCP server to expose brand operations (personas, content, intel, decisions) as tools for AI assistants using FastMCP + +## Requirements + +### Requirement: [Name] +The system SHALL [behavior]. + +#### Scenario: [Happy path] +- GIVEN [context] +- WHEN [action] +- THEN [result] diff --git a/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/tasks.md b/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/tasks.md new file mode 100644 index 0000000..56d3f0d --- /dev/null +++ b/specs/active/001-mcp-server-implementation---complete-the-mcp-server-to-expose-brand-operations-personas-content-intel-decisions-as-tools-for-ai-assistants-using-fastmcp/tasks.md @@ -0,0 +1,10 @@ +# Tasks: MCP Server Implementation - Complete the MCP server to expose brand operations (personas, content, intel, decisions) as tools for AI assistants using FastMCP + +## 1. Setup +- [ ] 1.1 [Task] + +## 2. Implementation +- [ ] 2.1 [Task] + +## 3. Testing +- [ ] 3.1 [Task] diff --git a/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/log.md b/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/log.md new file mode 100644 index 0000000..bec4b6b --- /dev/null +++ b/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/log.md @@ -0,0 +1,4 @@ +# Log: Content Producer Agent - Implement agent that takes Market Analyst outputs and generates brand-aligned content for publishing + +## 2026-02-01 +- Spec created diff --git a/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/proposal.md b/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/proposal.md new file mode 100644 index 0000000..05e7b1c --- /dev/null +++ b/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/proposal.md @@ -0,0 +1,14 @@ +# Proposal: Content Producer Agent - Implement agent that takes Market Analyst outputs and generates brand-aligned content for publishing + +## Intent + + +## Scope +**In scope:** +- + +**Out of scope:** +- + +## Approach + diff --git a/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/spec.md b/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/spec.md new file mode 100644 index 0000000..34a66b2 --- /dev/null +++ b/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/spec.md @@ -0,0 +1,11 @@ +# Spec: Content Producer Agent - Implement agent that takes Market Analyst outputs and generates brand-aligned content for publishing + +## Requirements + +### Requirement: [Name] +The system SHALL [behavior]. + +#### Scenario: [Happy path] +- GIVEN [context] +- WHEN [action] +- THEN [result] diff --git a/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/tasks.md b/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/tasks.md new file mode 100644 index 0000000..7bb1bfe --- /dev/null +++ b/specs/active/002-content-producer-agent---implement-agent-that-takes-market-analyst-outputs-and-generates-brand-aligned-content-for-publishing/tasks.md @@ -0,0 +1,10 @@ +# Tasks: Content Producer Agent - Implement agent that takes Market Analyst outputs and generates brand-aligned content for publishing + +## 1. Setup +- [ ] 1.1 [Task] + +## 2. Implementation +- [ ] 2.1 [Task] + +## 3. Testing +- [ ] 3.1 [Task] diff --git a/specs/archive/legacy-20260128/001-implement-notification-via-slack-sdk-or-email/.done b/specs/archive/legacy-20260128/001-implement-notification-via-slack-sdk-or-email/.done new file mode 100644 index 0000000..717502c --- /dev/null +++ b/specs/archive/legacy-20260128/001-implement-notification-via-slack-sdk-or-email/.done @@ -0,0 +1 @@ +2026-01-28 diff --git a/specs/archive/legacy-20260128/001-implement-notification-via-slack-sdk-or-email/spec.md b/specs/archive/legacy-20260128/001-implement-notification-via-slack-sdk-or-email/spec.md new file mode 100644 index 0000000..0407137 --- /dev/null +++ b/specs/archive/legacy-20260128/001-implement-notification-via-slack-sdk-or-email/spec.md @@ -0,0 +1,38 @@ +# [FIX] Implement notification in approval.py + +## Task +In `src/brand_os/workflows/approval.py` line 114, replace the TODO comment with actual Slack notification code. + +## Current Code (line 112-115) +```python + def _notify(self, message: str) -> None: + """Send notification (placeholder for Slack/email integration).""" + # TODO: Implement notification via slack-sdk or email + pass +``` + +## Required Change +Replace the TODO and `pass` with code that sends a Slack webhook notification using httpx (already imported in the project). Use env var `SLACK_WEBHOOK_URL`. If not set, just log the message. + +## Example Implementation +```python + def _notify(self, message: str) -> None: + """Send notification via Slack webhook.""" + import os + webhook_url = os.getenv("SLACK_WEBHOOK_URL") + if webhook_url: + try: + import httpx + httpx.post(webhook_url, json={"text": f"[BrandOS] {message}"}, timeout=10) + except Exception: + pass # Silent fail - notification is best-effort +``` + +## Completion Signal +```bash +grep -rn "# TODO: Implement notification via slack-sdk or email" src/brand_os/workflows/approval.py && exit 1 || echo "TODO resolved" +``` + +## Constraints +- Only modify the `_notify` method +- Keep it simple - just Slack webhook, no email diff --git a/src/brand_os/server/mcp.py b/src/brand_os/server/mcp.py index 5128341..b52faef 100644 --- a/src/brand_os/server/mcp.py +++ b/src/brand_os/server/mcp.py @@ -5,6 +5,21 @@ def create_mcp_server(): """Create MCP server for LLM integration. - This is a placeholder - implement with MCP SDK. + Requires: fastmcp optional dependency. """ - raise NotImplementedError("MCP server not yet implemented") + try: + from fastmcp import FastMCP + except ImportError as exc: + raise ImportError("fastmcp required. Install with: pip install brand-os[server]") from exc + + return FastMCP("brandos") + + +def run_server() -> None: + """Run the MCP server with default stdio transport.""" + mcp = create_mcp_server() + mcp.run() + + +if __name__ == "__main__": + run_server() diff --git a/src/brand_os/workflows/approval.py b/src/brand_os/workflows/approval.py index 8bae436..6b0bc57 100644 --- a/src/brand_os/workflows/approval.py +++ b/src/brand_os/workflows/approval.py @@ -110,9 +110,21 @@ def _save(self) -> None: get_decision_log().update(self.decision) def _notify(self, message: str) -> None: - """Send notification (placeholder for Slack/email integration).""" - # TODO: Implement notification via slack-sdk or email - pass + """Send notification via Slack webhook.""" + import os + + webhook_url = os.getenv("SLACK_WEBHOOK_URL") + if not webhook_url: + logger.info("Approval notification: %s", message) + return + try: + httpx.post( + webhook_url, + json={"text": f"[BrandOS] {message}"}, + timeout=10, + ) + except Exception: + pass # Best-effort notification else: # Fallback implementation without statemachine dependency