aios-core
Version:
Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework
541 lines (412 loc) • 13.5 kB
Markdown
tools:
- clickup # Required for ClickUp integration
checklists:
- po-master-checklist.md
# pull-story-from-clickup
**Purpose:** Pull complete story updates from ClickUp to local file, including task completions, description changes, and status updates. This is the **reverse direction** of sync-story-to-clickup.
**When to Use:**
- After making changes directly in ClickUp UI (marking checkboxes, updating description)
- When you need to pull latest state from ClickUp to continue work locally
- After collaborators update the ClickUp task
- To resolve sync conflicts (ClickUp is the source of truth)
**Important:** This overwrites local changes with ClickUp data. Use carefully if you have uncommitted local edits.
## Execution Modes
**Choose your execution mode:**
### 1. YOLO Mode - Fast, Autonomous (0-1 prompts)
- Autonomous decision making with logging
- Minimal user interaction
- **Best for:** Simple, deterministic tasks
### 2. Interactive Mode - Balanced, Educational (5-10 prompts) **[DEFAULT]**
- Explicit decision checkpoints
- Educational explanations
- **Best for:** Learning, complex decisions
### 3. Pre-Flight Planning - Comprehensive Upfront Planning
- Task analysis phase (identify all ambiguities)
- Zero ambiguity execution
- **Best for:** Ambiguous requirements, critical work
**Parameter:** `mode` (optional, default: `interactive`)
## Task Definition (AIOS Task Format V1.0)
```yaml
task: poPullStoryFromClickup()
responsável: Pax (Balancer)
responsavel_type: Agente
atomic_layer: Organism
**Entrada:**
- campo: task
tipo: string
origem: User Input
obrigatório: true
validação: Must be registered task
- campo: parameters
tipo: object
origem: User Input
obrigatório: false
validação: Valid task parameters
- campo: mode
tipo: string
origem: User Input
obrigatório: false
validação: yolo|interactive|pre-flight
**Saída:**
- campo: execution_result
tipo: object
destino: Memory
persistido: false
- campo: logs
tipo: array
destino: File (.ai/logs/*)
persistido: true
- campo: state
tipo: object
destino: State management
persistido: true
```
## Pre-Conditions
**Purpose:** Validate prerequisites BEFORE task execution (blocking)
**Checklist:**
```yaml
pre-conditions:
- [ ] Task is registered; required parameters provided; dependencies met
tipo: pre-condition
blocker: true
validação: |
Check task is registered; required parameters provided; dependencies met
error_message: "Pre-condition failed: Task is registered; required parameters provided; dependencies met"
```
## Post-Conditions
**Purpose:** Validate execution success AFTER task completes
**Checklist:**
```yaml
post-conditions:
- [ ] Task completed; exit code 0; expected outputs created
tipo: post-condition
blocker: true
validação: |
Verify task completed; exit code 0; expected outputs created
error_message: "Post-condition failed: Task completed; exit code 0; expected outputs created"
```
## Acceptance Criteria
**Purpose:** Definitive pass/fail criteria for task completion
**Checklist:**
```yaml
acceptance-criteria:
- [ ] Task completed as expected; side effects documented
tipo: acceptance-criterion
blocker: true
validação: |
Assert task completed as expected; side effects documented
error_message: "Acceptance criterion not met: Task completed as expected; side effects documented"
```
## Tools
**External/shared resources used by this task:**
- **Tool:** task-runner
- **Purpose:** Task execution and orchestration
- **Source:** .aios-core/core/task-runner.js
- **Tool:** logger
- **Purpose:** Execution logging and error tracking
- **Source:** .aios-core/utils/logger.js
## Scripts
**Agent-specific code for this task:**
- **Script:** execute-task.js
- **Purpose:** Generic task execution wrapper
- **Language:** JavaScript
- **Location:** .aios-core/scripts/execute-task.js
## Error Handling
**Strategy:** retry
**Common Errors:**
1. **Error:** Task Not Found
- **Cause:** Specified task not registered in system
- **Resolution:** Verify task name and registration
- **Recovery:** List available tasks, suggest similar
2. **Error:** Invalid Parameters
- **Cause:** Task parameters do not match expected schema
- **Resolution:** Validate parameters against task definition
- **Recovery:** Provide parameter template, reject execution
3. **Error:** Execution Timeout
- **Cause:** Task exceeds maximum execution time
- **Resolution:** Optimize task or increase timeout
- **Recovery:** Kill task, cleanup resources, log state
## Performance
**Expected Metrics:**
```yaml
duration_expected: 5-15 min (estimated)
cost_estimated: $0.003-0.010
token_usage: ~3,000-10,000 tokens
```
**Optimization Notes:**
- Break into smaller workflows; implement checkpointing; use async processing where possible
## Metadata
```yaml
story: N/A
version: 1.0.0
dependencies:
- N/A
tags:
- product-management
- planning
updated_at: 2025-11-17
```
## Task Inputs
```yaml
required:
- story_id: '{epic}.{story}' # e.g., "99.2" or "5.2.2"
optional:
- force: false # If true, pull even if last_sync indicates local is newer
```
## Prerequisites
- Story file must exist in `docs/stories/`
- Story must have ClickUp metadata in frontmatter (clickup.task_id)
- ClickUp MCP tool must be available and authenticated
## Task Execution Steps
### Step 1: Locate Story File
- Find story file in `docs/stories/` matching story_id pattern
- Expected format: `{epic}.{story}.*.md`
- If multiple files found, show list and ask user to clarify
- If no file found, ERROR and exit
### Step 2: Get ClickUp Task Data
```javascript
const clickupTool = await getClickUpTool();
// Get complete task data including description
const task = await clickupTool.getTask({
taskId: storyData.frontmatter.clickup.task_id
});
```
**What to extract from ClickUp task:**
- Task description (contains full story markdown)
- Story-status custom field
- Task native status
- Tags
- Custom fields (epic_number, story_number, story_file_path)
### Step 3: Parse ClickUp Description
The ClickUp task description contains the **complete story markdown**. We need to:
1. Extract the markdown from `task.description`
2. Parse sections:
- Story Statement
- Context
- Acceptance Criteria (with checkboxes)
- Tasks/Subtasks (with checkboxes)
- Dev Notes
- Testing
- File List
- QA Results
- Notes
- Change Log
3. **Critical:** Preserve checkbox states from ClickUp
- `- [x] Task` = completed
- `- [ ] Task` = pending
### Step 4: Merge with Local Frontmatter
**DO NOT overwrite entire file** - preserve frontmatter structure:
```javascript
const localFrontmatter = storyData.frontmatter;
const clickupFrontmatter = {
version: localFrontmatter.version,
story_id: localFrontmatter.story_id,
epic_id: localFrontmatter.epic_id,
title: task.name,
status: mapStatusFromClickUp(task.custom_fields.find(f => f.name === 'story-status').value),
created: localFrontmatter.created,
updated: new Date().toISOString().split('T')[0], // Today's date
clickup: {
task_id: task.id,
epic_task_id: task.parent,
list: task.list.name,
list_id: task.list.id,
url: task.url,
last_sync: new Date().toISOString(),
custom_fields: {
epic_number: task.custom_fields.find(f => f.name === 'epic-number')?.value || localFrontmatter.clickup.custom_fields.epic_number,
story_number: task.custom_fields.find(f => f.name === 'story-number')?.value || localFrontmatter.clickup.custom_fields.story_number,
story_file_path: task.custom_fields.find(f => f.name === 'story-file-path')?.value || localFrontmatter.clickup.custom_fields.story_file_path,
'story-status': task.custom_fields.find(f => f.name === 'story-status')?.value
}
},
tags: task.tags.map(t => t.name)
};
```
### Step 5: Reconstruct Story File
Build complete story markdown:
```markdown
# Story {story_id}: {title}
```yaml
{frontmatter}
```
{story body from ClickUp description}
```
**Important:** Use the ClickUp description as the **source of truth** for the story body.
### Step 6: Write Updated Story File
```javascript
const { saveStoryFile } = require('../../common/scripts/story-manager');
// Save with skipSync=true to avoid circular sync
await saveStoryFile(storyFilePath, newContent, true);
```
**Why skipSync=true?**
- We just pulled from ClickUp, so we don't want to immediately push back
- Prevents infinite sync loops
### Step 7: Display Sync Summary
```markdown
✅ Story {story_id} pulled from ClickUp
**Task ID:** {task_id}
**Task URL:** {url}
**Last Sync:** {timestamp}
**Changes Pulled:**
- Status: {old_status} → {new_status} (if changed)
- Tasks completed: {count of checkboxes changed from [ ] to [x]}
- Tasks reopened: {count of checkboxes changed from [x] to [ ]}
- Description updated: {yes/no}
- Tags updated: {changes}
**Local File Updated:**
- Frontmatter: ✓
- Story Body: ✓
- Checkbox States: ✓
- Last Sync Timestamp: ✓
```
## Error Handling
**Error: Story file not found**
```
❌ Story file not found for ID: {story_id}
Please check:
- Story ID format correct? (e.g., "99.2" not "Story 99.2")
- Story file exists in docs/stories/?
- File naming follows pattern: {epic}.{story}.*.md
```
**Error: No ClickUp metadata**
```
❌ Story has no ClickUp integration
This story was not created via ClickUp workflow and has no task_id.
Cannot pull from ClickUp without task_id in frontmatter.
```
**Error: ClickUp task not found**
```
❌ ClickUp task not found: {task_id}
Possible reasons:
- Task was deleted from ClickUp
- Task ID is incorrect in frontmatter
- You don't have access to this task
- ClickUp API authentication failed
Verify task exists: {task_url}
```
**Error: Description empty or malformed**
```
❌ ClickUp task description is empty or malformed
The task description should contain the full story markdown.
This may indicate:
- Task was created manually in ClickUp (not via story-manager)
- Description was accidentally cleared
- Task needs to be synced from local first
Recommendation:
1. Run: *sync-story {story_id}
2. Then try pulling again
```
## Usage Examples
### Basic Pull
```
*pull-story 99.2
```
### Force Pull (even if local is newer)
```
*pull-story 5.2.2 --force
```
### After ClickUp Updates
```
# Scenario: You marked checkboxes in ClickUp UI
1. Run: *pull-story {story_id}
2. Review changes shown in summary
3. Local file now matches ClickUp
4. Continue working locally
```
## Integration Notes
**For PO Agent:**
- Add to po.md commands: `pull-story {story}`: Pull story updates from ClickUp
- Use after collaborators update ClickUp tasks
- Use before starting validation if task was modified in ClickUp
**For Dev Agent:**
- Add to dev.md commands: `pull-story {story}`: Pull story updates from ClickUp
- Use at start of work session to get latest state
- Use after QA or PO updates task in ClickUp
**For QA Agent:**
- Add to qa.md commands: `pull-story {story}`: Pull story updates from ClickUp
- Use before starting review to get latest state
- Use after Dev marks tasks complete in ClickUp
**Best Practice:**
- Pull at the **start** of work sessions
- Push (*sync-story) at the **end** of work sessions
- ClickUp is the source of truth for collaborative updates
- Local file is the source of truth for agent work
## Workflow Examples
### Collaborative Workflow
```
1. PO updates story in ClickUp UI (adds acceptance criteria)
2. Dev pulls story: *pull-story 5.2.2
3. Dev implements locally, marks tasks done
4. Dev pushes to ClickUp: *sync-story 5.2.2
5. QA pulls latest: *pull-story 5.2.2
6. QA reviews and updates locally
7. QA pushes results: *sync-story 5.2.2
```
### Conflict Resolution
```
# If local and ClickUp diverged:
Option 1: ClickUp wins (recommended for collaborative work)
*pull-story 5.2.2 --force
Option 2: Local wins (when you have important uncommitted work)
*sync-story 5.2.2 --force
Option 3: Manual merge (complex changes)
1. Backup local file
2. Pull from ClickUp
3. Compare with backup
4. Manually merge important changes
5. Push back to ClickUp
```
## Technical Implementation
**Dependencies:**
- `common/scripts/story-manager.js` - saveStoryFile, parseStoryFile
- `common/scripts/status-mapper.js` - mapStatusFromClickUp
- ClickUp MCP tool (via global.mcp__clickup__* or tool-resolver)
**Process Flow:**
```
Task invoked
↓
Read local story file
↓
Extract task_id from frontmatter
↓
Fetch complete task from ClickUp (via MCP tool)
↓
Parse ClickUp description (story markdown)
↓
Merge frontmatter (preserve local structure, update from ClickUp)
↓
Reconstruct complete story file
↓
├─ Frontmatter (merged)
├─ Story body (from ClickUp description)
└─ Checkbox states (from ClickUp description)
↓
Write to local file (skipSync=true)
↓
Display sync summary
```
## Testing This Task
**Manual Test:**
1. Mark checkboxes in ClickUp UI for Story 99.2
2. Run: `*pull-story 99.2`
3. Verify:
- Checkboxes updated in local file
- last_sync timestamp updated
- Status changes reflected
- Summary shows correct change count
**Automated Test:** `tests/tasks/pull-story-from-clickup.test.js`
*Task created to provide reverse synchronization from ClickUp to local story files*