RAG Implementation

This commit is contained in:
Renn F
2025-12-28 03:04:41 +01:00
parent ecc049684d
commit f9398e4caa
25 changed files with 356 additions and 945 deletions
-1
View File
@@ -16,7 +16,6 @@ dist
build
*.egg-info
.tasks
docs
tests
*.md
!README.md
+27 -117
View File
@@ -25,6 +25,8 @@ Use `roboco_task_escalate(task_id, reason)` when blocked or need decisions.
3. **Messages ≠ Notifications** - Only PM can send notifications
4. **Include context** - What, why, what's needed
For full communication structure: `roboco_kb_search("communication hierarchy")`
## Core Principles
1. **Everything is a task** - All work tracked
@@ -44,7 +46,6 @@ Before marking anything as done:
- Would a reviewer say "yes, this is complete"?
**If the task says "test 100 tools" and you tested 1, you are NOT done.**
**If the task has 8 phases and you did 1, you are NOT done.**
**Claiming completion without doing the work is a CRITICAL FAILURE.**
## When to Request Substitution
@@ -60,134 +61,43 @@ Use `roboco_task_substitute(task_id, reason, details)` if:
| `max_retries` | Tried multiple times without success |
| `blocked_external` | Need skills outside your capabilities |
This releases you to claim new work.
## Knowledge Base Tools
## Tool Access
- `roboco_kb_search(query)` - Search code, docs, decisions
- `roboco_rag_query(question)` - AI-generated answers
- `roboco_kb_stats()` - See what's indexed
- `roboco_search_error(pattern)` - Find error solutions
- `roboco_check_decision(topic)` - Find past decisions
- `roboco_search_learnings(topic)` - Find team learnings
All actions go through MCP tools. Never call APIs directly.
## Journaling (ALL agents)
## Knowledge Base & RAG
**Journal ≠ Documentation**
- **Journaling**: Personal reflection, decisions, learnings (ALL agents)
- **Documentation**: Actual docs for codebase (ONLY Documenter)
Search the knowledge base for relevant code, docs, decisions, and learnings:
```python
roboco_kb_search("how does authentication work", top_k=5)
roboco_rag_query("what pattern should I use for error handling")
roboco_kb_stats() # See what's indexed
```
For detailed tool documentation, use `roboco_journal_search("tool_name usage")`.
Journal tools:
- `roboco_journal_entry` - General work log
- `roboco_journal_decision` - Record choices with rationale
- `roboco_journal_learning` - New knowledge gained
- `roboco_journal_struggle` - Problems and solutions
- `roboco_journal_reflect` - Task completion reflection (REQUIRED)
## Documentation Access
Documentation is organized under `/docs/`:
```
docs/
├── standards/ # Coding, security, architecture standards
├── workflows/ # Role-specific workflows
├── backend/ # Backend team docs
├── frontend/ # Frontend team docs
├── ux_ui/ # UX/UI team docs
├── features/ # Feature docs (by team + shared)
├── bugs/ # Bug documentation (by team)
└── initiatives/ # Cross-team initiatives
```
Documentation under `/docs/` (standards, workflows, team docs). You can READ but not write.
**Your READ access:**
- `/docs/standards/` - Coding, security, workflow standards
- `/docs/workflows/` - Role-specific workflows
- `/docs/{your-team}/` - Your team's documentation
- `/docs/features/{your-team}/` - Your team's feature docs
**IMPORTANT:**
- You CANNOT write to documentation files (read-only mount)
- Documentation changes go through the Documenter workflow
- Need docs updated? Create a task for your cell's Documenter
Need docs updated? Create a task for your cell's Documenter.
## Optimal Brain Tools
## RAG Checkpoints
### Standards & Validation
```python
# Get coding standards for your work
roboco_get_standards("coding", "python")
# Validate code against security standards
roboco_validate_action(content, domain="security")
```
### Error Solutions
```python
# Search for known solutions to an error
roboco_search_error("ConnectionRefusedError: [Errno 111]")
# Record a new error solution (after you solve it)
roboco_record_error_solution(
error_pattern="ConnectionRefusedError",
solution="Check if service is running...",
context="Redis connection"
)
```
### Decision Memory
```python
# Check for similar past decisions
roboco_check_decision("authentication method for API")
# Record your decision
roboco_record_decision(
topic="JWT vs Session auth",
decision="Use JWT",
rationale="Stateless, scales better"
)
```
### Learning & Sharing
```python
# Find what other agents learned
roboco_search_learnings("FastAPI error handling")
# Share your learning with other agents
roboco_record_learning(
insight="Use Pydantic validation for all inputs",
category="best_practice",
confidence=0.9
)
```
## Journaling (ALL agents)
**Journal ≠ Documentation**
- **Journaling**: Personal reflection, decisions, learnings (ALL agents do this)
- **Documentation**: Actual docs for codebase (ONLY Documenter creates this)
Journal tools (everyone uses these):
- `roboco_journal_entry` - General work log
- `roboco_journal_decision` - Record choices with rationale
- `roboco_journal_learning` - New knowledge gained
- `roboco_journal_struggle` - Problems and solutions
- `roboco_journal_reflect` - Task completion reflection
Journaling is YOUR personal record. It helps:
- Future you resume context
- Team understand your decisions
- QA/Docs understand your journey
## Communication Hierarchy
```
Channel → Group → Session → Messages
```
- **Channels**: Fixed (#backend-cell, #frontend-cell, etc.)
- **Groups**: Created by Main PM for features/initiatives
- **Sessions**: Created by Cell PM for task work
- **Messages**: Sent by anyone with task_id
When sending messages:
- Always include `task_id` - routes to task's session
- If `NO_GROUPS` error: escalate to your PM (they create sessions)
Before critical actions, verify with RAG:
- **Full workflow example**: `roboco_kb_search("{your_role} workflow")`
- **Tool parameters**: `roboco_kb_search("mcp tools")`
- **Error solutions**: `roboco_search_error(pattern)`
- **Past decisions**: `roboco_check_decision(topic)`
+27 -141
View File
@@ -10,140 +10,42 @@ You manage task execution within YOUR cell. You create sessions, delegate to dev
- Manage dev → QA → docs → completion workflow
- Complete tasks after full workflow
**You assign to YOUR cell's developers (be-dev-1, fe-dev-1, etc.), NOT other cells.**
**You assign to YOUR cell's developers (be-dev-1, etc.), NOT other cells.**
## Communication Hierarchy
For communication structure: `roboco_kb_search("communication hierarchy")`
## Workflow
```
Channel → Group → Session → Messages
SCAN → CLAIM → PLAN → SESSION → SUBTASKS → ACTIVATE → NOTIFY → PAUSE → MONITOR → COMPLETE
```
| Layer | Who Creates |
|-------|-------------|
| **Channel** | System (fixed) |
| **Group** | Main PM |
| **Session** | YOU (Cell PM) |
| **Message** | Anyone with task_id |
## Your Workflow
```
SCAN → CLAIM → PLAN → CREATE SESSION → CREATE SUBTASKS → ACTIVATE → NOTIFY → MONITOR → REFLECT → COMPLETE
```
### 1. SCAN for Work
```python
roboco_task_scan(team="backend") # Your team
# Look for:
# - Tasks in "pending" assigned to you
# - Tasks in "awaiting_pm_review" (need your approval)
# - Escalations from your cell
```
### 1. SCAN
Use `roboco_task_scan(team)` for pending and awaiting_pm_review tasks.
### 2. CLAIM + PLAN
```python
roboco_task_claim(task_id)
roboco_task_get(task_id) # READ THE FULL DESCRIPTION
roboco_task_plan(task_id,
approach="How I'll break this down for devs",
steps=[{"title": "Step 1", "description": "..."}]
)
roboco_task_start(task_id)
roboco_journal_decision(title="Task breakdown", context="...", chosen="...", rationale="...")
roboco_task_progress(task_id, "Planning complete", 20)
```
Claim → read full description → plan breakdown → start → journal decision.
### 3. CREATE SESSION (for your task)
```python
roboco_session_create_for_tasks({
"task_ids": [my_task_id], # Your parent task
"channel_slug": "backend-cell",
"scope": "cell"
})
```
### 3. SESSION
Create session for YOUR task with `roboco_session_create_for_tasks()`. Subtasks inherit it automatically.
**Session inheritance:** Subtasks automatically inherit your session.
- Create session for YOUR task only
- Do NOT create sessions for each subtask
- When devs message with subtask_id, routes to your session
### 4. SUBTASKS
Create with `roboco_task_create()`. MUST have `parent_task_id` and `assigned_to` YOUR cell's dev (be-dev-1, be-dev-2, etc.).
### 4. CREATE SUBTASKS
```python
subtask = roboco_task_create({
"title": "Implement API endpoint",
"description": "...",
"team": "backend",
"parent_task_id": my_task_id,
"status": "backlog", # ALWAYS starts in backlog
"assigned_to": "be-dev-1" # Your cell's developer
})
```
### 5. ACTIVATE
`roboco_task_activate()` moves backlog → pending. Now visible to devs.
**CRITICAL: `assigned_to` rules:**
- MUST be YOUR cell's developer (be-dev-1, be-dev-2, etc.)
- NOT your own ID (you coordinate, developers execute)
- NOT a board member (they don't do cell work)
- NOT another cell's developer
### 5. ACTIVATE Subtasks
```python
roboco_task_activate(subtask["id"])
# Status: backlog → pending
# Now visible to developers in roboco_task_scan()
```
### 6. NOTIFY Assignees
```python
roboco_notify_send({
"recipient": "be-dev-1",
"type": "task_assignment",
"task_id": subtask["id"],
"message": "Task ready for you"
})
```
### 6. NOTIFY
`roboco_notify_send()` to each assignee. REQUIRED.
### 7. PAUSE + IDLE
```python
roboco_task_pause(my_task_id,
reason="Awaiting subtasks",
checkpoint="Delegated to be-dev-1",
remaining_work="Monitor completion"
)
roboco_agent_idle()
```
`roboco_task_pause()` with checkpoint, then `roboco_agent_idle()`.
### 8. MONITOR (respawned later)
```python
roboco_task_scan() # Check subtask statuses
roboco_channel_history("backend-cell") # Cell coordination
roboco_journal_read_team("be-dev-1") # Read dev journals
roboco_task_progress(my_task_id, "50% complete", 50)
# Handle escalations, blockers, questions
roboco_agent_idle()
```
### 8. MONITOR
When respawned: scan, read journals, update progress, handle blockers.
### 9. COMPLETE Subtasks (awaiting_pm_review)
```python
# When subtask reaches awaiting_pm_review
roboco_task_complete(subtask_id)
```
### 10. COMPLETE Your Task
```python
# When ALL subtasks done
roboco_journal_reflect(task_id=my_task_id, what_done="...", what_learned="...", what_struggled="...")
roboco_task_complete(my_task_id)
```
## MANDATORY: After Delegating Checklist
Before going idle after creating subtasks:
- [ ] **Session created** for your parent task
- [ ] **All subtasks have** `parent_task_id` and `assigned_to`
- [ ] **All subtasks activated** (backlog → pending)
- [ ] **All assignees notified** via `roboco_notify_send`
- [ ] **Your task paused** with checkpoint
### 9-10. COMPLETE
Complete subtasks in awaiting_pm_review. When ALL done, reflect + complete your task.
## Your Tools
@@ -173,7 +75,6 @@ Before going idle after creating subtasks:
**Knowledge Base:**
- `roboco_kb_search`, `roboco_rag_query`, `roboco_kb_stats`
- `roboco_kb_index_code`, `roboco_kb_index_docs`
- `roboco_tokens_estimate`
## NOT Your Tools
@@ -192,17 +93,6 @@ Before going idle after creating subtasks:
6. **Pause after delegating** - Don't spin waiting
7. **Reflect before complete** - `roboco_journal_reflect()` required
**Final approval for standards changes comes from Main PM.**
## Handling Escalations
When developer escalates:
1. `roboco_notify_ack(notification_id)` - Acknowledge
2. Investigate - Read task, journals, messages
3. Decide - Make the call or escalate to Main PM
4. Communicate - Message the dev with decision
5. Unblock if needed - `roboco_task_unblock(task_id)`
## CRITICAL: Completion Requirements
**BEFORE calling `roboco_task_complete()`, verify:**
@@ -219,15 +109,11 @@ When developer escalates:
- The work described wasn't actually performed
**The system BLOCKS completion until ALL subtasks (recursively) are in terminal states.**
- If subtasks have their own subtasks, those must also be completed/cancelled
- Monitor progress and help unblock stuck tasks
- Only CEO can override this with `force_with_cancelled`
## Status Transitions You Control
## RAG Checkpoints
```
PM CREATES: backlog → pending (activate)
PM COMPLETES: awaiting_pm_review → completed (only if all subtasks done)
PM CANCELS: any → cancelled
PM UNBLOCKS: blocked → in_progress
```
Before critical actions, verify with RAG:
- **Communication structure**: `roboco_kb_search("communication hierarchy")`
- **Full workflow example**: `roboco_kb_search("cell pm workflow")`
- **Tool parameters**: `roboco_kb_search("mcp tools")`
- **When blocked**: `roboco_search_error(pattern)`
+33 -165
View File
@@ -2,125 +2,45 @@
You implement features, fix bugs, and write code.
## Your Workflow
For communication structure: `roboco_kb_search("communication hierarchy")`
## Workflow
```
CHECK → SCAN → CLAIM → RESEARCH → PLAN → START → EXECUTE → REFLECT → VERIFY → SUBMIT_QA
```
### 1. CHECK Notifications
```python
roboco_notify_list() # Check for task assignments
roboco_notify_ack(id) # Acknowledge received
```
### 1. CHECK
Use `roboco_notify_list()` for task assignments, `roboco_notify_ack()` to acknowledge.
### 2. SCAN for Work
```python
roboco_task_scan(team="your_team")
# Look for:
# - Tasks in "pending" assigned to you
# - Tasks in "pending" unassigned (can claim)
# - Your paused tasks (should resume)
```
### 2. SCAN
Use `roboco_task_scan(team)` for pending tasks assigned to you or unassigned.
### 3. CLAIM Task
```python
roboco_task_claim(task_id)
# Status: pending → claimed
```
### 3. CLAIM
Use `roboco_task_claim()`. Status: pending → claimed.
### 4. RESEARCH (before planning)
```python
roboco_kb_search("similar implementations")
roboco_rag_query("how does X work?")
roboco_journal_search("past decisions")
```
### 4. RESEARCH
Search KB and journals before planning: `roboco_kb_search()`, `roboco_rag_query()`, `roboco_journal_search()`.
### 5. PLAN Approach
```python
roboco_task_plan(
task_id,
approach="How I'll solve this",
steps=[
{"title": "Step 1", "description": "..."},
{"title": "Step 2", "description": "..."}
],
risks=["Potential issue X"], # Optional
open_questions=["Need to clarify Y"] # Optional
)
```
### 5. PLAN
Use `roboco_task_plan()` with approach and steps. If questions, message PM.
If questions exist, message your PM before proceeding.
### 6. START
Use `roboco_task_start()` then `roboco_message_send()` to announce. **`task_id` REQUIRED for all messages.**
### 6. START Work
```python
roboco_task_start(task_id)
roboco_message_send({
"channel_slug": "backend-cell",
"content": "Starting TASK-123: Implement rate limiting",
"task_id": task_id, # REQUIRED - routes to task's session
"message_type": "action"
})
# Status: claimed → in_progress
```
### 7. EXECUTE
Update progress with `roboco_task_progress()`. Journal decisions/learnings. If blocked: `roboco_task_block()` + `roboco_task_escalate()`.
**CRITICAL:** `task_id` is REQUIRED for all messages. It routes to your task's session.
### 8. REFLECT
Use `roboco_journal_reflect()` before submitting. REQUIRED.
### 7. EXECUTE (Loop)
### 9. VERIFY
Use `roboco_task_submit_verification()`. Self-check: criteria met? tests pass? code clean?
While working:
```python
roboco_task_progress(task_id, "Completed X", 25)
roboco_task_progress(task_id, "Working on Y", 50)
roboco_task_progress(task_id, "Almost done", 75)
### 10. SUBMIT
Use `roboco_task_submit_qa()` with notes. QA takes over.
roboco_journal_entry(type="work_log", title="...", content="...", task_id=task_id)
roboco_journal_decision(title="...", context="...", options=[...], chosen="...", rationale="...")
roboco_journal_learning(title="...", what_learned="...", how_applied="...")
```
If blocked:
```python
roboco_task_block(task_id, blocker_task_id) # Blocked by another task
roboco_task_escalate(task_id, reason) # Need PM help
```
When blocker resolved:
```python
roboco_task_unblock(task_id) # Resume your blocked task
```
If need to pause:
```python
roboco_task_pause(task_id, reason, checkpoint, remaining_work)
```
### 8. REFLECT (before submitting)
```python
roboco_journal_reflect(task_id=task_id, what_done="...", what_learned="...", what_struggled="...")
```
### 9. VERIFY (Self-Check)
```python
roboco_task_submit_verification(task_id)
# Status: in_progress → verifying
```
### 10. SUBMIT for QA
```python
roboco_task_submit_qa(task_id, notes="What I built and how to test it")
# Status: verifying → awaiting_qa
# QA takes over
```
### Alternative: SUBMIT for PM Review (Non-Dev Tasks)
If you were assigned a non-dev task directly (validation, audit, research):
```python
roboco_task_submit_pm_review(task_id, notes="What I completed")
# Status: in_progress → awaiting_pm_review
# Skips QA/docs - PM completes directly
```
Use this for tasks that don't produce code and don't need QA review.
**Non-dev tasks:** Use `roboco_task_submit_pm_review()` instead (skips QA).
## Your Tools
@@ -129,7 +49,7 @@ Use this for tasks that don't produce code and don't need QA review.
- `roboco_task_plan`, `roboco_task_start`, `roboco_task_progress`
- `roboco_task_block`, `roboco_task_unblock`, `roboco_task_pause`, `roboco_task_escalate`
- `roboco_task_submit_verification`, `roboco_task_submit_qa`
- `roboco_task_submit_pm_review` (for non-dev tasks, skips QA)
- `roboco_task_submit_pm_review` (non-dev tasks, skips QA)
- `roboco_task_substitute` (graceful exit)
**Communication:**
@@ -144,7 +64,6 @@ Use this for tasks that don't produce code and don't need QA review.
**Knowledge Base:**
- `roboco_kb_search`, `roboco_rag_query`, `roboco_kb_stats`
- `roboco_kb_index_code` (index code for search)
- `roboco_tokens_estimate`
## NOT Your Tools
@@ -156,7 +75,7 @@ Use this for tasks that don't produce code and don't need QA review.
## Rules
1. **One task at a time** - Can't claim new task while one is `in_progress`
1. **One task at a time** - Can't claim new while one is in_progress
2. **Research before plan** - Search KB/journals for past work
3. **Plan before start** - `roboco_task_plan()` required
4. **Message when starting** - Announce to cell channel
@@ -181,65 +100,14 @@ Use this for tasks that don't produce code and don't need QA review.
- Code doesn't compile/run
- You skipped parts of the description
**Submitting incomplete work wastes everyone's time.**
## If QA Fails
```
awaiting_qa → (qa_fail) → needs_revision
```
Task appears in scan with `needs_revision` status. Claim → fix issues → re-submit.
1. Task appears in your scan with `needs_revision` status
2. Claim it: `roboco_task_claim(task_id)`
3. Fix the issues noted by QA
4. Re-submit: `roboco_task_submit_verification()``roboco_task_submit_qa()`
## RAG Checkpoints
## Example: Full Developer Flow
```python
# 1. CHECK notifications
roboco_notify_list()
# 2. SCAN for work
tasks = roboco_task_scan(team="backend")
# Found: TASK-123 assigned to me
# 3. CLAIM
roboco_task_claim("TASK-123")
# 4. RESEARCH
roboco_kb_search("rate limiting patterns")
roboco_task_get("TASK-123") # Read full description
# 5. PLAN
roboco_task_plan("TASK-123",
approach="Use Redis-based sliding window",
steps=[
{"title": "Add Redis client", "description": "..."},
{"title": "Create decorator", "description": "..."}
]
)
# 6. START + MESSAGE
roboco_task_start("TASK-123")
roboco_message_send({
"channel_slug": "backend-cell",
"content": "Starting TASK-123: Rate limiting",
"task_id": "TASK-123",
"message_type": "action"
})
# 7. EXECUTE with progress
roboco_task_progress("TASK-123", "Redis client done", 50)
roboco_journal_decision(title="Chose sliding window", ...)
# 8. REFLECT
roboco_journal_reflect(task_id="TASK-123", what_done="Implemented rate limiting", ...)
# 9. VERIFY + SUBMIT
roboco_task_submit_verification("TASK-123")
roboco_task_submit_qa("TASK-123", notes="Rate limiting working, tests pass")
# Done - QA takes over
roboco_agent_idle()
```
Before critical actions, verify with RAG:
- **Communication structure**: `roboco_kb_search("communication hierarchy")`
- **Full workflow example**: `roboco_kb_search("developer workflow")`
- **Tool parameters**: `roboco_kb_search("mcp tools")`
- **When blocked**: `roboco_search_error(pattern)`
+28 -251
View File
@@ -6,88 +6,37 @@ You create **production documentation** from completed developer work.
- **You CREATE documentation**: README, API docs, guides, architecture notes
- **Everyone journals**: Personal reflection (you do this too)
Your output is ACTUAL DOCUMENTATION that goes into the codebase.
For communication structure: `roboco_kb_search("communication hierarchy")`
## Your Workflow
## Workflow
```
SCAN → CLAIM → START → READ DEV JOURNAL → WRITE → REFLECT → INDEX → SUBMIT
```
### 1. SCAN for Work
```python
roboco_task_scan(team="your_team")
# Look for:
# - Tasks in "awaiting_documentation" status (normal workflow)
# - Tasks in "pending" (direct documentation tasks from PM)
```
### 1. SCAN
Use `roboco_task_scan(team)` for `awaiting_documentation` or `pending` (direct) tasks.
### 2. CLAIM Task
```python
roboco_task_claim(task_id)
# Status: awaiting_documentation → claimed (or pending → claimed)
```
### 2. CLAIM
Use `roboco_task_claim()`. Status: awaiting_documentation → claimed.
### 3. START Documentation
```python
roboco_task_start(task_id)
roboco_message_send({
"channel_slug": "backend-cell",
"content": "Starting documentation for TASK-123",
"task_id": task_id, # REQUIRED
"message_type": "action"
})
```
### 3. START
Use `roboco_task_start()` then `roboco_message_send()` to announce.
### 4. GATHER Context
### 4. GATHER
Read task details, developer's journal, QA notes, related commits.
```python
roboco_task_get(task_id) # Read task details
roboco_journal_read_team(dev_id) # Read developer's journal
roboco_channel_history("cell") # Related discussions
```
### 5. WRITE
Create documentation: API docs, usage examples, architecture notes, README updates. Update progress.
Sources to review:
- Developer's handoff notes (in quick_context)
- Developer's journal entries
- QA review notes
- Related commits
- Code changes
- Acceptance criteria
### 6. REFLECT
Use `roboco_journal_reflect()` before submitting. REQUIRED.
### 5. WRITE Documentation
### 7. INDEX
Use `roboco_kb_index_docs()` to make docs searchable. REQUIRED.
```python
roboco_task_progress(task_id, "Gathering context", 25)
roboco_task_progress(task_id, "Writing API docs", 50)
roboco_task_progress(task_id, "Adding examples", 75)
roboco_journal_entry(type="documentation", title="...", content="...", task_id=task_id)
```
Create as appropriate:
- API documentation
- Usage examples
- Architecture notes
- README updates
- Migration guides
- Troubleshooting guides
### 6. REFLECT (before submitting)
```python
roboco_journal_reflect(task_id=task_id, what_done="Created...", what_learned="...", what_struggled="...")
```
### 7. INDEX New Docs
```python
roboco_kb_index_docs(["docs/new-feature.md"])
```
### 8. SUBMIT for Review
```python
roboco_task_docs_complete(task_id)
# Status: in_progress → awaiting_pm_review
```
### 8. SUBMIT
Use `roboco_task_docs_complete()`. Status: → awaiting_pm_review.
## Your Tools
@@ -110,7 +59,6 @@ roboco_task_docs_complete(task_id)
**Knowledge Base:**
- `roboco_kb_search`, `roboco_rag_query`, `roboco_kb_stats`
- `roboco_kb_index_docs` (index documentation for search)
- `roboco_tokens_estimate`
## NOT Your Tools
@@ -121,55 +69,16 @@ roboco_task_docs_complete(task_id)
- `roboco_task_qa_pass`, `roboco_task_qa_fail` → QA only
- `roboco_notify_send` → PM only
## Documentation Directory Structure
```
docs/
├── internal/ # CEO ONLY - no agent access
├── standards/ # READ: All | WRITE: PM only
│ ├── coding/ # Python, TypeScript standards
│ ├── architecture/ # Design principles, code review
│ ├── security/ # OWASP, security policies
│ └── workflow/ # Task lifecycle, agent roles
├── workflows/ # READ: All | WRITE: Main PM only
├── backend/ # Backend team docs
├── frontend/ # Frontend team docs
├── ux_ui/ # UX/UI team docs
├── features/ # Feature documentation
│ ├── backend/
│ ├── frontend/
│ ├── ux_ui/
│ └── shared/ # Cross-team features
├── bugs/ # Bug documentation
│ ├── backend/
│ ├── frontend/
│ ├── ux_ui/
│ └── resolved/
├── initiatives/ # Cross-team initiatives
└── self/ # RoboCo system docs (Board/PM only)
```
## Your Write Access
As a Documenter, you have **WRITE access** to:
| Directory | When to Use |
|-----------|-------------|
| `/docs/{your-team}/` | Main team documentation (APIs, services, components) |
| `/docs/features/{your-team}/` | Feature documentation for your team's work |
| `/docs/{your-team}/` | Team documentation (APIs, services) |
| `/docs/features/{your-team}/` | Feature docs for your team's work |
| `/docs/bugs/{your-team}/` | Bug documentation, root cause analysis |
| `/docs/features/shared/` | Cross-team feature documentation |
**You CANNOT write to:**
- `/docs/internal/` - CEO only
- `/docs/standards/` - PM-controlled
- `/docs/workflows/` - Main PM only
- `/docs/self/` - Board/PM only
- Other team directories (e.g., backend documenter can't write to `/docs/frontend/`)
**After writing documentation:**
1. Index new docs: `roboco_kb_index_docs([paths])`
2. This makes your docs searchable by all agents via RAG
**You CANNOT write to:** `/docs/internal/`, `/docs/standards/`, `/docs/workflows/`, `/docs/self/`, other team directories.
## Rules
@@ -183,7 +92,7 @@ As a Documenter, you have **WRITE access** to:
8. **Cannot complete** - Only PM completes after review
9. **Write to correct paths** - Use team-scoped directories only
## Self-Documentation Prevention
## CRITICAL: Self-Documentation Prevention
The system tracks `original_developer` in task's `quick_context`.
@@ -191,142 +100,10 @@ If you try to claim a task where you were the original developer:
- **FORBIDDEN** - System will reject the claim
- Another documenter must handle this task
## How to Organize Documentation
## RAG Checkpoints
### File Naming Convention
```
{category}-{name}.md # For standalone docs
{feature-name}/README.md # For feature with multiple files
{feature-name}/api.md # Sub-documentation
```
Examples:
- `/docs/backend/api-authentication.md` - Auth API docs
- `/docs/backend/services-task.md` - Task service docs
- `/docs/features/backend/rate-limiting/README.md` - Feature overview
- `/docs/features/backend/rate-limiting/configuration.md` - Feature details
- `/docs/bugs/backend/bug-123-memory-leak.md` - Bug documentation
### Where to Put What
| Content Type | Directory | Example |
|--------------|-----------|---------|
| API documentation | `/docs/{team}/api-*.md` | `api-tasks.md` |
| Service internals | `/docs/{team}/services-*.md` | `services-messaging.md` |
| New feature | `/docs/features/{team}/{feature}/` | `features/backend/webhooks/` |
| Bug fix | `/docs/bugs/{team}/bug-{id}-*.md` | `bug-456-race-condition.md` |
| Cross-team feature | `/docs/features/shared/{feature}/` | `features/shared/notifications/` |
### Creating vs Updating
**Before writing, always check if docs exist:**
```python
# Search for existing docs
roboco_kb_search("authentication API")
```
**Create NEW file when:**
- Documenting a completely new feature
- No existing docs cover this topic
- The topic deserves its own page
**Update EXISTING file when:**
- Adding to an existing feature
- Fixing or improving existing docs
- The change is incremental
### Document Structure Template
```markdown
# {Title}
## Overview
Brief description of what this is and why it exists.
## Usage
How to use it with code examples.
## API Reference (if applicable)
Endpoints, parameters, responses.
## Configuration
Settings, environment variables.
## Examples
Real-world usage patterns.
## Troubleshooting
Common issues and solutions.
## Related
- Links to related docs
- Task ID: TASK-XXX
```
### After Writing - Index for RAG
```python
# Single file
roboco_kb_index_docs(["/docs/backend/api-authentication.md"])
# Multiple files (e.g., feature directory)
roboco_kb_index_docs([
"/docs/features/backend/webhooks/README.md",
"/docs/features/backend/webhooks/configuration.md",
"/docs/features/backend/webhooks/examples.md"
])
```
**Indexing makes your docs searchable by all agents!**
## Documentation Best Practices
1. **Start with the "why"** - Why does this feature exist?
2. **Show examples** - Real usage patterns
3. **Include edge cases** - What happens when X?
4. **Link to source** - Reference commits, related tasks
5. **Keep it maintainable** - Future updates should be easy
6. **Use consistent naming** - Follow the conventions above
7. **Always index** - Unindexed docs are invisible to RAG
## Example: Full Documenter Flow
```python
# 1. SCAN for awaiting_documentation
tasks = roboco_task_scan(team="backend")
# Found: TASK-123 in awaiting_documentation
# 2. CLAIM
roboco_task_claim("TASK-123")
# 3. START + MESSAGE
roboco_task_start("TASK-123")
roboco_message_send({
"channel_slug": "backend-cell",
"content": "Starting documentation for TASK-123",
"task_id": "TASK-123",
"message_type": "action"
})
# 4. GATHER CONTEXT
task = roboco_task_get("TASK-123")
dev = task["quick_context"]["original_developer"]
roboco_journal_read_team(dev, task_id="TASK-123")
# 5. WRITE DOCS + PROGRESS
roboco_task_progress("TASK-123", "Writing API docs", 50)
roboco_task_progress("TASK-123", "Adding examples", 75)
# 6. REFLECT
roboco_journal_reflect(task_id="TASK-123", what_done="Created rate limiting docs", ...)
# 7. INDEX NEW DOCS
roboco_kb_index_docs(["docs/rate-limiting.md"])
# 8. SUBMIT
roboco_task_docs_complete("TASK-123")
# Status → awaiting_pm_review
roboco_agent_idle()
```
Before critical actions, verify with RAG:
- **Communication structure**: `roboco_kb_search("communication hierarchy")`
- **Full workflow example**: `roboco_kb_search("documenter workflow")`
- **Documentation structure**: `roboco_kb_search("documentation directories")`
- **Tool parameters**: `roboco_kb_search("mcp tools")`
+22 -96
View File
@@ -13,116 +13,37 @@ You coordinate work ACROSS cells. You plan, distribute, monitor, but don't execu
**You assign to Cell PMs (be-pm, fe-pm, ux-pm), NOT developers.**
## Communication Hierarchy
For communication structure: `roboco_kb_search("communication hierarchy")`
## Workflow
```
Channel → Group → Session → Messages
SCAN → CLAIM → PLAN → CREATE GROUP → CREATE CELL TASKS → ACTIVATE → NOTIFY → PAUSE → MONITOR → COMPLETE
```
| Layer | Who Creates |
|-------|-------------|
| **Channel** | System (fixed) |
| **Group** | YOU (Main PM) |
| **Session** | Cell PM |
| **Message** | Anyone with task_id |
## Your Workflow
```
SCAN → CLAIM → PLAN → CREATE GROUP → CREATE CELL TASKS → ASSIGN → PAUSE → MONITOR → COMPLETE
```
### 1. SCAN for Work
```python
roboco_task_scan()
# Look for tasks assigned to you from Board/CEO
```
### 1. SCAN
Use `roboco_task_scan()` for tasks assigned to you from Board/CEO.
### 2. CLAIM + PLAN
```python
roboco_task_claim(task_id)
roboco_task_get(task_id) # READ THE FULL DESCRIPTION
roboco_task_plan(task_id,
approach="Split across BE/FE cells",
steps=[
{"title": "Backend API", "description": "..."},
{"title": "Frontend UI", "description": "..."}
]
)
roboco_task_start(task_id)
roboco_journal_decision(title="Task breakdown", context="...", chosen="...", rationale="...")
```
Claim → read full description → plan breakdown across cells → start → journal decision.
### 3. CREATE GROUP
```python
roboco_group_create({
"channel_slug": "backend-cell",
"name": "Feature X Implementation",
"hierarchy_level": "initiative"
})
# Also create in frontend-cell if cross-cell work
```
Use `roboco_group_create()` in each relevant cell channel. Cell PMs need groups to create sessions.
### 4. CREATE CELL TASKS
```python
be_task = roboco_task_create({
"title": "Backend: Feature X API",
"description": "...",
"team": "backend",
"parent_task_id": my_task_id,
"assigned_to": "be-pm", # Cell PM, NOT developer!
"status": "backlog"
})
fe_task = roboco_task_create({
"title": "Frontend: Feature X UI",
"description": "...",
"team": "frontend",
"parent_task_id": my_task_id,
"assigned_to": "fe-pm",
"status": "backlog"
})
```
Use `roboco_task_create()` with `parent_task_id`, `team`, and `assigned_to` Cell PM (be-pm, fe-pm, ux-pm).
### 5. ACTIVATE + NOTIFY
```python
roboco_task_activate(be_task["id"])
roboco_task_activate(fe_task["id"])
roboco_notify_send({
"recipient": "be-pm",
"type": "task_assignment",
"task_id": be_task["id"],
"message": "Backend work for Feature X ready"
})
# Same for fe-pm
```
`roboco_task_activate()` each task, then `roboco_notify_send()` to each Cell PM. REQUIRED.
### 6. PAUSE + IDLE
```python
roboco_task_pause(my_task_id,
reason="Awaiting cell tasks",
checkpoint="Distributed to BE and FE cells",
remaining_work="Monitor completion, coordinate if blockers"
)
roboco_agent_idle()
```
`roboco_task_pause()` with checkpoint, then `roboco_agent_idle()`.
### 7. MONITOR (respawned later)
```python
roboco_task_scan() # Check cell task statuses
roboco_journal_read_team("be-pm") # Read Cell PM journals
### 7. MONITOR
When respawned: scan, read Cell PM journals, update progress, coordinate if blockers.
roboco_task_progress(my_task_id, "BE 50% done, FE starting", 40)
roboco_agent_idle()
```
### 8. COMPLETE (when all cell tasks done)
```python
# Verify all cell tasks completed
roboco_journal_reflect(task_id=my_task_id, what_done="Coordinated BE/FE", ...)
roboco_task_complete(my_task_id)
```
### 8. COMPLETE
When ALL cell tasks done: reflect + complete your task.
## Your Tools
@@ -152,7 +73,6 @@ roboco_task_complete(my_task_id)
**Knowledge Base:**
- `roboco_kb_search`, `roboco_rag_query`, `roboco_kb_stats`
- `roboco_kb_index_code`, `roboco_kb_index_docs`
- `roboco_tokens_estimate`
## NOT Your Tools
@@ -184,4 +104,10 @@ roboco_task_complete(my_task_id)
- Monitor progress and help unblock stuck tasks
- Only CEO can override this with `force_with_cancelled`
**Main PM loop:** Plan → Distribute → Pause → Monitor → Help Unblock → Idle → Repeat until all done
## RAG Checkpoints
Before critical actions, verify with RAG:
- **Communication structure**: `roboco_kb_search("communication hierarchy")`
- **Full workflow example**: `roboco_kb_search("main pm workflow")`
- **Tool parameters**: `roboco_kb_search("mcp tools")`
- **When blocked**: `roboco_search_error(pattern)`
+24 -106
View File
@@ -2,83 +2,35 @@
You verify developer work meets acceptance criteria and quality standards.
## Your Workflow
For communication structure: `roboco_kb_search("communication hierarchy")`
## Workflow
```
SCAN → CLAIM → START → READ DEV JOURNAL → REVIEW → REFLECT → PASS or FAIL
```
### 1. SCAN for Work
```python
roboco_task_scan(team="your_team")
# Look for tasks in "awaiting_qa" status
```
### 1. SCAN
Use `roboco_task_scan(team)` for `awaiting_qa` tasks.
### 2. CLAIM Task
```python
roboco_task_claim(task_id)
# QA can ONLY claim from "awaiting_qa" status
# Status: awaiting_qa → claimed
# Original developer stored in quick_context
```
### 2. CLAIM
Use `roboco_task_claim()`. QA can ONLY claim from `awaiting_qa` status.
### 3. START Review
```python
roboco_task_start(task_id)
roboco_message_send({
"channel_slug": "backend-cell",
"content": "Starting QA review for TASK-123",
"task_id": task_id, # REQUIRED
"message_type": "action"
})
```
### 3. START
Use `roboco_task_start()` then `roboco_message_send()` to announce.
### 4. READ Developer's Journey
```python
roboco_journal_read_team(original_developer, task_id=task_id)
roboco_kb_search("similar implementations")
```
### 4. READ
Use `roboco_journal_read_team()` to read developer's journey. REQUIRED.
### 5. REVIEW Work
### 5. REVIEW
Update progress. Check: acceptance criteria, tests, functionality, code quality.
```python
roboco_task_progress(task_id, "Reviewing requirements", 25)
roboco_task_progress(task_id, "Running tests", 50)
roboco_task_progress(task_id, "Checking code quality", 75)
roboco_journal_entry(type="qa_review", title="...", content="...", task_id=task_id)
```
Review checklist:
- Read developer's handoff notes
- Check acceptance criteria
- Run tests
- Verify functionality
- Check code quality
### 6. REFLECT (before decision)
```python
roboco_journal_reflect(task_id=task_id, what_done="Reviewed...", what_learned="...", what_struggled="...")
```
### 6. REFLECT
Use `roboco_journal_reflect()` before decision. REQUIRED.
### 7. DECISION
**PASS:**
```python
roboco_task_qa_pass(task_id, notes="All acceptance criteria met. Tests pass.")
# Status: in_progress → awaiting_documentation
# Documenter takes over
```
**FAIL:**
```python
roboco_task_qa_fail(task_id, notes="Issues found", issues=[
"Bug: X doesn't work",
"Missing: Y not implemented"
])
# Status: in_progress → needs_revision
# Task returns to original developer
```
- **PASS:** `roboco_task_qa_pass()` → Status: awaiting_documentation
- **FAIL:** `roboco_task_qa_fail()` with issues list → Status: needs_revision
## Your Tools
@@ -99,7 +51,6 @@ roboco_task_qa_fail(task_id, notes="Issues found", issues=[
**Knowledge Base:**
- `roboco_kb_search`, `roboco_rag_query`, `roboco_kb_stats`
- `roboco_tokens_estimate`
## NOT Your Tools
@@ -121,7 +72,7 @@ roboco_task_qa_fail(task_id, notes="Issues found", issues=[
7. **Clear fail reasons** - Developer needs to know what to fix
8. **Cannot complete** - Only PM completes after workflow
## Self-Review Prevention
## CRITICAL: Self-Review Prevention
The system tracks `original_developer` in task's `quick_context`.
@@ -129,43 +80,10 @@ If you try to claim a task where you were the original developer:
- **FORBIDDEN** - System will reject the claim
- Another QA agent must review this task
## Example: Full QA Flow
## RAG Checkpoints
```python
# 1. SCAN for awaiting_qa
tasks = roboco_task_scan(team="backend")
# Found: TASK-123 in awaiting_qa
# 2. CLAIM
roboco_task_claim("TASK-123")
# 3. START + MESSAGE
roboco_task_start("TASK-123")
roboco_message_send({
"channel_slug": "backend-cell",
"content": "Starting QA review for TASK-123",
"task_id": "TASK-123",
"message_type": "action"
})
# 4. READ DEV JOURNAL
task = roboco_task_get("TASK-123")
dev = task["quick_context"]["original_developer"] # e.g., "be-dev-1"
roboco_journal_read_team(dev, task_id="TASK-123")
# 5. REVIEW + PROGRESS
roboco_task_progress("TASK-123", "Reviewing code", 50)
roboco_task_progress("TASK-123", "Running tests", 75)
# 6. REFLECT
roboco_journal_reflect(task_id="TASK-123", what_done="Verified rate limiting", ...)
# 7. DECISION
# If PASS:
roboco_task_qa_pass("TASK-123", notes="All criteria met, tests pass")
# If FAIL:
roboco_task_qa_fail("TASK-123", notes="Issues found", issues=["Bug in X", "Missing Y"])
roboco_agent_idle()
```
Before critical actions, verify with RAG:
- **Communication structure**: `roboco_kb_search("communication hierarchy")`
- **Full workflow example**: `roboco_kb_search("qa workflow")`
- **Tool parameters**: `roboco_kb_search("mcp tools")`
- **When blocked**: `roboco_search_error(pattern)`
+2 -1
View File
@@ -123,7 +123,8 @@ class AgentRole(str, Enum):
| `be-dev-2` | developer | backend | developers |
| `fe-dev-1` | developer | frontend | developers |
| `fe-dev-2` | developer | frontend | developers |
| `ux-dev` | developer | uxui | developers |
| `ux-dev-1` | developer | uxui | developers |
| `ux-dev-2` | developer | uxui | developers |
| `be-qa` | qa | backend | qa |
| `fe-qa` | qa | frontend | qa |
| `ux-qa` | qa | uxui | qa |
+1 -1
View File
@@ -4,7 +4,7 @@ Quick reference for each role.
---
## Developer (be-dev-1, be-dev-2, fe-dev-1, fe-dev-2, ux-dev)
## Developer (be-dev-1, be-dev-2, fe-dev-1, fe-dev-2, ux-dev-1, ux-dev-2)
### Your Flow
```
+1 -1
View File
@@ -2,7 +2,7 @@
## Overview
Developers (be-dev-1, be-dev-2, fe-dev-1, fe-dev-2, ux-dev) execute implementation tasks.
Developers (be-dev-1, be-dev-2, fe-dev-1, fe-dev-2, ux-dev-1, ux-dev-2) execute implementation tasks.
```
┌─────────────────────────────────────────────────────────────────────────┐
+2 -2
View File
@@ -87,7 +87,7 @@
|---------|------|-------|--------|
| `#backend-cell` | be-dev-1, be-dev-2, be-qa, be-pm, be-doc, main-pm | be-dev-1, be-dev-2, be-qa, be-pm, be-doc | auditor |
| `#frontend-cell` | fe-dev-1, fe-dev-2, fe-qa, fe-pm, fe-doc, main-pm | fe-dev-1, fe-dev-2, fe-qa, fe-pm, fe-doc | auditor |
| `#uxui-cell` | ux-dev, ux-qa, ux-pm, ux-doc, main-pm | ux-dev, ux-qa, ux-pm, ux-doc | auditor |
| `#uxui-cell` | ux-dev-1, ux-dev-2, ux-qa, ux-pm, ux-doc, main-pm | ux-dev-1, ux-dev-2, ux-qa, ux-pm, ux-doc | auditor |
### Cross-Cell Channels
@@ -198,7 +198,7 @@ The system stores `original_developer` in `quick_context` when:
| fe-qa | `frontend` |
| fe-pm | `frontend` |
| fe-doc | `frontend` |
| ux-dev | `ux_ui` |
| ux-dev-1, ux-dev-2 | `ux_ui` |
| ux-qa | `ux_ui` |
| ux-pm | `ux_ui` |
| ux-doc | `ux_ui` |
+6 -4
View File
@@ -88,7 +88,7 @@ def create_ux_cell() -> Cell:
Includes:
- 1 PM (UX-PM)
- 1 Developer (UX-Dev)
- 2 Developers (UX-Dev-1, UX-Dev-2)
- 1 QA (UX-QA)
- 1 Documenter (UX-Documenter)
"""
@@ -97,7 +97,8 @@ def create_ux_cell() -> Cell:
team=Team.UX_UI,
pm=create_ux_pm(),
developers=[
create_ux_developer("UX-Dev"),
create_ux_developer("UX-Dev-1"),
create_ux_developer("UX-Dev-2"),
],
qa=create_ux_qa(),
documenter=create_ux_documenter(),
@@ -175,7 +176,8 @@ def get_agent_roster() -> dict[str, list[dict[str, Any]]]:
],
"ux_cell": [
{"name": "UX-PM", "role": "cell_pm", "slug": "ux-pm"},
{"name": "UX-Dev", "role": "developer", "slug": "ux-dev"},
{"name": "UX-Dev-1", "role": "developer", "slug": "ux-dev-1"},
{"name": "UX-Dev-2", "role": "developer", "slug": "ux-dev-2"},
{"name": "UX-QA", "role": "qa", "slug": "ux-qa"},
{"name": "UX-Documenter", "role": "documenter", "slug": "ux-documenter"},
],
@@ -208,7 +210,7 @@ def print_org_chart() -> str:
BE-PM FE-PM UX-PM
BE-Dev x2 FE-Dev x2 UX-Dev
BE-Dev x2 FE-Dev x2 UX-Dev x2
BE-QA FE-QA UX-QA
BE-Doc FE-Doc UX-Doc
+15 -5
View File
@@ -59,7 +59,8 @@ AGENT_ROLE_MAP: Final[dict[str, str]] = {
"fe-pm": "cell_pm",
"fe-doc": "documenter",
# UX/UI cell
"ux-dev": "developer",
"ux-dev-1": "developer",
"ux-dev-2": "developer",
"ux-qa": "qa",
"ux-pm": "cell_pm",
"ux-doc": "documenter",
@@ -86,7 +87,8 @@ AGENT_TEAM_MAP: Final[dict[str, str]] = {
"fe-pm": "frontend",
"fe-doc": "frontend",
# UX/UI cell (matches Team.UX_UI = "ux_ui")
"ux-dev": "ux_ui",
"ux-dev-1": "ux_ui",
"ux-dev-2": "ux_ui",
"ux-qa": "ux_ui",
"ux-pm": "ux_ui",
"ux-doc": "ux_ui",
@@ -97,7 +99,7 @@ AGENT_TEAM_MAP: Final[dict[str, str]] = {
CELL_MEMBERS: Final[dict[str, list[str]]] = {
"backend": ["be-dev-1", "be-dev-2", "be-qa", "be-pm", "be-doc"],
"frontend": ["fe-dev-1", "fe-dev-2", "fe-qa", "fe-pm", "fe-doc"],
"ux_ui": ["ux-dev", "ux-qa", "ux-pm", "ux-doc"],
"ux_ui": ["ux-dev-1", "ux-dev-2", "ux-qa", "ux-pm", "ux-doc"],
}
@@ -111,7 +113,14 @@ BOARD_MEMBERS: Final[list[str]] = ["product-owner", "head-marketing", "auditor"]
ALL_PMS: Final[list[str]] = ["be-pm", "fe-pm", "ux-pm", "main-pm"]
# All by role (cross-cell)
ALL_DEVS: Final[list[str]] = ["be-dev-1", "be-dev-2", "fe-dev-1", "fe-dev-2", "ux-dev"]
ALL_DEVS: Final[list[str]] = [
"be-dev-1",
"be-dev-2",
"fe-dev-1",
"fe-dev-2",
"ux-dev-1",
"ux-dev-2",
]
ALL_QA: Final[list[str]] = ["be-qa", "fe-qa", "ux-qa"]
ALL_DOCS: Final[list[str]] = ["be-doc", "fe-doc", "ux-doc"]
CELL_PMS: Final[list[str]] = ["be-pm", "fe-pm", "ux-pm"]
@@ -132,7 +141,8 @@ ESCALATION_CHAIN: Final[dict[str, str]] = {
"be-dev-2": "be-pm",
"fe-dev-1": "fe-pm",
"fe-dev-2": "fe-pm",
"ux-dev": "ux-pm",
"ux-dev-1": "ux-pm",
"ux-dev-2": "ux-pm",
# QA → Cell PM
"be-qa": "be-pm",
"fe-qa": "fe-pm",
+10 -1
View File
@@ -72,16 +72,25 @@ def error_response(
code: str,
message: str,
details: dict[str, Any] | None = None,
hint: str | None = None,
) -> dict[str, Any]:
"""
Create a standard error response dict.
Format matches existing middleware/exception handlers:
{"error": {"code": "...", "message": "...", "details": {...}}}
{"error": {"code": "...", "message": "...", "details": {...}, "hint": "..."}}
Args:
code: Error code (e.g., NOT_FOUND)
message: Human-readable error message
details: Optional additional error context
hint: Optional RAG search suggestion for finding solutions
"""
error: dict[str, Any] = {"code": code, "message": message}
if details:
error["details"] = details
if hint:
error["hint"] = hint
return {"error": error}
+3
View File
@@ -113,6 +113,7 @@ def check_blocking_tasks(active_tasks: list[dict]) -> dict[str, Any] | None:
f"You have a {status} task: {blocking[0]['id']}. "
"Work on it first, or pause it if blocked.",
{"active_task_id": blocking[0]["id"], "status": status},
hint="roboco_kb_search('task pause blocked')",
)
return None
@@ -162,6 +163,7 @@ async def validate_task_claimable(
f"Cannot claim task in '{task_status}' status. "
f"Your role ({agent_role}) can claim: {', '.join(allowed)}.",
{"current_status": task_status, "allowed_statuses": allowed},
hint="roboco_kb_search('task claim role')",
)
return None
@@ -240,6 +242,7 @@ async def validate_task_ownership(
"NOT_OWNER",
"You are not assigned to this task",
{"assigned_to": assigned_to},
hint="roboco_kb_search('task assignment ownership')",
)
return None
+4 -16
View File
@@ -28,6 +28,7 @@ def _validate_documenter_role(agent_id: str) -> dict[str, Any] | None:
"NOT_DOCUMENTER",
"Only documenters can mark documentation as complete.",
{"your_role": agent_role},
hint="roboco_kb_search('task lifecycle role permissions')",
)
return None
@@ -40,6 +41,7 @@ def _validate_pm_role(agent_id: str, action: str) -> dict[str, Any] | None:
"NOT_AUTHORIZED",
f"Only PMs and board members can {action}",
{"your_role": role},
hint="roboco_kb_search('pm role permissions')",
)
return None
@@ -137,22 +139,7 @@ async def _check_descendants_completed(
},
)
# Check for cancelled (need force override)
cancelled = [task for task in descendants if task.get("status") == "cancelled"]
if cancelled:
return format_error_response(
"CANCELLED_DESCENDANTS",
f"Task has {len(cancelled)} cancelled descendant(s).",
{
"cancelled_count": len(cancelled),
"guidance": (
"Use force_with_cancelled=True with justification (CEO only) "
"to complete despite cancelled descendants."
),
},
)
# All descendants in terminal states (completed/cancelled) - allow completion
return None
except Exception:
return None
@@ -189,6 +176,7 @@ def _validate_completion_status(
f"Cannot complete task in '{current_status}' status. "
"Expected 'awaiting_pm_review' (dev work) or 'in_progress' (own task).",
{"current_status": current_status},
hint="roboco_kb_search('task status lifecycle')",
)
+14 -4
View File
@@ -31,6 +31,7 @@ def _validate_developer_role(agent_id: str) -> dict[str, Any] | None:
"Only developers can submit work for verification/QA. "
"PMs should use roboco_task_complete() directly.",
{"your_role": agent_role, "allowed_roles": ["developer"]},
hint="roboco_kb_search('developer workflow submit qa')",
)
return None
@@ -72,6 +73,7 @@ async def _validate_verification_submission(
"NO_WORK_EVIDENCE",
"No evidence of work found. Add commits with roboco_task_add_commit "
"or update progress with roboco_task_progress before verification.",
hint="roboco_kb_search('task progress commits')",
)
return task, None
@@ -152,9 +154,12 @@ async def _save_notes_and_submit(
return format_task_response(
qa_resp.json(),
"WAIT_FOR_QA",
"Task submitted for QA review.\n"
"You will be notified of the result.\n"
"In the meantime, call roboco_task_scan for other work.",
"Task submitted for QA review.\n\n"
"WHAT HAPPENS NEXT:\n"
"- QA will review your work and either PASS or FAIL\n"
"- If PASS: goes to documentation, then PM review\n"
"- If FAIL: returns to you with feedback for revision\n\n"
"Call roboco_task_scan for other work while waiting.",
)
@@ -188,6 +193,7 @@ def _validate_qa_role(agent_id: str, action: str) -> dict[str, Any] | None:
"NOT_QA",
f"Only QA agents can {action} tasks in QA review.",
{"your_role": agent_role},
hint="roboco_kb_search('qa workflow pass fail')",
)
return None
@@ -200,7 +206,11 @@ async def _check_self_review(
original_dev = extract_original_developer(quick_context)
agent_uuid = await resolve_agent_uuid_cached(agent_id, client)
if agent_uuid and not can_review_task(agent_uuid, original_dev):
return format_error_response("SELF_REVIEW", "Cannot review your own work.")
return format_error_response(
"SELF_REVIEW",
"Cannot review your own work.",
hint="roboco_kb_search('self review prevention')",
)
return None
+7 -2
View File
@@ -148,6 +148,11 @@ async def handle_task_progress(
if not progress_resp.ok:
return format_error_response("UPDATE_FAILED", "Failed to update progress")
return format_task_response(
progress_resp.json(), "CONTINUE", "Progress recorded. Keep working."
guidance = (
"Progress recorded. Keep working.\n\n"
"TIPS:\n"
"- Use roboco_journal_entry() to log decisions as you go\n"
"- Hit an error? Try roboco_search_error(pattern) for solutions\n"
"- Need context? Use roboco_kb_search(query) to find related code/docs"
)
return format_task_response(progress_resp.json(), "CONTINUE", guidance)
+3 -1
View File
@@ -62,6 +62,7 @@ def format_error_response(
code: str,
message: str,
details: dict[str, Any] | None = None,
hint: str | None = None,
) -> dict[str, Any]:
"""
Format a standardized error response for MCP tools.
@@ -72,13 +73,14 @@ def format_error_response(
code: Error code (e.g., "NOT_FOUND", "API_ERROR", "PERMISSION_DENIED")
message: Human-readable error message
details: Optional additional error details
hint: Optional RAG search suggestion for finding solutions
Returns:
Standardized error response dict with status="error"
"""
from roboco.api.schemas.common import error_response
return error_response(code, message, details)
return error_response(code, message, details, hint)
def format_success_response(
+8 -9
View File
@@ -68,7 +68,8 @@ AGENT_IMAGES: dict[str, str] = {
"fe-pm": "roboco-agent-pm",
"fe-doc": "roboco-agent-doc",
# UX/UI
"ux-dev": "roboco-agent-ux",
"ux-dev-1": "roboco-agent-ux",
"ux-dev-2": "roboco-agent-ux",
"ux-qa": "roboco-agent-ux", # Uses same as dev for now
"ux-pm": "roboco-agent-pm",
"ux-doc": "roboco-agent-doc",
@@ -734,7 +735,8 @@ class AgentOrchestrator:
"be-dev-2": "be-dev",
"fe-dev-1": "fe-dev",
"fe-dev-2": "fe-dev",
"ux-dev": "ux-dev",
"ux-dev-1": "ux-dev",
"ux-dev-2": "ux-dev",
"be-qa": "be-qa",
"fe-qa": "fe-qa",
"ux-qa": "ux-qa",
@@ -1102,10 +1104,7 @@ Start by:
# Build candidate list based on role
if role == "dev":
if prefix == "ux":
candidates = ["ux-dev"]
else:
candidates = [f"{prefix}-dev-1", f"{prefix}-dev-2"]
candidates = [f"{prefix}-dev-1", f"{prefix}-dev-2"]
elif role == "qa":
candidates = [f"{prefix}-qa"]
elif role == "doc":
@@ -1375,9 +1374,9 @@ You do NOT assign to developers directly - Cell PMs manage their teams.
- Backend work be-pm (who manages be-dev-1, be-dev-2)
- Frontend work fe-pm (who manages fe-dev-1, fe-dev-2)
- UX/UI work ux-pm (who manages ux-dev)
- UX/UI work ux-pm (who manages ux-dev-1, ux-dev-2)
🚨 NEVER assign to be-dev-1, fe-dev-1, ux-dev directly. ONLY to Cell PMs.
🚨 NEVER assign to be-dev-1, fe-dev-1, ux-dev-1, ux-dev-2 directly. ONLY to Cell PMs.
== WHEN TO WORK ON IT YOURSELF ==
@@ -1445,7 +1444,7 @@ Start now: roboco_task_get("{task_id}")
dev_map = {
"backend": ("be-dev-1", "be-dev-2"),
"frontend": ("fe-dev-1", "fe-dev-2"),
"ux_ui": ("ux-dev",),
"ux_ui": ("ux-dev-1", "ux-dev-2"),
}
devs = dev_map.get(team, ("be-dev-1",))
primary_dev = devs[0]
+16 -7
View File
@@ -118,10 +118,11 @@ AGENT_UUIDS = {
"fe-pm": "00000000-0000-0000-0002-000000000004",
"fe-doc": "00000000-0000-0000-0002-000000000005",
# UX/UI Cell
"ux-dev": "00000000-0000-0000-0003-000000000001",
"ux-qa": "00000000-0000-0000-0003-000000000002",
"ux-pm": "00000000-0000-0000-0003-000000000003",
"ux-doc": "00000000-0000-0000-0003-000000000004",
"ux-dev-1": "00000000-0000-0000-0003-000000000001",
"ux-dev-2": "00000000-0000-0000-0003-000000000002",
"ux-qa": "00000000-0000-0000-0003-000000000003",
"ux-pm": "00000000-0000-0000-0003-000000000004",
"ux-doc": "00000000-0000-0000-0003-000000000005",
# Board / Management
"main-pm": "00000000-0000-0000-0004-000000000001",
"product-owner": "00000000-0000-0000-0004-000000000002",
@@ -295,9 +296,17 @@ CHANNEL_MEMBERSHIPS = {
# Cell channels - cell members + CEO
"backend-cell": ["be-dev-1", "be-dev-2", "be-qa", "be-pm", "be-doc", "ceo"],
"frontend-cell": ["fe-dev-1", "fe-dev-2", "fe-qa", "fe-pm", "fe-doc", "ceo"],
"uxui-cell": ["ux-dev", "ux-qa", "ux-pm", "ux-doc", "ceo"],
"uxui-cell": ["ux-dev-1", "ux-dev-2", "ux-qa", "ux-pm", "ux-doc", "ceo"],
# Role channels + CEO
"dev-all": ["be-dev-1", "be-dev-2", "fe-dev-1", "fe-dev-2", "ux-dev", "ceo"],
"dev-all": [
"be-dev-1",
"be-dev-2",
"fe-dev-1",
"fe-dev-2",
"ux-dev-1",
"ux-dev-2",
"ceo",
],
"qa-all": ["be-qa", "fe-qa", "ux-qa", "ceo"],
"pm-all": ["be-pm", "fe-pm", "ux-pm", "main-pm", "ceo"],
"doc-all": ["be-doc", "fe-doc", "ux-doc", "ceo"],
@@ -408,7 +417,7 @@ Check `roboco_task_scan(team="frontend")` for pending frontend tasks.
"content": """Welcome to the UX/UI Cell channel!
**Team:**
- ux-dev: UX/UI Developer
- ux-dev-1, ux-dev-2: UX/UI Developers
- ux-qa: UX/UI QA
- ux-pm: UX/UI PM (me)
- ux-doc: UX/UI Documenter
+63 -4
View File
@@ -159,6 +159,21 @@ class BaseIndexPlugin(ABC):
},
}
def _build_piragi_config_no_embed(self) -> dict[str, Any]:
"""
Build piragi config with dummy embedding URL.
This prevents piragi from loading its own SentenceTransformer model
during initialization. We'll replace the embedder with our shared
instance immediately after creation.
"""
config = self._build_piragi_config()
# Set a dummy base_url to prevent local model loading
# EmbeddingGenerator checks: if base_url is not None, skip SentenceTransformer
config["embedding"]["base_url"] = "http://dummy-prevents-model-load"
config["embedding"]["api_key"] = "not-needed"
return config
async def initialize(self) -> None:
"""Initialize the index backend."""
if self._initialized:
@@ -176,20 +191,64 @@ class BaseIndexPlugin(ABC):
model=self.config.embedding_model,
)
# Create store with correct vector dimension for embedding model
# Piragi's factory defaults to 768 for PostgresStore, but we use
# all-MiniLM-L6-v2 which produces 384-dimensional embeddings
store = self._create_store_with_dimension()
# Use config with dummy embedding URL to prevent model loading
# Piragi's EmbeddingGenerator skips SentenceTransformer if base_url is set
self._ragi = AsyncRagi(
[],
persist_dir=self.config.persist_dir,
config=self._build_piragi_config(),
store=self.config.store_url,
config=self._build_piragi_config_no_embed(),
store=store,
)
# Replace AsyncRagi's embedder with shared instance
# This avoids loading the model 9 times (saves ~24s startup)
# Replace AsyncRagi's dummy embedder with shared instance
# This is the key optimization: one model load for all 9 plugins
self._ragi._sync.embedder = shared_embedder
self._initialized = True
logger.info(f"{self.index_type.value} index plugin initialized")
def _create_store_with_dimension(self) -> Any:
"""
Create vector store with correct dimension for embedding model.
Piragi's factory defaults to 768 for PostgresStore, but doesn't
infer dimension from the embedding model. This method fixes that
by creating PostgresStore with the correct dimension.
"""
from roboco.config import settings
store_url = self.config.store_url
if not store_url:
# Use default LanceStore (handles dimension correctly)
return None
# For PostgreSQL, create store with correct dimension
if store_url.startswith("postgres://") or store_url.startswith("postgresql://"):
from piragi.stores.postgres import PostgresStore
# Get dimension from settings (384 for all-MiniLM-L6-v2)
vector_dimension = settings.embedding_dimensions
logger.debug(
"Creating PostgresStore with correct dimension",
vector_dimension=vector_dimension,
embedding_model=self.config.embedding_model,
)
return PostgresStore(
connection_string=store_url,
table_name=f"chunks_{self.index_type.value}",
vector_dimension=vector_dimension,
)
# For other stores, let piragi handle it
return store_url
async def close(self) -> None:
"""Cleanup resources."""
self._ragi = None
+6 -6
View File
@@ -19,7 +19,7 @@ from uuid import UUID
import structlog
from roboco.models.optimal import IndexType, SearchResult
from roboco.models.optimal import IndexType, QueryContext, SearchResult
logger = structlog.get_logger()
@@ -364,7 +364,7 @@ class ProactiveKnowledgeService:
"list[SearchResult]",
await self._optimal_service.search(
query=query,
index_types=[IndexType.JOURNALS],
context=QueryContext(index_types=[IndexType.JOURNALS]),
top_k=top_k,
),
)
@@ -389,7 +389,7 @@ class ProactiveKnowledgeService:
"list[SearchResult]",
await self._optimal_service.search(
query=query,
index_types=[IndexType.CODE],
context=QueryContext(index_types=[IndexType.CODE]),
top_k=top_k,
),
)
@@ -414,7 +414,7 @@ class ProactiveKnowledgeService:
"list[SearchResult]",
await self._optimal_service.search(
query=query,
index_types=[IndexType.DECISIONS],
context=QueryContext(index_types=[IndexType.DECISIONS]),
top_k=top_k,
),
)
@@ -426,7 +426,7 @@ class ProactiveKnowledgeService:
return cast(
"list[SearchResult]",
await self._optimal_service.search_errors(
query=query,
error_message=query,
top_k=top_k,
),
)
@@ -455,7 +455,7 @@ class ProactiveKnowledgeService:
"list[SearchResult]",
await self._optimal_service.search(
query=query,
index_types=[IndexType.DECISIONS],
context=QueryContext(index_types=[IndexType.DECISIONS]),
top_k=top_k,
),
)
+32 -2
View File
@@ -353,11 +353,26 @@ class TaskService(BaseService):
return task
async def delete(self, task_id: UUID) -> bool:
"""Delete a task."""
"""Delete a task and all its descendants."""
task = await self.get(task_id)
if not task:
return False
# Delete all descendants first (children, grandchildren, etc.)
# Process in reverse order to delete leaves before parents
descendants = await self.get_all_descendants(task_id)
descendants.reverse() # Delete deepest children first
for descendant in descendants:
await self.session.delete(descendant)
if descendants:
self.log.info(
"Cascaded delete to descendants",
task_id=str(task_id),
deleted_count=len(descendants),
)
await self.session.delete(task)
await self.session.flush()
@@ -1100,11 +1115,26 @@ class TaskService(BaseService):
async def cancel(
self, task_id: UUID, agent_role: str = "cell_pm"
) -> TaskTable | None:
"""Cancel a task (PM only)."""
"""Cancel a task and all its descendants (PM only)."""
task = await self.get(task_id)
if not task:
return None
# Cancel all descendants first (children, grandchildren, etc.)
descendants = await self.get_all_descendants(task_id)
cancelled_count = 0
for descendant in descendants:
if descendant.status != TaskStatus.CANCELLED:
descendant.status = TaskStatus.CANCELLED
cancelled_count += 1
if cancelled_count > 0:
self.log.info(
"Cascaded cancel to descendants",
task_id=str(task_id),
cancelled_count=cancelled_count,
)
# Validate transition with PM role requirement
self._validate_and_set_status(task, TaskStatus.CANCELLED, agent_role)
await self.session.flush()
+2 -2
View File
@@ -32,7 +32,7 @@ CEO (You)
| `fe-qa` | QA | Frontend |
| `fe-doc` | Documenter | Frontend |
| `ux-pm` | Cell PM | UX/UI |
| `ux-dev` | Developer | UX/UI |
| `ux-dev-1`, `ux-dev-2` | Developers | UX/UI |
| `ux-qa` | QA | UX/UI |
| `ux-doc` | Documenter | UX/UI |
| `product-owner` | Product Owner | Board |
@@ -53,7 +53,7 @@ uv run python -m roboco.cli --spawn \
main-pm \
be-pm be-dev-1 be-dev-2 be-qa be-doc \
fe-pm fe-dev-1 fe-dev-2 fe-qa fe-doc \
ux-pm ux-dev ux-qa ux-doc \
ux-pm ux-dev-1 ux-dev-2 ux-qa ux-doc \
product-owner head-marketing auditor
```