Skill: shylee1/openclaw-skills (version 1.0.0)

# Agent Team Kit — SKILL.md *A framework for self-sustaining AI agent teams.* --- ## What This Is A complete team process kit for OpenClaw agents that enables: - **Self-service work queues** — Agents pick up tasks without human bottlenecks - **Clear role ownership** — Everyone knows who does what - **Continuous discovery** — Work flows in automatically - **Proactive operation** — The team runs itself via heartbeat --- ## Quick Start ### 1. Copy the Process Files ```bash # From your workspace root cp -r skills/agent-team-kit/templates/process ./process ``` This creates: - `process/INTAKE.md` — The 5-phase work loop - `process/ROLES.md` — Role definitions - `process/OPPORTUNITIES.md` — Raw ideas/discoveries - `process/BACKLOG.md` — Triaged work queue - `process/STATUS.md` — Who's working on what ### 2. Add Heartbeat Config Merge `templates/HEARTBEAT.md` into your existing `HEARTBEAT.md`: ```bash cat skills/agent-team-kit/templates/HEARTBEAT.md >> HEARTBEAT.md ``` Or copy it directly if you don't have one yet. ### 3. Customize Roles Edit `process/ROLES.md` to match your team: - Rename roles to fit your domain - Add/remove specialized execution roles - Update the human lead section with your name --- ## The Intake Loop ``` DISCOVER → TRIAGE → READY → EXECUTE → FEEDBACK ↑ ↓ └──────────────────────────────────────┘ ``` 1. **Discover** — Find opportunities (Scout role) 2. **Triage** — Decide what's ready (Rhythm role) 3. **Ready** — Self-service queue (any agent) 4. **Execute** — Do the work (assigned agent) 5. **Feedback** — Learn and spawn new ideas (completing agent) --- ## Core Roles | Role | Mission | Owns | |------|---------|------| | **Scout 🔍** | Find opportunities | `OPPORTUNITIES.md`, discovery | | **Rhythm 🥁** | Keep work flowing | `BACKLOG.md`, triage | | **Harmony 🤝** | Keep team healthy | Unblocking, retros | | **[Human]** | Strategic direction | Hard calls, spawning | **Execution roles** (spawn as needed): - Link 🔗 — Builder - Pixel 🎨 — Designer - Sage 🦉 — Architect - Echo 📢 — Voice - Spark ✨ — Creative --- ## Key Principles ### Self-Service If it's in Ready, any agent can pick it up. No approval needed. ### Clear Ownership Every phase has ONE owner. No ambiguity. ### Always Log Ideas, discoveries, completions — if you don't log it, it didn't happen. ### Spawn, Don't Solo Main agent coordinates. Sub-agents execute. Don't do everything yourself. --- ## File Structure ``` process/ ├── INTAKE.md # How the loop works (reference) ├── ROLES.md # Who does what ├── OPPORTUNITIES.md # Raw discoveries (anyone adds) ├── BACKLOG.md # Triaged work (Rhythm maintains) └── STATUS.md # Current activity (self-updated) HEARTBEAT.md # Proactive check triggers ``` --- ## Heartbeat Integration Add to your heartbeat checks: ```markdown ### Team Health (run hourly) - [ ] OPPORTUNITIES.md stale? → Spawn Scout - [ ] Ready queue empty? → Alert Rhythm - [ ] Active work stuck >2h? → Nudge owner - [ ] Any unresolved blockers? → Harmony ``` The heartbeat keeps the loop spinning even when the human isn't watching. --- ## Customization ### Adding a New Role 1. Define in `ROLES.md`: - Mission (one sentence) - Owns (what they're responsible for) - Cadence (how often they work) - Outputs (what they produce) 2. Update the ownership matrix 3. Add spawn criteria in `INTAKE.md` if needed ### Changing the Loop The 5-phase loop is flexible. Adapt it: - Add validation gates between phases - Split EXECUTE into parallel tracks - Add approval checkpoints (if your domain requires it) --- ## Anti-Patterns ❌ Human manually adds every task → Use triage role instead ❌ Waiting for permission to pick up work → Ready = fair game ❌ One agent does everything → Spawn specialists ❌ Ideas stay in heads → Log to OPPORTUNITIES.md ❌ Heartbeat just returns OK → Actually check the loop --- ## Metrics (Optional) Track team health: - **Cycle time** — OPPORTUNITIES → DONE - **Queue depth** — Items in Ready (healthy: 5-15) - **Stale items** — Days since last triage - **Spawn rate** — Sub-agents created per day --- *The system runs itself. Your job is to trust it.*

path: desktop-control-1.0.0/__init__.py
content: """
Desktop Control - Advanced Mouse, Keyboard, and Screen Automation
The best ever possible responsive desktop control for OpenClaw
"""

import pyautogui
import time
import sys
from typing import Tuple, Optional, List, Union
from pathlib import Path
import logging

# Configure PyAutoGUI
pyautogui.MINIMUM_DURATION = 0  # Allow instant movements
pyautogui.MINIMUM_SLEEP = 0     # No forced delays
pyautogui.PAUSE = 0             # No pause between function calls

# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class DesktopController:
    """
    Advanced desktop automation controller with mouse, keyboard, and screen operations.
    Designed for maximum responsiveness and reliability.
    """
    
    def __init__(self, failsafe: bool = True, require_approval: bool = False):
        """
        Initialize desktop controller.
        
        Args:
            failsafe: Enable failsafe (move mouse to corner to abort)
            require_approval: Require user confirmation for actions
        """
        self.failsafe = failsafe
        self.require_approval = require_approval
        pyautogui.FAILSAFE = failsafe
        
        # Get screen info
        self.screen_width, self.screen_height = pyautogui.size()
        logger.info(f"Desktop Controller initialized. Screen: {self.screen_width}x{self.screen_height}")
        logger.info(f"Failsafe: {failsafe}, Require Approval: {require_approval}")
    
    # ========== MOUSE OPERATIONS ==========
    
    def move_mouse(self, x: int, y: int, duration: float = 0, smooth: bool = True) -> None:
        """
        Move mouse to absolute screen coordinates.
        
        Args:
            x: X coordinate (pixels from left)
            y: Y coordinate (pixels from top)
            duration: Movement time in seconds (0 = instant)
            smooth: Use smooth movement (cubic bezier)
        """
        if self._check_approval(f"move mouse to ({x}, {y})"):
            if smooth and duration > 0:
                pyautogui.moveTo(x, y, duration=duration, tween=pyautogui.easeInOutQuad)
            else:
                pyautogui.moveTo(x, y, duration=duration)
            logger.debug(f"Moved mouse to ({x}, {y}) in {duration}s")
    
    def move_relative(self, x_offset: int, y_offset: int, duration: float = 0) -> None:
        """
        Move mouse relative to current position.
        
        Args:
            x_offset: Pixels to move horizontally (+ = right, - = left)
            y_offset: Pixels to move vertically (+ = down, - = up)
            duration: Movement time in seconds
        """
        if self._check_approval(f"move mouse relative ({x_offset}, {y_offset})"):
            pyautogui.move(x_offset, y_offset, duration=duration)
            logger.debug(f"Moved mouse relative ({x_offset}, {y_offset})")
    
    def click(self, x: Optional[int] = None, y: Optional[int] = None, 
              button: str = 'left', clicks: int = 1, interval: float = 0.1) -> None:
        """
        Perform mouse click.
        
        Args:
            x, y: Coordinates to click (None = current position)
            button: 'left', 'right', 'middle'
            clicks: Number of clicks (1 = single, 2 = double, etc.)
            interval: Delay between multiple clicks
        """
        position_str = f"at ({x}, {y})" if x is not None else "at current position"
        if self._check_approval(f"{button} click {position_str}"):
            pyautogui.click(x=x, y=y, clicks=clicks, interval=interval, button=button)
            logger.info(f"{button.capitalize()} click {position_str} (x{clicks})")
    
    def double_click(self, x: Optional[int] = None, y: Optional[int] = None) -> None:
        """Convenience method for double-click."""
        self.click(x, y, clicks=2)
    
    def right_click(self, x: Optional[int] = None, y: Optional[int] = None) -> None:
        """Convenience method for right-click."""
        self.click(x, y, button='right')
    
    def middle_click(self, x: Optional[int] = None, y: Optional[int] = None) -> None:
        """Convenience method for middle-click."""
        self.click(x, y, button='middle')
    
    def drag(self, start_x: int, start_y: int, end_x: int, end_y: int,
             duration: float = 0.5, button: str = 'left') -> None:
        """
        Drag and drop operation.
        
        Args:
            start_x, start_y: Starting coordinates
            end_x, end_y: Ending coordinates
            duration: Drag duration in seconds
            button: Mouse button to use ('left', 'right', 'middle')
        """
        if self._check_approval(f"drag from ({start_x}, {start_y}) to ({end_x}, {end_y})"):
            pyautogui.moveTo(start_x, start_y)
            time.sleep(0.05)  # Small delay to ensure position
            pyautogui.drag(end_x - start_x, end_y - start_y, duration=duration, button=button)
            logger.info(f"Dragged from ({start_x}, {start_y}) to ({end_x}, {end_y})")
    
    def scroll(self, clicks: int, direction: str = 'vertical', 
               x: Optional[int] = None, y: Optional[int] = None) -> None:
        """
        Scroll mouse wheel.
        
        Args:
            clicks: Scroll amount (+ = up/left, - = down/right)
            direction: 'vertical' or 'horizontal'
            x, y: Position to scroll at (None = current position)
        """
        if x is not None and y is not None:
            pyautogui.moveTo(x, y)
        
        if direction == 'vertical':
            pyautogui.scroll(clicks)
        else:
            pyautogui.hscroll(clicks)
        logger.debug(f"Scrolled {direction} {clicks} clicks")
    
    def get_mouse_position(self) -> Tuple[int, int]:
        """
        Get current mouse coordinates.
        
        Returns:
            (x, y) tuple
        """
        pos = pyautogui.position()
        return (pos.x, pos.y)
    
    # ========== KEYBOARD OPERATIONS ==========
    
    def type_text(self, text: str, interval: float = 0, wpm: Optional[int] = None) -> None:
        """
        Type text with configurable speed.
        
        Args:
            text: Text to type
            interval: Delay between keystrokes (0 = instant)
            wpm: Words per minute (overrides interval, typical human: 40-80 WPM)
        """
        if wpm is not None:
            # Convert WPM to interval (assuming avg 5 chars per word)
            chars_per_second = (wpm * 5) / 60
            interval = 1.0 / chars_per_second
        
        if self._check_approval(f"type text: '{text[:50]}...'"):
            pyautogui.write(text, interval=interval)
            logger.info(f"Typed text: '{text[:50]}{'...' if len(text) > 50 else ''}' (interval={interval:.3f}s)")
    
    def press(self, key: str, presses: int = 1, interval: float = 0.1) -> None:
        """
        Press and release a key.
        
        Args:
            key: Key name (e.g., 'enter', 'space', 'a', 'f1')
            presses: Number of times to press
            interval: Delay between presses
        """
        if self._check_approval(f"press '{key}' {presses}x"):
            pyautogui.press(key, presses=presses, interval=interval)
            logger.info(f"Pressed '{key}' {presses}x")
    
    def hotkey(self, *keys, interval: float = 0.05) -> None:
        """
        Execute keyboard shortcut (e.g., Ctrl+C, Alt+Tab).
        
        Args:
            *keys: Keys to press together (e.g., 'ctrl', 'c')
            interval: Delay between key presses
        """
        keys_str = '+'.join(keys)
        if self._check_approval(f"hotkey: {keys_str}"):
            pyautogui.hotkey(*keys, interval=interval)
            logger.info(f"Executed hotkey: {keys_str}")
    
    def key_down(self, key: str) -> None:
        """Press and hold a key without releasing."""
        pyautogui.keyDown(key)
        logger.debug(f"Key down: '{key}'")
    
    def key_up(self, key: str) -> None:
        """Release a held key."""
        pyautogui.keyUp(key)
        logger.debug(f"Key up: '{key}'")
    
    # ========== SCREEN OPERATIONS ==========
    
    def screenshot(self, region: Optional[Tuple[int, int, int, int]] = None,
                   filename: Optional[str] = None):
        """
        Capture screen or region.
        
        Args:
            region: (left, top, width, height) for partial capture
            filename: Path to save image (None = return PIL Image)
            
        Returns:
            PIL Image object (if filename is None)
        """
        img = pyautogui.screenshot(region=region)
        
        if filename:
            img.save(filename)
            logger.info(f"Screenshot saved to: {filename}")
        else:
            logger.debug(f"Screenshot captured (region={region})")
            return img
    
    def get_pixel_color(self, x: int, y: int) -> Tuple[int, int, int]:
        """
        Get RGB color of pixel at coordinates.
        
        Args:
            x, y: Screen coordinates
            
        Returns:
            (r, g, b) tuple
        """
        color = pyautogui.pixel(x, y)
        return color
    
    def find_on_screen(self, image_path: str, confidence: float = 0.8,
                       region: Optional[Tuple[int, int, int, int]] = None):
        """
        Find image on screen using template matching.
        Requires OpenCV (opencv-python).
        
        Args:
            image_path: Path to template image
            confidence: Match threshold 0-1 (0.8 = 80% match)
            region: Search region (left, top, width, height)
            
        Returns:
            (x, y, width, height) of match, or None if not found
        """
        try:
            location = pyautogui.locateOnScreen(image_path, confidence=confidence, region=region)
            if location:
                logger.info(f"Found '{image_path}' at {location}")
                return location
            else:
                logger.debug(f"'{image_path}' not found on screen")
                return None
        except Exception as e:
            logger.error(f"Error finding image: {e}")
            return None
    
    def get_screen_size(self) -> Tuple[int, int]:
        """
        Get screen resolution.
        
        Returns:
            (width, height) tuple
        """
        return (self.screen_width, self.screen_height)
    
    # ========== WINDOW OPERATIONS ==========
    
    def get_all_windows(self) -> List[str]:
        """
        Get list of all open window titles.
        
        Returns:
            List of window title strings
        """
        try:
            import pygetwindow as gw
            windows = gw.getAllTitles()
            # Filter out empty titles
            windows = [w for w in windows if w.strip()]
            return windows
        except ImportError:
            logger.error("pygetwindow not installed. Run: pip install pygetwindow")
            return []
        except Exception as e:
            logger.error(f"Error getting windows: {e}")
            return []
    
    def activate_window(self, title_substring: str) -> bool:
        """
        Bring window to front by title (partial match).
        
        Args:
            title_substring: Part of window title to match
            
        Returns:
            True if window was activated, False otherwise
        """
        try:
            import pygetwindow as gw
            windows = gw.getWindowsWithTitle(title_substring)
            if windows:
                windows[0].activate()
                logger.info(f"Activated window: '{windows[0].title}'")
                return True
            else:
                logger.warning(f"No window found with title containing: '{title_substring}'")
                return False
        except ImportError:
            logger.error("pygetwindow not installed")
            return False
        except Exception as e:
            logger.error(f"Error activating window: {e}")
            return False
    
    def get_active_window(self) -> Optional[str]:
        """
        Get title of currently focused window.
        
        Returns:
            Window title string, or None if error
        """
        try:
            import pygetwindow as gw
            active = gw.getActiveWindow()
            return active.title if active else None
        except ImportError:
            logger.error("pygetwindow not installed")
            return None
        except Exception as e:
            logger.error(f"Error getting active window: {e}")
            return None
    
    # ========== CLIPBOARD OPERATIONS ==========
    
    def copy_to_clipboard(self, text: str) -> None:
        """
        Copy text to clipboard.
        
        Args:
            text: Text to copy
        """
        try:
            import pyperclip
            pyperclip.copy(text)
            logger.info(f"Copied to clipboard: '{text[:50]}...'")
        except ImportError:
            logger.error("pyperclip not installed. Run: pip install pyperclip")
        except Exception as e:
            logger.error(f"Error copying to clipboard: {e}")
    
    def get_from_clipboard(self) -> Optional[str]:
        """
        Get text from clipboard.
        
        Returns:
            Clipboard text, or None if error
        """
        try:
            import pyperclip
            text = pyperclip.paste()
            logger.debug(f"Got from clipboard: '{text[:50]}...'")
            return text
        except ImportError:
            logger.error("pyperclip not installed. Run: pip install pyperclip")
            return None
        except Exception as e:
            logger.error(f"Error getting clipboard: {e}")
            return None
    
    # ========== UTILITY METHODS ==========
    
    def pause(self, seconds: float) -> None:
        """
        Pause automation for specified duration.
        
        Args:
            seconds: Time to pause
        """
        logger.info(f"Pausing for {seconds}s...")
        time.sleep(seconds)
    
    def is_safe(self) -> bool:
        """
        Check if it's safe to continue automation.
        Returns False if mouse is in a corner (failsafe position).
        
        Returns:
            True if safe to continue
        """
        if not self.failsafe:
            return True
        
        x, y = self.get_mouse_position()
        corner_tolerance = 5
        
        # Check corners
        corners = [
            (0, 0),  # Top-left
            (self.screen_width - 1, 0),  # Top-right
            (0, self.screen_height - 1),  # Bottom-left
            (self.screen_width - 1, self.screen_height - 1)  # Bottom-right
        ]
        
        for cx, cy in corners:
            if abs(x - cx) <= corner_tolerance and abs(y - cy) <= corner_tolerance:
                logger.warning(f"Mouse in corner ({x}, {y}) - FAILSAFE TRIGGERED")
                return False
        
        return True
    
    def _check_approval(self, action: str) -> bool:
        """
        Check if user approves action (if approval mode is enabled).
        
        Args:
            action: Description of action
            
        Returns:
            True if approved (or approval not required)
        """
        if not self.require_approval:
            return True
        
        response = input(f"Allow: {action}? [y/n]: ").strip().lower()
        approved = response in ['y', 'yes']
        
        if not approved:
            logger.warning(f"Action declined: {action}")
        
        return approved
    
    # ========== CONVENIENCE METHODS ==========
    
    def alert(self, text: str = '', title: str = 'Alert', button: str = 'OK') -> None:
        """Show alert dialog box."""
        pyautogui.alert(text=text, title=title, button=button)
    
    def confirm(self, text: str = '', title: str = 'Confirm', buttons: List[str] = None) -> str:
        """Show confirmation dialog with buttons."""
        if buttons is None:
            buttons = ['OK', 'Cancel']
        return pyautogui.confirm(text=text, title=title, buttons=buttons)
    
    def prompt(self, text: str = '', title: str = 'Input', default: str = '') -> Optional[str]:
        """Show input prompt dialog."""
        return pyautogui.prompt(text=text, title=title, default=default)


# ========== QUICK ACCESS FUNCTIONS ==========

# Global controller instance for quick access
_controller = None

def get_controller(**kwargs) -> DesktopController:
    """Get or create global controller instance."""
    global _controller
    if _controller is None:
        _controller = DesktopController(**kwargs)
    return _controller


# Convenience function exports
def move_mouse(x: int, y: int, duration: float = 0) -> None:
    """Quick mouse move."""
    get_controller().move_mouse(x, y, duration)

def click(x: Optional[int] = None, y: Optional[int] = None, button: str = 'left') -> None:
    """Quick click."""
    get_controller().click(x, y, button=button)

def type_text(text: str, wpm: Optional[int] = None) -> None:
    """Quick text typing."""
    get_controller().type_text(text, wpm=wpm)

def hotkey(*keys) -> None:
    """Quick hotkey."""
    get_controller().hotkey(*keys)

def screenshot(filename: Optional[str] = None):
    """Quick screenshot."""
    return get_controller().screenshot(filename=filename)


# ========== DEMONSTRATION ==========

if __name__ == "__main__":
    print("🖱️  Desktop Control Skill - Test Mode")
    print("=" * 50)
    
    # Initialize controller
    dc = DesktopController(failsafe=True)
    
    # Display info
    print(f"\n📺 Screen Size: {dc.get_screen_size()}")
    print(f"🖱️  Current Mouse Position: {dc.get_mouse_position()}")
    
    # Test window operations
    print(f"\n🪟 Active Window: {dc.get_active_window()}")
    
    windows = dc.get_all_windows()
    print(f"\n📋 Open Windows ({len(windows)}):")
    for i, title in enumerate(windows[:10], 1):  # Show first 10
        print(f"  {i}. {title}")
    
    print("\n✅ Desktop Control ready!")
    print("⚠️  Move mouse to any corner to trigger failsafe")
    
    # Keep running to allow testing
    print("\nController is ready. Import this module to use it in your OpenClaw skills!")


path: desktop-control-1.0.0/AI_AGENT_GUIDE.md
content: # AI Desktop Agent - Cognitive Automation Guide

## 🤖 What Is This?

The **AI Desktop Agent** is an intelligent layer on top of the basic desktop control that **understands** what you want and figures out how to do it autonomously.

Unlike basic automation that requires exact instructions, the AI Agent:
- **Understands natural language** ("Draw a cat in Paint")
- **Plans the steps** automatically
- **Executes autonomously** 
- **Adapts** based on what it sees

---

## 🎯 What Can It Do?

### ✅ Autonomous Drawing
```python
from skills.desktop_control.ai_agent import AIDesktopAgent

agent = AIDesktopAgent()

# Just describe what you want!
agent.execute_task("Draw a circle in Paint")
agent.execute_task("Draw a star in MS Paint")
agent.execute_task("Draw a house with a sun")
```

**What it does:**
1. Opens MS Paint
2. Selects pencil tool
3. Figures out how to draw the requested shape
4. Draws it autonomously
5. Takes a screenshot of the result

### ✅ Autonomous Text Entry
```python
# It figures out where to type
agent.execute_task("Type 'Hello World' in Notepad")
agent.execute_task("Write an email saying thank you")
```

**What it does:**
1. Opens Notepad (or finds active text editor)
2. Types the text naturally
3. Formats if needed

### ✅ Autonomous Application Control
```python
# It knows how to open apps
agent.execute_task("Open Calculator")
agent.execute_task("Launch Microsoft Paint")
agent.execute_task("Open File Explorer")
```

### ✅ Autonomous Game Playing (Advanced)
```python
# It will try to play the game!
agent.execute_task("Play Solitaire for me")
agent.execute_task("Play Minesweeper")
```

**What it does:**
1. Analyzes the game screen
2. Detects game state (cards, mines, etc.)
3. Decides best move
4. Executes the move
5. Repeats until win/lose

---

## 🏗️ How It Works

### Architecture

```
User Request ("Draw a cat")
    ↓
Natural Language Understanding
    ↓
Task Planning (Step-by-step plan)
    ↓
Step Execution Loop:
    - Observe Screen (Computer Vision)
    - Decide Action (AI Reasoning)
    - Execute Action (Desktop Control)
    - Verify Result
    ↓
Task Complete!
```

### Key Components

1. **Task Planner** - Breaks down high-level tasks into steps
2. **Vision System** - Understands what's on screen (screenshots, OCR, object detection)
3. **Reasoning Engine** - Decides what to do next
4. **Action Executor** - Performsthe actual mouse/keyboard actions
5. **Feedback Loop** - Verifies actions succeeded

---

## 📋 Supported Tasks (Current)

### Tier 1: Fully Automated ✅

| Task Pattern | Example | Status |
|-------------|---------|---------|
| Draw shapes in Paint | "Draw a circle" | ✅ Working |
| Basic text entry | "Type Hello" | ✅ Working |
| Launch applications | "Open Paint" | ✅ Working |

### Tier 2: Partially Automated 🔨

| Task Pattern | Example | Status |
|-------------|---------|---------|
| Form filling | "Fill out this form" | 🔨 In Progress |
| File operations | "Copy these files" | 🔨 In Progress |
| Web navigation | "Find on Google" | 🔨 Planned |

### Tier 3: Experimental 🧪

| Task Pattern | Example | Status |
|-------------|---------|---------|
| Game playing | "Play Solitaire" | 🧪 Experimental |
| Image editing | "Resize this photo" | 🧪 Planned |
| Code editing | "Fix this bug" | 🧪 Research |

---

## 🎨 Example: Drawing in Paint

### Simple Request
```python
agent = AIDesktopAgent()
result = agent.execute_task("Draw a circle in Paint")

# Check result
print(f"Status: {result['status']}")
print(f"Steps taken: {len(result['steps'])}")
```

### What Happens Behind the Scenes

**1. Planning Phase:**
```
Plan generated:
  Step 1: Launch MS Paint
  Step 2: Wait 2s for Paint to load
  Step 3: Activate Paint window
  Step 4: Select pencil tool (press 'P')
  Step 5: Draw circle at canvas center
  Step 6: Screenshot the result
```

**2. Execution Phase:**
```
[✓] Launched Paint via Win+R → mspaint
[✓] Waited 2.0s
[✓] Activated window "Paint"
[✓] Pressed 'P' to select pencil
[✓] Drew circle with 72 points
[✓] Screenshot saved: drawing_result.png
```

**3. Result:**
```python
{
    "task": "Draw a circle in Paint",
    "status": "completed",
    "success": True,
    "steps": [... 6 steps ...],
    "screenshots": [... 6 screenshots ...],
}
```

---

## 🎮 Example: Game Playing

```python
agent = AIDesktopAgent()

# Play a simple game
result = agent.execute_task("Play Solitaire for me")
```

### Game Playing Loop

```
1. Analyze screen → Detect cards, positions
2. Identify valid moves → Find legal plays
3. Evaluate moves → Which is best?
4. Execute move → Click and drag card
5. Repeat until game ends
```

### Game-Specific Intelligence

The agent can learn patterns for:
- **Solitaire**: Card stacking rules, suit matching
- **Minesweeper**: Probability calculations, safe clicks
- **2048**: Tile merging strategy
- **Chess** (if integrated with engine): Move evaluation

---

## 🧠 Enhancing the AI

### Adding Application Knowledge

```python
# In ai_agent.py, add to app_knowledge:

self.app_knowledge = {
    "photoshop": {
        "name": "Adobe Photoshop",
        "launch_command": "photoshop",
        "common_actions": {
            "new_layer": {"hotkey": ["ctrl", "shift", "n"]},
            "brush_tool": {"hotkey": ["b"]},
            "eraser": {"hotkey": ["e"]},
        }
    }
}
```

### Adding Custom Task Patterns

```python
# Add a custom planning method
def _plan_photo_edit(self, task: str) -> List[Dict]:
    """Plan for photo editing tasks."""
    return [
        {"type": "launch_app", "app": "photoshop"},
        {"type": "wait", "duration": 3.0},
        {"type": "open_file", "path": extracted_path},
        {"type": "apply_filter", "filter": extracted_filter},
        {"type": "save_file"},
    ]
```

---

## 🔥 Advanced: Vision + Reasoning

### Screen Analysis

The agent can analyze screenshots to:
- **Detect UI elements** (buttons, text fields, menus)
- **Read text** (OCR for labels, instructions)
- **Identify objects** (icons, images, game pieces)
- **Understand layout** (where things are)

```python
# Analyze what's on screen
analysis = agent._analyze_screen()

print(analysis)
# Output:
# {
#     "active_window": "Untitled - Paint",
#     "mouse_position": (640, 480),
#     "detected_elements": [...],
#     "text_found": [...],
# }
```

### Integration with OpenClaw LLM

```python
# Future: Use OpenClaw's LLM for reasoning
agent = AIDesktopAgent(llm_client=openclaw_llm)

# The agent can now:
# - Reason about complex tasks
# - Understand context better
# - Plan more sophisticated workflows
# - Learn from feedback
```

---

## 🛠️ Extending for Your Needs

### Add Support for New Apps

1. **Identify the app**
2. **Document common actions**
3. **Add to knowledge base**
4. **Create planning method**

Example: Adding Excel support

```python
# Step 1: Add to app_knowledge
"excel": {
    "name": "Microsoft Excel",
    "launch_command": "excel",
    "common_actions": {
        "new_sheet": {"hotkey": ["shift", "f11"]},
        "sum_formula": {"action": "type", "text": "=SUM()"},
    }
}

# Step 2: Create planner
def _plan_excel_task(self, task: str) -> List[Dict]:
    return [
        {"type": "launch_app", "app": "excel"},
        {"type": "wait", "duration": 2.0},
        # ... specific Excel steps
    ]

# Step 3: Hook into main planner
if "excel" in task_lower or "spreadsheet" in task_lower:
    return self._plan_excel_task(task)
```

---

## 🎯 Real-World Use Cases

### 1. Automated Form Filling
```python
agent.execute_task("Fill out the job application with my resume data")
```

### 2. Batch Image Processing
```python
agent.execute_task("Resize all images in this folder to 800x600")
```

### 3. Social Media Posting
```python
agent.execute_task("Post this image to Instagram with caption 'Beautiful sunset'")
```

### 4. Data Entry
```python
agent.execute_task("Copy data from this PDF to Excel spreadsheet")
```

### 5. Testing
```python
agent.execute_task("Test the login form with invalid credentials")
```

---

## ⚙️ Configuration

### Enable/Disable Failsafe
```python
# Safe mode (default)
agent = AIDesktopAgent(failsafe=True)

# Fast mode (no failsafe)
agent = AIDesktopAgent(failsafe=False)
```

### Set Max Steps
```python
# Prevent infinite loops
result = agent.execute_task("Play game", max_steps=100)
```

### Access Action History
```python
# Review what the agent did
print(agent.action_history)
```

---

## 🐛 Debugging

### View Step-by-Step Execution
```python
result = agent.execute_task("Draw a star in Paint")

for i, step in enumerate(result['steps'], 1):
    print(f"Step {i}: {step['step']['description']}")
    print(f"  Success: {step['success']}")
    if 'error' in step:
        print(f"  Error: {step['error']}")
```

### View Screenshots
```python
# Each step captures before/after screenshots
for screenshot_pair in result['screenshots']:
    before = screenshot_pair['before']
    after = screenshot_pair['after']
    
    # Display or save for analysis
    before.save(f"step_{screenshot_pair['step']}_before.png")
    after.save(f"step_{screenshot_pair['step']}_after.png")
```

---

## 🚀 Future Enhancements

Planned features:

- [ ] **Computer Vision**: OCR, object detection, UI element recognition
- [ ] **LLM Integration**: Natural language understanding with OpenClaw LLM
- [ ] **Learning**: Remember successful patterns, improve over time
- [ ] **Multi-App Workflows**: "Get data from Chrome and put in Excel"
- [ ] **Voice Control**: "Alexa, draw a cat in Paint"
- [ ] **Autonomous Debugging**: Fix errors automatically
- [ ] **Game AI**: Reinforcement learning for game playing
- [ ] **Web Automation**: Full browser control with understanding

---

## 📚 Full API

### Main Methods

```python
# Execute a task
result = agent.execute_task(task: str, max_steps: int = 50)

# Analyze screen
analysis = agent._analyze_screen()

# Manual mode: Execute individual steps
step = {"type": "launch_app", "app": "paint"}
result = agent._execute_step(step)
```

### Result Structure

```python
{
    "task": str,                    # Original task
    "status": str,                  # "completed", "failed", "error"
    "success": bool,                # Overall success
    "steps": List[Dict],            # All steps executed
    "screenshots": List[Dict],      # Before/after screenshots
    "failed_at_step": int,          # If failed, which step
    "error": str,                   # Error message if failed
}
```

---

**🦞 Built for OpenClaw - The future of desktop automation!**


path: desktop-control-1.0.0/ai_agent.py
content: """
AI Desktop Agent - Cognitive Desktop Automation
Combines vision, reasoning, and control for autonomous task execution
"""

import base64
import time
from typing import Dict, List, Optional, Any, Callable
from pathlib import Path
import logging

from desktop_control import DesktopController

logger = logging.getLogger(__name__)


class AIDesktopAgent:
    """
    Intelligent desktop agent that combines computer vision, LLM reasoning,
    and desktop control for autonomous task execution.
    
    Can understand screen content, plan actions, and execute complex workflows.
    """
    
    def __init__(self, llm_client=None, failsafe: bool = True):
        """
        Initialize AI Desktop Agent.
        
        Args:
            llm_client: OpenClaw LLM client for reasoning (optional, will try to auto-detect)
            failsafe: Enable failsafe mode
        """
        self.dc = DesktopController(failsafe=failsafe)
        self.llm_client = llm_client
        self.screen_width, self.screen_height = self.dc.get_screen_size()
        
        # Action history for learning
        self.action_history = []
        
        # Application knowledge base
        self.app_knowledge = self._load_app_knowledge()
        
        logger.info("AI Desktop Agent initialized")
    
    def _load_app_knowledge(self) -> Dict[str, Dict]:
        """
        Load application-specific knowledge.
        This can be extended with learned patterns.
        """
        return {
            "mspaint": {
                "name": "Microsoft Paint",
                "launch_command": "mspaint",
                "common_actions": {
                    "select_pencil": {"menu": "Tools", "position": "toolbar_left"},
                    "select_brush": {"menu": "Tools", "position": "toolbar"},
                    "select_color": {"menu": "Colors", "action": "click_palette"},
                    "draw_line": {"action": "drag", "tool_required": "line"},
                }
            },
            "notepad": {
                "name": "Notepad",
                "launch_command": "notepad",
                "common_actions": {
                    "type_text": {"action": "type"},
                    "save": {"hotkey": ["ctrl", "s"]},
                    "new_file": {"hotkey": ["ctrl", "n"]},
                }
            },
            "calculator": {
                "name": "Calculator",
                "launch_command": "calc",
                "common_actions": {
                    "calculate": {"action": "type_numbers"},
                }
            }
        }
    
    def execute_task(self, task: str, max_steps: int = 50) -> Dict[str, Any]:
        """
        Execute a high-level task autonomously.
        
        Args:
            task: Natural language task description
            max_steps: Maximum number of steps to attempt
            
        Returns:
            Execution result with status and details
        """
        logger.info(f"Executing task: {task}")
        
        # Initialize result
        result = {
            "task": task,
            "status": "in_progress",
            "steps": [],
            "screenshots": [],
            "success": False
        }
        
        try:
            # Step 1: Analyze task and plan
            plan = self._plan_task(task)
            logger.info(f"Generated plan with {len(plan)} steps")
            
            # Step 2: Execute plan step by step
            for step_num, step in enumerate(plan, 1):
                if step_num > max_steps:
                    logger.warning(f"Reached max steps ({max_steps})")
                    break
                
                logger.info(f"Step {step_num}/{len(plan)}: {step['description']}")
                
                # Capture screen before action
                screenshot_before = self.dc.screenshot()
                
                # Execute step
                step_result = self._execute_step(step)
                result["steps"].append(step_result)
                
                # Capture screen after action
                screenshot_after = self.dc.screenshot()
                result["screenshots"].append({
                    "step": step_num,
                    "before": screenshot_before,
                    "after": screenshot_after
                })
                
                # Verify step success
                if not step_result.get("success", False):
                    logger.error(f"Step {step_num} failed: {step_result.get('error')}")
                    result["status"] = "failed"
                    result["failed_at_step"] = step_num
                    return result
                
                # Small delay between steps
                time.sleep(0.5)
            
            result["status"] = "completed"
            result["success"] = True
            logger.info(f"Task completed successfully in {len(result['steps'])} steps")
            
        except Exception as e:
            logger.error(f"Task execution error: {e}")
            result["status"] = "error"
            result["error"] = str(e)
        
        return result
    
    def _plan_task(self, task: str) -> List[Dict[str, Any]]:
        """
        Plan task execution using LLM reasoning.
        
        Args:
            task: Task description
            
        Returns:
            List of execution steps
        """
        # For now, use rule-based planning
        # TODO: Integrate with OpenClaw LLM for intelligent planning
        
        # Parse task intent
        task_lower = task.lower()
        
        # Pattern matching for common tasks
        if "draw" in task_lower and "paint" in task_lower:
            return self._plan_paint_drawing(task)
        elif "type" in task_lower or "write" in task_lower:
            return self._plan_text_entry(task)
        elif "play" in task_lower and "game" in task_lower:
            return self._plan_game_play(task)
        elif "open" in task_lower or "launch" in task_lower:
            return self._plan_app_launch(task)
        else:
            # Generic plan - analyze and improvise
            return self._plan_generic(task)
    
    def _plan_paint_drawing(self, task: str) -> List[Dict]:
        """Plan for drawing in MS Paint."""
        # Extract what to draw
        drawing_subject = self._extract_subject(task)
        
        return [
            {
                "type": "launch_app",
                "app": "mspaint",
                "description": "Launch Microsoft Paint"
            },
            {
                "type": "wait",
                "duration": 2.0,
                "description": "Wait for Paint to load"
            },
            {
                "type": "activate_window",
                "title": "Paint",
                "description": "Ensure Paint window is active"
            },
            {
                "type": "select_tool",
                "tool": "pencil",
                "description": "Select pencil tool"
            },
            {
                "type": "draw",
                "subject": drawing_subject,
                "description": f"Draw {drawing_subject}"
            },
            {
                "type": "screenshot",
                "save_as": "drawing_result.png",
                "description": "Capture the drawing"
            }
        ]
    
    def _plan_text_entry(self, task: str) -> List[Dict]:
        """Plan for text entry task."""
        # Extract text to type
        text_content = self._extract_text_content(task)
        
        return [
            {
                "type": "launch_app",
                "app": "notepad",
                "description": "Launch Notepad"
            },
            {
                "type": "wait",
                "duration": 1.0,
                "description": "Wait for Notepad to load"
            },
            {
                "type": "type_text",
                "text": text_content,
                "wpm": 80,
                "description": f"Type: {text_content[:50]}..."
            }
        ]
    
    def _plan_game_play(self, task: str) -> List[Dict]:
        """Plan for playing a game."""
        game_name = self._extract_game_name(task)
        
        return [
            {
                "type": "analyze_screen",
                "description": "Analyze game screen"
            },
            {
                "type": "detect_game_state",
                "game": game_name,
                "description": f"Detect {game_name} state"
            },
            {
                "type": "execute_game_loop",
                "game": game_name,
                "max_iterations": 100,
                "description": f"Play {game_name}"
            }
        ]
    
    def _plan_app_launch(self, task: str) -> List[Dict]:
        """Plan for launching an application."""
        app_name = self._extract_app_name(task)
        
        return [
            {
                "type": "launch_app",
                "app": app_name,
                "description": f"Launch {app_name}"
            },
            {
                "type": "wait",
                "duration": 2.0,
                "description": f"Wait for {app_name} to load"
            }
        ]
    
    def _plan_generic(self, task: str) -> List[Dict]:
        """Generic planning fallback."""
        return [
            {
                "type": "analyze_screen",
                "description": "Analyze current screen state"
            },
            {
                "type": "infer_action",
                "task": task,
                "description": f"Infer action for: {task}"
            }
        ]
    
    def _execute_step(self, step: Dict[str, Any]) -> Dict[str, Any]:
        """
        Execute a single step.
        
        Args:
            step: Step definition
            
        Returns:
            Execution result
        """
        step_type = step.get("type")
        result = {"step": step, "success": False}
        
        try:
            if step_type == "launch_app":
                self._do_launch_app(step["app"])
                result["success"] = True
                
            elif step_type == "wait":
                time.sleep(step["duration"])
                result["success"] = True
                
            elif step_type == "activate_window":
                success = self.dc.activate_window(step["title"])
                result["success"] = success
                
            elif step_type == "select_tool":
                self._do_select_tool(step["tool"])
                result["success"] = True
                
            elif step_type == "draw":
                self._do_draw(step["subject"])
                result["success"] = True
                
            elif step_type == "type_text":
                self.dc.type_text(step["text"], wpm=step.get("wpm", 80))
                result["success"] = True
                
            elif step_type == "screenshot":
                filename = step.get("save_as", "screenshot.png")
                self.dc.screenshot(filename=filename)
                result["success"] = True
                result["saved_to"] = filename
                
            elif step_type == "analyze_screen":
                analysis = self._analyze_screen()
                result["analysis"] = analysis
                result["success"] = True
                
            elif step_type == "execute_game_loop":
                game_result = self._execute_game_loop(step)
                result["game_result"] = game_result
                result["success"] = True
                
            else:
                result["error"] = f"Unknown step type: {step_type}"
                
        except Exception as e:
            logger.error(f"Step execution error: {e}")
            result["error"] = str(e)
        
        return result
    
    def _do_launch_app(self, app: str) -> None:
        """Launch an application."""
        # Get launch command from knowledge base
        app_info = self.app_knowledge.get(app, {})
        launch_cmd = app_info.get("launch_command", app)
        
        # Open Run dialog
        self.dc.hotkey('win', 'r')
        time.sleep(0.5)
        
        # Type and execute command
        self.dc.type_text(launch_cmd, wpm=100)
        self.dc.press('enter')
        
        logger.info(f"Launched: {app}")
    
    def _do_select_tool(self, tool: str) -> None:
        """Select a tool (e.g., in Paint)."""
        # This is simplified - in reality would use computer vision
        # to find and click the tool button
        
        # For Paint, tools are typically in the ribbon
        # We'll use hotkeys where possible
        if tool == "pencil":
            # In Paint, press 'P' for pencil
            self.dc.press('p')
        elif tool == "brush":
            self.dc.press('b')
        elif tool == "eraser":
            self.dc.press('e')
        
        logger.info(f"Selected tool: {tool}")
    
    def _do_draw(self, subject: str) -> None:
        """
        Draw something on screen.
        This is a simplified implementation - would be enhanced with:
        - Image generation (use wan2gp to generate reference)
        - Trace generation (convert image to draw commands)
        - Executed drawing (execute the commands)
        """
        logger.info(f"Drawing: {subject}")
        
        # Get canvas center (simplified - would detect canvas)
        canvas_x = self.screen_width // 2
        canvas_y = self.screen_height // 2
        
        # Simple drawing pattern (example: draw a    simple shape)
        if "circle" in subject.lower():
            self._draw_circle(canvas_x, canvas_y, radius=100)
        elif "square" in subject.lower():
            self._draw_square(canvas_x, canvas_y, size=200)
        elif "star" in subject.lower():
            self._draw_star(canvas_x, canvas_y, size=100)
        else:
            # Generic: draw a simple pattern
            self._draw_simple_pattern(canvas_x, canvas_y)
        
        logger.info(f"Completed drawing: {subject}")
    
    def _draw_circle(self, cx: int, cy: int, radius: int) -> None:
        """Draw a circle."""
        import math
        
        points = []
        for angle in range(0, 360, 5):
            rad = math.radians(angle)
            x = int(cx + radius * math.cos(rad))
            y = int(cy + radius * math.sin(rad))
            points.append((x, y))
        
        # Draw by connecting points
        for i in range(len(points) - 1):
            self.dc.drag(points[i][0], points[i][1], 
                        points[i+1][0], points[i+1][1], 
                        duration=0.01)
        # Close the circle
        self.dc.drag(points[-1][0], points[-1][1], 
                    points[0][0], points[0][1], 
                    duration=0.01)
    
    def _draw_square(self, cx: int, cy: int, size: int) -> None:
        """Draw a square."""
        half = size // 2
        corners = [
            (cx - half, cy - half),  # Top-left
            (cx + half, cy - half),  # Top-right
            (cx + half, cy + half),  # Bottom-right
            (cx - half, cy + half),  # Bottom-left
        ]
        
        # Draw sides
        for i in range(4):
            start = corners[i]
            end = corners[(i + 1) % 4]
            self.dc.drag(start[0], start[1], end[0], end[1], duration=0.2)
    
    def _draw_star(self, cx: int, cy: int, size: int) -> None:
        """Draw a 5-pointed star."""
        import math
        
        points = []
        for i in range(10):
            angle = math.radians(i * 36 - 90)
            radius = size if i % 2 == 0 else size // 2
            x = int(cx + radius * math.cos(angle))
            y = int(cy + radius * math.sin(angle))
            points.append((x, y))
        
        # Draw by connecting points
        for i in range(len(points)):
            start = points[i]
            end = points[(i + 1) % len(points)]
            self.dc.drag(start[0], start[1], end[0], end[1], duration=0.1)
    
    def _draw_simple_pattern(self, cx: int, cy: int) -> None:
        """Draw a simple decorative pattern."""
        # Draw a few curved lines
        for offset in [-50, 0, 50]:
            self.dc.drag(cx - 100, cy + offset, 
                        cx + 100, cy + offset, 
                        duration=0.3)
    
    def _analyze_screen(self) -> Dict[str, Any]:
        """
        Analyze current screen state.
        Would use OCR, object detection in full implementation.
        """
        screenshot = self.dc.screenshot()
        active_window = self.dc.get_active_window()
        mouse_pos = self.dc.get_mouse_position()
        
        analysis = {
            "active_window": active_window,
            "mouse_position": mouse_pos,
            "screen_size": (self.screen_width, self.screen_height),
            "timestamp": time.time()
        }
        
        # TODO: Add OCR, object detection, UI element detection
        
        return analysis
    
    def _execute_game_loop(self, step: Dict) -> Dict:
        """
        Execute game playing loop.
        Would use reinforcement learning in full implementation.
        """
        game = step.get("game", "unknown")
        max_iter = step.get("max_iterations", 100)
        
        logger.info(f"Starting game loop for: {game}")
        
        result = {
            "game": game,
            "iterations": 0,
            "actions_taken": []
        }
        
        # Simple game loop - would be much more sophisticated
        for i in range(max_iter):
            # Analyze game state
            state = self._analyze_screen()
            
            # Decide action (simplified - would use ML model)
            action = self._decide_game_action(state, game)
            
            # Execute action
            self._execute_game_action(action)
            
            result["iterations"] += 1
            result["actions_taken"].append(action)
            
            # Check win/lose condition
            # (would detect from screen)
            
            time.sleep(0.1)
        
        return result
    
    def _decide_game_action(self, state: Dict, game: str) -> str:
        """Decide next game action based on state."""
        # Simplified - would use game-specific AI
        return "continue"
    
    def _execute_game_action(self, action: str) -> None:
        """Execute a game action."""
        # Simplified - would translate to specific inputs
        pass
    
    # Helper methods for parsing
    
    def _extract_subject(self, text: str) -> str:
        """Extract subject from drawing request."""
        # Simple extraction - would use NLP
        if "draw" in text.lower():
            parts = text.lower().split("draw")
            if len(parts) > 1:
                return parts[1].strip()
        return "unknown"
    
    def _extract_text_content(self, text: str) -> str:
        """Extract text content from typing request."""
        # Simple extraction
        if "type" in text.lower():
            parts = text.split("type")
            if len(parts) > 1:
                return parts[1].strip().strip('"').strip("'")
        return text
    
    def _extract_game_name(self, text: str) -> str:
        """Extract game name from request."""
        # Would use NER for better extraction
        return "unknown_game"
    
    def _extract_app_name(self, text: str) -> str:
        """Extract application name from request."""
        # Simple extraction - would use NER
        for app in self.app_knowledge.keys():
            if app in text.lower():
                return app
        return "notepad"  # Default fallback


# Quick access function
def create_agent(**kwargs) -> AIDesktopAgent:
    """Create an AI Desktop Agent instance."""
    return AIDesktopAgent(**kwargs)


if __name__ == "__main__":
    print("🤖 AI Desktop Agent - Cognitive Automation")
    print("=" * 60)
    
    # Create agent
    agent = AIDesktopAgent(failsafe=True)
    
    print("\n✨ Examples of what you can ask:")
    print("  - 'Draw a circle in Paint'")
    print("  - 'Type Hello World in Notepad'")
    print("  - 'Open Calculator'")
    print("  - 'Play Solitaire for me'")
    
    print("\n🎯 Try it:")
    task = input("\nWhat would you like me to do? ")
    
    if task.strip():
        result = agent.execute_task(task)
        print(f"\n{'='* 60}")
        print(f"Task Status: {result['status']}")
        print(f"Steps Executed: {len(result['steps'])}")
        print(f"Success: {result['success']}")
        
        if result.get('screenshots'):
            print(f"Screenshots captured: {len(result['screenshots'])}")
    else:
        print("\nNo task entered. Exiting.")


path: desktop-control-1.0.0/demo.py
content: """
Desktop Control Demo - Quick examples and tests
"""

import sys
import time
from pathlib import Path

# Add skills to path
sys.path.insert(0, str(Path(__file__).parent))

from desktop_control import DesktopController

def demo_mouse_control():
    """Demo: Mouse movement and clicking"""
    print("\n🖱️  === MOUSE CONTROL DEMO ===")
    
    dc = DesktopController(failsafe=True)
    
    print(f"Current position: {dc.get_mouse_position()}")
    
    # Smooth movement
    print("\n1. Moving mouse smoothly to center of screen...")
    screen_w, screen_h = dc.get_screen_size()
    center_x, center_y = screen_w // 2, screen_h // 2
    dc.move_mouse(center_x, center_y, duration=1.0)
    
    # Relative movement
    print("2. Moving 100px right...")
    dc.move_relative(100, 0, duration=0.5)
    
    print(f"Final position: {dc.get_mouse_position()}")
    
    print("✅ Mouse demo complete!")


def demo_keyboard_control():
    """Demo: Keyboard typing"""
    print("\n⌨️  === KEYBOARD CONTROL DEMO ===")
    
    dc = DesktopController()
    
    print("\n⚠️  In 3 seconds, I'll type 'Hello from OpenClaw!' in the active window")
    print("Switch to Notepad or any text editor NOW!")
    time.sleep(3)
    
    # Type with human-like speed
    dc.type_text("Hello from OpenClaw! ", wpm=60)
    dc.type_text("This is desktop automation in action. ", wpm=80)
    
    # Press Enter
    dc.press('enter')
    dc.press('enter')
    
    # Type instant
    dc.type_text("This was typed instantly!", interval=0)
    
    print("\n✅ Keyboard demo complete!")


def demo_screen_capture():
    """Demo: Screenshot functionality"""
    print("\n📸 === SCREEN CAPTURE DEMO ===")
    
    dc = DesktopController()
    
    # Full screenshot
    print("\n1. Capturing full screen...")
    dc.screenshot(filename="demo_fullscreen.png")
    print("   Saved: demo_fullscreen.png")
    
    # Region screenshot (center 800x600)
    print("\n2. Capturing center region (800x600)...")
    screen_w, screen_h = dc.get_screen_size()
    region = (
        (screen_w - 800) // 2,  # left
        (screen_h - 600) // 2,  # top
        800,  # width
        600   # height
    )
    dc.screenshot(region=region, filename="demo_region.png")
    print("   Saved: demo_region.png")
    
    # Get pixel color
    print("\n3. Getting pixel color at center...")
    center_x, center_y = screen_w // 2, screen_h // 2
    r, g, b = dc.get_pixel_color(center_x, center_y)
    print(f"   Color at ({center_x}, {center_y}): RGB({r}, {g}, {b})")
    
    print("\n✅ Screen capture demo complete!")


def demo_window_management():
    """Demo: Window operations"""
    print("\n🪟 === WINDOW MANAGEMENT DEMO ===")
    
    dc = DesktopController()
    
    # Get current window
    print(f"\n1. Active window: {dc.get_active_window()}")
    
    # List all windows
    windows = dc.get_all_windows()
    print(f"\n2. Found {len(windows)} open windows:")
    for i, title in enumerate(windows[:15], 1):  # Show first 15
        print(f"   {i}. {title}")
    
    print("\n✅ Window management demo complete!")


def demo_hotkeys():
    """Demo: Keyboard shortcuts"""
    print("\n🔥 === HOTKEY DEMO ===")
    
    dc = DesktopController()
    
    print("\n⚠️  This demo will:")
    print("   1. Open Windows Run dialog (Win+R)")
    print("   2. Type 'notepad'")
    print("   3. Press Enter to open Notepad")
    print("   4. Type a message")
    print("\nPress Enter to continue...")
    input()
    
    # Open Run dialog
    print("\n1. Opening Run dialog...")
    dc.hotkey('win', 'r')
    time.sleep(0.5)
    
    # Type notepad command
    print("2. Typing 'notepad'...")
    dc.type_text('notepad', wpm=80)
    time.sleep(0.3)
    
    # Press Enter
    print("3. Launching Notepad...")
    dc.press('enter')
    time.sleep(1)
    
    # Type message
    print("4. Typing message in Notepad...")
    dc.type_text("Desktop Control Skill Test\n\n", wpm=60)
    dc.type_text("This was automated by OpenClaw!\n", wpm=60)
    dc.type_text("- Mouse control ✓\n", wpm=60)
    dc.type_text("- Keyboard control ✓\n", wpm=60)
    dc.type_text("- Hotkeys ✓\n", wpm=60)
    
    print("\n✅ Hotkey demo complete!")


def demo_advanced_automation():
    """Demo: Complete automation workflow"""
    print("\n🚀 === ADVANCED AUTOMATION DEMO ===")
    
    dc = DesktopController()
    
    print("\nThis demo will:")
    print("1. Get your clipboard content")
    print("2. Copy a new string to clipboard")
    print("3. Show the changes")
    print("\nPress Enter to continue...")
    input()
    
    # Get current clipboard
    original = dc.get_from_clipboard()
    print(f"\n1. Original clipboard: '{original}'")
    
    # Copy new content
    test_text = "Hello from OpenClaw Desktop Control!"
    dc.copy_to_clipboard(test_text)
    print(f"2. Copied to clipboard: '{test_text}'")
    
    # Verify
    new_clipboard = dc.get_from_clipboard()
    print(f"3. Verified clipboard: '{new_clipboard}'")
    
    # Restore original
    if original:
        dc.copy_to_clipboard(original)
        print("4. Restored original clipboard")
    
    print("\n✅ Advanced automation demo complete!")


def  main():
    """Run all demos"""
    print("=" * 60)
    print("🎮 DESKTOP CONTROL SKILL - DEMO SUITE")
    print("=" * 60)
    print("\n⚠️  IMPORTANT:")
    print("- Failsafe is ENABLED (move mouse to corner to abort)")
    print("- Some demos will control your mouse and keyboard")
    print("- Close important applications before continuing")
    print("\n" + "=" * 60)
    
    demos = [
        ("Mouse Control", demo_mouse_control),
        ("Window Management", demo_window_management),
        ("Screen Capture", demo_screen_capture),
        ("Hotkeys", demo_hotkeys),
        ("Keyboard Control", demo_keyboard_control),
        ("Advanced Automation", demo_advanced_automation),
    ]
    
    while True:
        print("\n📋 SELECT DEMO:")
        for i, (name, _) in enumerate(demos, 1):
            print(f"  {i}. {name}")
        print(f"  {len(demos) + 1}. Run All")
        print("  0. Exit")
        
        choice = input("\nEnter choice: ").strip()
        
        if choice == '0':
            print("\n👋 Goodbye!")
            break
        elif choice == str(len(demos) + 1):
            for name, func in demos:
                print(f"\n{'=' * 60}")
                func()
                time.sleep(1)
            print(f"\n{'=' * 60}")
            print("🎉 All demos complete!")
        elif choice.isdigit() and 1 <= int(choice) <= len(demos):
            demos[int(choice) - 1][1]()
        else:
            print("❌ Invalid choice!")


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n\n⚠️  Demo interrupted by user")
    except Exception as e:
        print(f"\n\n❌ Error: {e}")
        import traceback
        traceback.print_exc()


path: desktop-control-1.0.0/QUICK_REFERENCE.md
content: # Desktop Control - Quick Reference Card

## 🚀 Instant Start

```python
from skills.desktop_control import DesktopController

dc = DesktopController()
```

## 🖱️ Mouse Control (Top 10)

```python
# 1. Move mouse
dc.move_mouse(500, 300, duration=0.5)

# 2. Click
dc.click(500, 300)  # Left click at position
dc.click()           # Click at current position

# 3. Right click
dc.right_click(500, 300)

# 4. Double click
dc.double_click(500, 300)

# 5. Drag & drop
dc.drag(100, 100, 500, 500, duration=1.0)

# 6. Scroll
dc.scroll(-5)  # Scroll down 5 clicks

# 7. Get position
x, y = dc.get_mouse_position()

# 8. Move relative
dc.move_relative(100, 50)  # Move 100px right, 50px down

# 9. Smooth movement
dc.move_mouse(1000, 500, duration=1.0, smooth=True)

# 10. Middle click
dc.middle_click()
```

## ⌨️ Keyboard Control (Top 10)

```python
# 1. Type text (instant)
dc.type_text("Hello World")

# 2. Type text (human-like, 60 WPM)
dc.type_text("Hello World", wpm=60)

# 3. Press key
dc.press('enter')
dc.press('tab')
dc.press('escape')

# 4. Hotkeys (shortcuts)
dc.hotkey('ctrl', 'c')      # Copy
dc.hotkey('ctrl', 'v')      # Paste  
dc.hotkey('ctrl', 's')      # Save
dc.hotkey('win', 'r')       # Run dialog
dc.hotkey('alt', 'tab')     # Switch window

# 5. Hold & release
dc.key_down('shift')
dc.type_text("hello")  # Types "HELLO"
dc.key_up('shift')

# 6. Arrow keys
dc.press('up')
dc.press('down')
dc.press('left')
dc.press('right')

# 7. Function keys
dc.press('f5')  # Refresh

# 8. Multiple presses
dc.press('backspace', presses=5)

# 9. Special keys
dc.press('home')
dc.press('end')
dc.press('pagedown')
dc.press('delete')

# 10. Fast combo
dc.hotkey('ctrl', 'alt', 'delete')
```

## 📸 Screen Operations (Top 5)

```python
# 1. Screenshot (full screen)
img = dc.screenshot()
dc.screenshot(filename="screen.png")

# 2. Screenshot (region)
img = dc.screenshot(region=(100, 100, 800, 600))

# 3. Get pixel color
r, g, b = dc.get_pixel_color(500, 300)

# 4. Find image on screen
location = dc.find_on_screen("button.png")

# 5. Get screen size
width, height = dc.get_screen_size()
```

## 🪟 Window Management (Top 5)

```python
# 1. Get all windows
windows = dc.get_all_windows()

# 2. Activate window
dc.activate_window("Chrome")

# 3. Get active window
active = dc.get_active_window()

# 4. List windows
for title in dc.get_all_windows():
    print(title)

# 5. Switch to app
dc.activate_window("Visual Studio Code")
```

## 📋 Clipboard (Top 2)

```python
# 1. Copy to clipboard
dc.copy_to_clipboard("Hello!")

# 2. Get from clipboard
text = dc.get_from_clipboard()
```

## 🔥 Real-World Examples

### Example 1: Auto-fill Form
```python
dc.click(300, 200)  # Name field
dc.type_text("John Doe", wpm=80)
dc.press('tab')
dc.type_text("[REDACTED_SECRET]", wpm=80)
dc.press('tab')
dc.type_text("Password123", wpm=60)
dc.press('enter')
```

### Example 2: Copy-Paste Automation
```python
# Select all
dc.hotkey('ctrl', 'a')
# Copy
dc.hotkey('ctrl', 'c')
# Wait
dc.pause(0.5)
# Switch window
dc.hotkey('alt', 'tab')
# Paste
dc.hotkey('ctrl', 'v')
```

### Example 3: File Operations
```python
# Select multiple files
dc.key_down('ctrl')
dc.click(100, 200)
dc.click(100, 250)
dc.click(100, 300)
dc.key_up('ctrl')
# Copy
dc.hotkey('ctrl', 'c')
```

### Example 4: Screenshot Workflow
```python
# Take screenshot
dc.screenshot(filename=f"capture_{time.time()}.png")
# Open in Paint
dc.hotkey('win', 'r')
dc.pause(0.5)
dc.type_text('mspaint')
dc.press('enter')
```

### Example 5: Search & Replace
```python
# Open Find & Replace
dc.hotkey('ctrl', 'h')
dc.pause(0.3)
# Type find text
dc.type_text("old_text")
dc.press('tab')
# Type replace text
dc.type_text("new_text")
# Replace all
dc.hotkey('alt', 'a')
```

## ⚙️ Configuration

```python
# With failsafe (move to corner to abort)
dc = DesktopController(failsafe=True)

# With approval mode (ask before each action)
dc = DesktopController(require_approval=True)

# Maximum speed (no safety checks)
dc = DesktopController(failsafe=False)
```

## 🛡️ Safety

```python
# Check if safe to continue
if dc.is_safe():
    dc.click(500, 500)

# Pause execution
dc.pause(2.0)  # Wait 2 seconds

# Emergency abort: Move mouse to any screen corner
```

## 🎯 Pro Tips

1. **Instant typing**: `interval=0` or `wpm=None`
2. **Human typing**: `wpm=60` (60 words/min)
3. **Smooth mouse**: `duration=0.5, smooth=True`
4. **Instant mouse**: `duration=0`
5. **Wait for UI**: `dc.pause(0.5)` between actions
6. **Failsafe**: Always enable for safety
7. **Test first**: Use `demo.py` to test features
8. **Coordinates**: Use `get_mouse_position()` to find them
9. **Screenshots**: Capture before/after for verification
10. **Hotkeys > Menus**: Faster and more reliable

## 📦 Dependencies

```bash
pip install pyautogui pillow opencv-python pygetwindow pyperclip
```

## 🚨 Common Issues

**Mouse not moving correctly?**
- Check DPI scaling in Windows settings
- Verify coordinates with `get_mouse_position()`

**Keyboard not working?**
- Ensure target app has focus
- Some apps block automation (games, secure apps)

**Failsafe triggering?**
- Keep mouse away from screen corners
- Disable if needed: `failsafe=False`

---

**Built for OpenClaw** 🦞 - Desktop automation made easy!


path: desktop-control-1.0.0/_meta.json
content: ownerId: kn7ag28ra4hhta8bx2k2j1kpv180kqbk
slug: desktop-control
version: 1.0.0
publishedAt: 1770255200863

path: agents-config-draft.md
content: # Agent Config Draft

## Agents to Rebuild

1. **Scout** 🔍
   - Role: Discovery (find opportunities)
   - Model: anthropic/claude-sonnet-4-5

2. **Sage** 🦉
   - Role: Architecture (from opportunities → specs)
   - Model: anthropic/claude-sonnet-4-5

3. **Pixel** 🎨
   - Role: Design (visuals, branding)
   - Model: anthropic/claude-sonnet-4-5

4. **Link** 🔗
   - Role: Build (code, MVP construction)
   - Model: anthropic/claude-sonnet-4-5

5. **Spark** ✨
   - Role: Distribution (content, announcements)
   - Model: anthropic/claude-sonnet-4-5

6. **Echo** 📝
   - Role: Documentation (write docs, guides, blogs)
   - Model: anthropic/claude-sonnet-4-5

7. **Rhythm** 🥁
   - Role: Backlog/Grooming (ops/triage)
   - Model: anthropic/claude-sonnet-4-5

8. **Harmony** 🤝
   - Role: Health/Morale (team vibes, audits)
   - Model: anthropic/claude-sonnet-4-5

---

## Test Plan
- **Testing sequence:** One at a time
- **Verify model**: Sonnet for all agents
- **Ensure work proceeds:** Use `HEARTBEAT.md` loop tasks to validate role functions

---

## Next Steps
- Enable config for seamless spawning.
- Test roles sequentially (start with Scout, validate tools + outputs).
- Document fixes.

path: package.json
content: {
  "name": "agent-team-kit",
  "version": "1.0.0",
  "description": "Self-sustaining process framework for AI agent teams",
  "keywords": [
    "openclaw",
    "agent",
    "team",
    "process",
    "workflow",
    "autonomous",
    "multi-agent"
  ],
  "author": "OpenClaw Community",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/openclaw/agent-team-kit"
  },
  "openclaw": {
    "type": "skill",
    "category": "process",
    "requires": [],
    "provides": [
      "intake-loop",
      "role-definitions",
      "heartbeat-patterns"
    ],
    "files": {
      "skill": "SKILL.md",
      "readme": "README.md",
      "templates": "templates/"
    }
  },
  "files": [
    "SKILL.md",
    "README.md",
    "templates/"
  ]
}


path: README.md
content: # Agent Team Kit

[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![OpenClaw Skill](https://img.shields.io/badge/openclaw-skill-purple.svg)](https://github.com/openclaw/openclaw)

**A self-sustaining process framework for AI agent teams.**

Built for [OpenClaw](https://github.com/openclaw/openclaw) but adaptable to any multi-agent setup.

---

## Why This Exists

AI agents working together hit the same problems as human teams:
- Work piles up waiting for one person to triage
- Nobody knows who owns what
- Great ideas get forgotten
- Nothing happens unless someone pushes

This kit solves that with:

✅ **Self-service work queues** — Agents pick tasks without bottlenecks  
✅ **Clear role ownership** — No ambiguity about responsibilities  
✅ **Continuous discovery** — Work flows in automatically  
✅ **Heartbeat-driven operation** — The team runs itself  

---

## The Loop

```
     ┌────────────────────────────────────────────────────┐
     │                                                    │
     ▼                                                    │
┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐ │
│ DISCOVER│───▶│  TRIAGE │───▶│  READY  │───▶│ EXECUTE │─┘
│ Scout 🔍│    │Rhythm 🥁│    │Self-Srv │    │ Agents  │
└─────────┘    └─────────┘    └─────────┘    └─────────┘
                                                   │
                              FEEDBACK ◀───────────┘
```

1. **Discover** — Find opportunities and problems
2. **Triage** — Decide what's ready to work
3. **Ready** — Self-service queue (anyone can pick up)
4. **Execute** — Do the work
5. **Feedback** — Learn, improve, spawn new opportunities

---

## Roles

| Role | Emoji | Mission |
|------|-------|---------|
| Scout | 🔍 | Find opportunities before they find us |
| Rhythm | 🥁 | Keep work flowing, triage ruthlessly |
| Harmony | 🤝 | Keep the team healthy and unblocked |
| Human | 🌊 | Strategic direction, hard calls |

**Execution roles** (spawned as needed): Link 🔗 (build), Pixel 🎨 (design), Sage 🦉 (architecture), Echo 📢 (communication), Spark ✨ (creative)

---

## Installation

### For OpenClaw

```bash
# Clone into your skills directory
git clone https://github.com/reflectt/agent-team-kit skills/agent-team-kit

# Copy templates to your workspace
cp -r skills/agent-team-kit/templates/process ./process
```

### Manual Setup

Copy these files to your workspace:
- `templates/process/INTAKE.md`
- `templates/process/ROLES.md`
- `templates/HEARTBEAT.md`

Create empty process files:
- `process/OPPORTUNITIES.md`
- `process/BACKLOG.md`
- `process/STATUS.md`

---

## Quick Start

1. **Read** `process/INTAKE.md` to understand the loop
2. **Customize** `process/ROLES.md` with your role names
3. **Add** heartbeat checks from `HEARTBEAT.md`
4. **Start discovering** — add first opportunities to `OPPORTUNITIES.md`
5. **Let it run** — the heartbeat keeps the loop spinning

---

## Key Principles

### 1. Self-Service
If work is in the Ready queue, any agent can pick it up. No approval needed. First claim wins.

### 2. Clear Ownership
Every phase has ONE owner. No "shared responsibility" (which means no responsibility).

### 3. Log Everything
Ideas, discoveries, completions — if it's not logged, it didn't happen. Memory is limited; files persist.

### 4. Spawn, Don't Solo
The main agent coordinates. Sub-agents execute. Don't try to do everything in one context.

### 5. Trust the System
Once it's set up, let it run. The heartbeat keeps things moving. Intervene only when something breaks.

---

## File Structure

```
your-workspace/
├── process/
│   ├── INTAKE.md         # The 5-phase loop (reference doc)
│   ├── ROLES.md          # Role definitions
│   ├── OPPORTUNITIES.md  # Raw discoveries (anyone adds)
│   ├── BACKLOG.md        # Triaged work queue
│   └── STATUS.md         # Current activity
├── HEARTBEAT.md          # Proactive operation triggers
└── skills/
    └── agent-team-kit/   # This skill
```

---

## Customization

The kit is designed to be adapted:

- **Rename roles** to fit your domain (Scout → Researcher, Link → Developer)
- **Add specialized roles** for your work type
- **Adjust cadences** based on your team's rhythm
- **Modify the loop** — add gates, split phases, whatever works

See `SKILL.md` for detailed customization instructions.

---

## Anti-Patterns

These kill autonomous teams:

| ❌ Don't | ✅ Do Instead |
|----------|---------------|
| Human adds every task | Rhythm triages, anyone discovers |
| Wait for approval | Ready = fair game |
| One agent does everything | Spawn specialists |
| Keep ideas in your head | Log to OPPORTUNITIES.md |
| Heartbeat just returns OK | Actually check the loop |

---

## Contributing

PRs welcome. This framework evolved from real multi-agent team operation.

Especially interested in:
- Adaptations for different domains
- Additional role templates
- Metrics and observability patterns
- Integration with other agent frameworks

---

## Related Kits

Part of the Reflectt agent kit family:

- **[agent-memory-kit](https://github.com/reflectt/agent-memory-kit)** — Structured memory patterns for persistent agent context
- **[agent-autonomy-kit](https://github.com/reflectt/agent-autonomy-kit)** — Self-directed operation via heartbeats, cron, and proactive behavior

These kits work great together — memory for continuity, autonomy for self-operation, and team for coordination.

---

## License

MIT — use it, fork it, adapt it.

---

*Built with 📝 by teams that got tired of being bottlenecks.*


path: templates/HEARTBEAT.md
content: # HEARTBEAT.md — Team Operations

## Autonomous Team Operations

Heartbeat = keep the team running. NOT "check and chill." Spawn agents, keep work flowing.

### 1. Human First (always)

- [ ] Human messages waiting? → Handle immediately
- [ ] Direct request? → Respond or delegate

### 2. Check Task Queue (`tasks/QUEUE.md`)

- [ ] Any Critical/High priority tasks in Ready?
- [ ] If yes → spawn agent for top task (queue takes priority over discovery loop)
- [ ] Queue tasks = explicit work. Loop tasks = generative work. Explicit > generative.

### 4. Run the Intake Loop (if queue empty)

**Discovery:** Is Scout finding opportunities?
- Check `process/OPPORTUNITIES.md` last modified
- If stale (>4 hours) or empty → spawn Scout to discover

**Triage:** Is Rhythm processing the backlog?
- Check `process/BACKLOG.md` Ready section
- If opportunities sitting untriaged → spawn Rhythm to triage

**Execution:** Is work getting done?
- Check `process/BACKLOG.md` Ready section
- If tasks sitting >2 hours → spawn appropriate agent (Link for dev, Pixel for design, etc.)

### 5. Health Checks

- [ ] Any blockers that need escalation?
- [ ] Any agents stuck or erroring?
- [ ] Status files reflect reality?

### 6. Keep State Updated

- [ ] `process/STATUS.md` — accurate?
- [ ] `process/BACKLOG.md` — queue healthy (5-15 items in Ready)?

### 7. Log Activity

- [ ] Update `memory/YYYY-MM-DD.md` with what happened

---

## The Rule

**If the team isn't working, spawn them.**

Don't do the work yourself. Don't just say HEARTBEAT_OK. Check the loop, spawn agents, keep it moving.

You're the coordinator. The team does the work. Your job is to make sure they're working.

---

## Spawn Quick Reference

| Situation | Spawn |
|-----------|-------|
| No new opportunities in 4h | Scout 🔍 |
| Untriaged items piling up | Rhythm 🥁 |
| Work stuck, needs unblocking | Harmony 🤝 |
| Dev task ready | Link 🔗 |
| Design task ready | Pixel 🎨 |
| Architecture decision needed | Sage 🦉 |
| Content/comms task ready | Echo 📢 |
| Creative task ready | Spark ✨ |

---

## ❌ Anti-Patterns (Don't Do This)

| Bad | Why | Fix |
|-----|-----|-----|
| Return HEARTBEAT_OK without checking | Loop dies silently | Actually run the checklist |
| Do the work yourself instead of spawning | You become the bottleneck | Spawn specialists |
| Ask "what's next?" | That's the team's job to figure out | Check backlog, spawn who's needed |
| Wait for human direction | Defeats autonomy | Execute from Ready queue |
| Spawn and forget | Work may stall | Monitor running agents, follow up |

**The test:** If YOU are doing the work instead of coordinating agents, you're in Task Dispatcher mode. Stop. Spawn. Coordinate.

---

*Idle team = broken autonomy. Fix it.*


path: templates/process/BACKLOG.md
content: # Backlog

*Triaged work queue. Self-service from Ready.*

---

## 🟡 Ready (can be picked up)

### High Priority
| Task | Size | Notes |
|------|------|-------|
| | | |

### Medium Priority
| Task | Size | Notes |
|------|------|-------|
| | | |

### Low Priority
| Task | Size | Notes |
|------|------|-------|
| | | |

---

## 🔴 Blocked

| Task | Blocker | Owner |
|------|---------|-------|
| | | |

---

## ✅ Done (this sprint)

| Task | Completed | Agent |
|------|-----------|-------|
| | | |

---

## Notes

- **Ready = fair game** — Any agent can claim without approval
- **Pick top-down** — High priority before medium before low
- **First claim wins** — If conflict, whoever claimed first keeps it
- **Size guide** — S (<1h), M (1-4h), L (4h+)


path: templates/process/INTAKE.md
content: # Intake Process: How Work Flows

*The self-sustaining loop that keeps work moving without bottlenecks.*

---

## The Problem We're Solving

Before: One person manually added tasks. Ideas sat in parking lots. Nothing moved unless someone pushed it.

After: A self-sustaining system where work flows continuously and agents can self-serve.

---

## The Intake Loop

```
     ┌─────────────────────────────────────────────────────────┐
     │                                                         │
     ▼                                                         │
┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐      │
│ DISCOVER│───▶│  TRIAGE │───▶│  READY  │───▶│ EXECUTE │──────┘
│         │    │         │    │         │    │         │
│ Scout 🔍│    │Rhythm 🥁│    │Self-Srv │    │ Agents  │
└─────────┘    └─────────┘    └─────────┘    └─────────┘
     ▲                                              │
     │              Feedback Loop                   │
     └──────────────────────────────────────────────┘
```

---

## Phase 1: DISCOVER 🔍

**Owner:** Scout (or any agent who finds something)

**Sources of work:**
- User feedback (community channels, DMs, emails)
- Research findings (gaps, competitors, market shifts)
- Build failures (bugs, broken things, tech debt)
- Shipped work retrospectives (what should we improve?)
- External signals (social mentions, community requests)
- Internal signals (heartbeat checks, monitoring alerts)

**Output:** Raw ideas logged to `process/OPPORTUNITIES.md`

**Format for new entries:**
```markdown
### [Opportunity Name]
**Discovered:** YYYY-MM-DD
**Source:** [where it came from]
**Description:** [what's the opportunity/problem]
**Suggested action:** [rough idea of what to do]
```

**Who can add:** ANYONE. Discovery is open. If you see something, log it.

**Cadence:** 
- Scout does a dedicated discovery pass 2x/week
- Anyone adds opportunistically when they encounter things

---

## Phase 2: TRIAGE 🥁

**Owner:** Rhythm (Backlog Owner)

**When:** 
- Daily quick scan (5 min, async)
- Deep triage session at sprint boundaries

**The Triage Decision:**

For each item in OPPORTUNITIES.md, decide:

| Decision | Criteria | Destination |
|----------|----------|-------------|
| **READY** | Clear scope, high impact, can start now | → BACKLOG.md "Ready" section |
| **BLOCKED** | Needs info, depends on other work | → BACKLOG.md "Blocked" section |
| **PARK** | Good idea, not now | Leave in OPPORTUNITIES.md |
| **KILL** | Not aligned, low value | Delete from OPPORTUNITIES.md |

**Ready Criteria Checklist:**
- [ ] Clear outcome defined (what does "done" look like?)
- [ ] Size estimated (S/M/L)
- [ ] No blocking dependencies
- [ ] Aligned with current sprint/strategy
- [ ] Someone could pick this up without asking questions

---

## Phase 3: READY QUEUE 📋

**Location:** `process/BACKLOG.md` → "Ready" section

**Structure:**
```markdown
## 🟡 Ready (can be picked up)

### High Priority
| Task | Size | Notes |
|------|------|-------|
| [task] | S/M/L | [context] |

### Medium Priority
| Task | Size | Notes |
|------|------|-------|

### Low Priority
| Task | Size | Notes |
|------|------|-------|
```

**Rules:**
1. High priority = needs to happen this sprint
2. Medium priority = should happen soon
3. Low priority = when there's capacity
4. Agents pick from top-down (high before medium before low)
5. If two agents want the same task, first claim wins

---

## Phase 4: SELF-SERVICE EXECUTION 🤖

**How agents claim work:**

1. **Check the queue:** Read `process/BACKLOG.md`
2. **Pick a task:** Choose from Ready section (respect priority order)
3. **Claim it:** Update STATUS.md with your name + task
4. **Work it:** Do the thing
5. **Complete it:** Move to DONE, update STATUS.md

**Claim Format (in STATUS.md):**
```markdown
## Active Work

| Agent | Task | Started | Status |
|-------|------|---------|--------|
| [Agent] | [Task name] | [Date] | 🟡 In Progress |
```

**No bottleneck rule:** Agents don't need permission to pick up Ready tasks. If it's in Ready, it's fair game.

---

## Phase 5: FEEDBACK LOOP 🔄

**Owner:** Whoever completes the work

**After completing any task:**

1. **Log completion:** Update DONE section with what shipped
2. **Capture learnings:** What did we discover while building?
3. **Spawn opportunities:** Did this work reveal new tasks/problems?

**Feedback Template:**
```markdown
### [Task Name] — Completed YYYY-MM-DD

**What shipped:** [brief description]

**Learnings:**
- [what we learned]

**New opportunities discovered:**
- [any new ideas → add to OPPORTUNITIES.md]
```

**This closes the loop:** Completed work generates new discoveries, which feed back into the top of the funnel.

---

## Ownership Summary

| Phase | Owner | Backup |
|-------|-------|--------|
| Discover | Scout 🔍 | Any agent (opportunistic) |
| Triage | Rhythm 🥁 | Human (strategic decisions) |
| Ready Queue | Self-serve | Rhythm maintains queue health |
| Execute | Assigned agent | Spawn sub-agents as needed |
| Feedback | Completing agent | — |

---

## Anti-Patterns to Avoid

❌ **"[Human] will add it"** — No. Anyone adds to OPPORTUNITIES.md.

❌ **"Waiting for approval"** — No. If it's in Ready, pick it up.

❌ **"I'll remember this idea"** — No. Log it or lose it.

❌ **"This is too small to log"** — No. Small tasks clog brains. Log them.

❌ **"Someone else will notice"** — No. You noticed. You log it.

---

*The system runs itself. Your job is to feed it and trust it.*


path: templates/process/OPPORTUNITIES.md
content: # Opportunities

*Raw discoveries. Anyone can add. Rhythm triages.*

---

## How to Add

```markdown
### [Opportunity Name]
**Discovered:** YYYY-MM-DD
**Source:** [where it came from]
**Description:** [what's the opportunity/problem]
**Suggested action:** [rough idea of what to do]
```

---

## Pending Triage

<!-- Add new discoveries below this line -->



---

## Parked (good ideas, not now)

<!-- Rhythm moves items here during triage -->




path: templates/process/ROLES.md
content: # Team Roles & Ownership

*Who does what. Clear ownership = no bottlenecks.*

---

## Core Roles

### Scout 🔍 — The Discoverer
**Mission:** Find opportunities before they find us.

**Owns:**
- `process/OPPORTUNITIES.md` — keeping it fed with discoveries
- Discovery research (user feedback, competitors, market gaps)
- External monitoring (community channels, social signals)
- Running the DISCOVER phase of the intake loop

**Cadence:**
- Dedicated discovery pass: 2x/week
- Opportunistic: Log anything discovered during other work

**Outputs:**
- New entries in OPPORTUNITIES.md
- Discovery findings docs when deep research is needed

**Does NOT own:**
- Prioritization (that's Rhythm)
- Execution (that's assigned agents)

---

### Rhythm 🥁 — The Backlog Owner
**Mission:** Keep work flowing. Triage ruthlessly.

**Owns:**
- `process/BACKLOG.md` — maintaining queue health
- Triage decisions (what's Ready, what's Blocked, what's Parked)
- Sprint planning
- Queue health (not too full, not empty)

**Cadence:**
- Daily: 5-min scan of OPPORTUNITIES.md
- Sprint boundary: Deep triage session
- Weekly: Queue health check (is Ready section healthy?)

**Triage Power:**
- Can move items to Ready without approval
- Can park/kill low-value items
- Escalates strategic decisions to human lead

**Outputs:**
- Triaged backlog with clear priorities
- Sprint goals
- Triage session logs (optional)

**Does NOT own:**
- Finding opportunities (that's Scout)
- Execution (that's assigned agents)
- Team health (that's Harmony)

---

### Harmony 🤝 — The Facilitator
**Mission:** Keep the team healthy and unblocked.

**Owns:**
- Team health monitoring
- Conflict resolution (when two agents claim same task)
- Retros and process improvements
- Communication health (are status updates happening?)

**Cadence:**
- Continuous: Monitor STATUS.md for stale/stuck work
- Sprint boundary: Facilitate retro
- As-needed: Jump in when conflicts arise

**Powers:**
- Can reassign stuck work
- Can facilitate priority disputes
- Can call for team sync when needed

**Outputs:**
- Unblocked team members
- Process improvement suggestions
- Retro notes (when applicable)

**Does NOT own:**
- Backlog management (that's Rhythm)
- Research (that's Scout)
- Execution (that's assigned agents)

---

## Execution Roles (Spawn as Needed)

### Link 🔗 — The Builder
**Mission:** Ship code. Build things that work.

**Specializes in:**
- Frontend/backend development
- DevOps and deployment
- Technical implementation

**Spawned when:** Development work needs doing

---

### Pixel 🎨 — The Designer
**Mission:** Make it beautiful and usable.

**Specializes in:**
- Visual design
- UX flows
- Brand consistency

**Spawned when:** Design work needs doing

---

### Sage 🦉 — The Architect
**Mission:** Make sure it scales and makes sense.

**Specializes in:**
- System architecture
- Technical decisions
- Code review for structural soundness

**Spawned when:** Architecture decisions needed

---

### Echo 📢 — The Voice
**Mission:** Tell the world what we built.

**Specializes in:**
- Content writing
- Documentation
- Announcements and launches

**Spawned when:** Communication/content work needed

---

### Spark ✨ — The Creative
**Mission:** Make it interesting and memorable.

**Specializes in:**
- Creative direction
- Experience design
- "What if we..." ideas

**Spawned when:** Creative work needed

---

## The Human Lead

### [Your Name] — Strategic Lead
**Role:** Sets direction, makes hard calls, unblocks when system fails.

**DOES:**
- Strategic decisions (what should we be building?)
- Tie-breaker on priority disputes
- Unblock when automation fails
- Spawn new agents when needed

**DOES NOT:**
- Manually add every task to Ready (that's Rhythm's job)
- Be the only source of new ideas (anyone can discover)
- Approve every task pickup (self-serve from Ready)

**When to escalate:**
- Strategic direction unclear
- Major pivot decision
- Resource allocation disputes
- Something broke that the system can't fix

---

## Ownership Matrix

| Process | Primary Owner | Backup |
|---------|---------------|--------|
| Finding opportunities | Scout 🔍 | Anyone (opportunistic) |
| Triage & prioritization | Rhythm 🥁 | Human (strategic) |
| Maintaining Ready queue | Rhythm 🥁 | — |
| Claiming tasks | Self-serve | — |
| Execution | Assigned agent | Sub-agents as needed |
| Unblocking stuck work | Harmony 🤝 | Human |
| Feedback & learning | Completing agent | — |
| Process improvement | Harmony 🤝 | Anyone |
| Strategic direction | Human | — |

---

## Spawning Guidelines

### When to spawn a role:
- Work exists that matches their specialty
- Main agent would context-switch too much
- Parallel work is possible

### When NOT to spawn:
- Task is quick (<10 minutes)
- Task needs back-and-forth with user
- Task needs ongoing conversation context

### Spawn template:
```
Spawn [Role] to: [Clear, scoped task]
Context: [Relevant files/background]
Output: [Expected deliverable]
```

---

## Role Rotation

Roles aren't permanent identities—they're hats. In a small team:

- Main agent might wear Scout hat during discovery
- Main agent might wear Rhythm hat during triage
- Sub-agents get spawned with specific hats for execution

As team grows, roles can become dedicated agents.

---

*Roles exist to clarify ownership, not to create bureaucracy. When in doubt, do the work.*


path: templates/process/STATUS.md
content: # Status

*Who's working on what. Self-updated by agents.*

---

## Active Work

| Agent | Task | Started | Status |
|-------|------|---------|--------|
| | | | |

---

## Status Key

- 🟡 In Progress — Working on it
- 🔴 Blocked — Stuck, needs help
- 🟢 Done — Ready to move to Backlog

---

## Recently Completed

| Agent | Task | Completed |
|-------|------|-----------|
| | | |

---

## Notes

- **Claim format:** Add your row when you pick up a task
- **Update often:** Change status as work progresses
- **Move when done:** Completed work → Backlog Done section


path: _meta.json
content: ownerId: kn76py1tc3spdqaw1mw9aaxs1580e64b
slug: agent-team-kit
version: 1.0.0
publishedAt: 1770237845906

path: agent-team-kit-1.0.0/agents-config-draft.md
content: # Agent Config Draft

## Agents to Rebuild

1. **Scout** 🔍
   - Role: Discovery (find opportunities)
   - Model: anthropic/claude-sonnet-4-5

2. **Sage** 🦉
   - Role: Architecture (from opportunities → specs)
   - Model: anthropic/claude-sonnet-4-5

3. **Pixel** 🎨
   - Role: Design (visuals, branding)
   - Model: anthropic/claude-sonnet-4-5

4. **Link** 🔗
   - Role: Build (code, MVP construction)
   - Model: anthropic/claude-sonnet-4-5

5. **Spark** ✨
   - Role: Distribution (content, announcements)
   - Model: anthropic/claude-sonnet-4-5

6. **Echo** 📝
   - Role: Documentation (write docs, guides, blogs)
   - Model: anthropic/claude-sonnet-4-5

7. **Rhythm** 🥁
   - Role: Backlog/Grooming (ops/triage)
   - Model: anthropic/claude-sonnet-4-5

8. **Harmony** 🤝
   - Role: Health/Morale (team vibes, audits)
   - Model: anthropic/claude-sonnet-4-5

---

## Test Plan
- **Testing sequence:** One at a time
- **Verify model**: Sonnet for all agents
- **Ensure work proceeds:** Use `HEARTBEAT.md` loop tasks to validate role functions

---

## Next Steps
- Enable config for seamless spawning.
- Test roles sequentially (start with Scout, validate tools + outputs).
- Document fixes.

path: agent-team-kit-1.0.0/package.json
content: {
  "name": "agent-team-kit",
  "version": "1.0.0",
  "description": "Self-sustaining process framework for AI agent teams",
  "keywords": [
    "openclaw",
    "agent",
    "team",
    "process",
    "workflow",
    "autonomous",
    "multi-agent"
  ],
  "author": "OpenClaw Community",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/openclaw/agent-team-kit"
  },
  "openclaw": {
    "type": "skill",
    "category": "process",
    "requires": [],
    "provides": [
      "intake-loop",
      "role-definitions",
      "heartbeat-patterns"
    ],
    "files": {
      "skill": "SKILL.md",
      "readme": "README.md",
      "templates": "templates/"
    }
  },
  "files": [
    "SKILL.md",
    "README.md",
    "templates/"
  ]
}


path: agent-team-kit-1.0.0/README.md
content: # Agent Team Kit

[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![OpenClaw Skill](https://img.shields.io/badge/openclaw-skill-purple.svg)](https://github.com/openclaw/openclaw)

**A self-sustaining process framework for AI agent teams.**

Built for [OpenClaw](https://github.com/openclaw/openclaw) but adaptable to any multi-agent setup.

---

## Why This Exists

AI agents working together hit the same problems as human teams:
- Work piles up waiting for one person to triage
- Nobody knows who owns what
- Great ideas get forgotten
- Nothing happens unless someone pushes

This kit solves that with:

✅ **Self-service work queues** — Agents pick tasks without bottlenecks  
✅ **Clear role ownership** — No ambiguity about responsibilities  
✅ **Continuous discovery** — Work flows in automatically  
✅ **Heartbeat-driven operation** — The team runs itself  

---

## The Loop

```
     ┌────────────────────────────────────────────────────┐
     │                                                    │
     ▼                                                    │
┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐ │
│ DISCOVER│───▶│  TRIAGE │───▶│  READY  │───▶│ EXECUTE │─┘
│ Scout 🔍│    │Rhythm 🥁│    │Self-Srv │    │ Agents  │
└─────────┘    └─────────┘    └─────────┘    └─────────┘
                                                   │
                              FEEDBACK ◀───────────┘
```

1. **Discover** — Find opportunities and problems
2. **Triage** — Decide what's ready to work
3. **Ready** — Self-service queue (anyone can pick up)
4. **Execute** — Do the work
5. **Feedback** — Learn, improve, spawn new opportunities

---

## Roles

| Role | Emoji | Mission |
|------|-------|---------|
| Scout | 🔍 | Find opportunities before they find us |
| Rhythm | 🥁 | Keep work flowing, triage ruthlessly |
| Harmony | 🤝 | Keep the team healthy and unblocked |
| Human | 🌊 | Strategic direction, hard calls |

**Execution roles** (spawned as needed): Link 🔗 (build), Pixel 🎨 (design), Sage 🦉 (architecture), Echo 📢 (communication), Spark ✨ (creative)

---

## Installation

### For OpenClaw

```bash
# Clone into your skills directory
git clone https://github.com/reflectt/agent-team-kit skills/agent-team-kit

# Copy templates to your workspace
cp -r skills/agent-team-kit/templates/process ./process
```

### Manual Setup

Copy these files to your workspace:
- `templates/process/INTAKE.md`
- `templates/process/ROLES.md`
- `templates/HEARTBEAT.md`

Create empty process files:
- `process/OPPORTUNITIES.md`
- `process/BACKLOG.md`
- `process/STATUS.md`

---

## Quick Start

1. **Read** `process/INTAKE.md` to understand the loop
2. **Customize** `process/ROLES.md` with your role names
3. **Add** heartbeat checks from `HEARTBEAT.md`
4. **Start discovering** — add first opportunities to `OPPORTUNITIES.md`
5. **Let it run** — the heartbeat keeps the loop spinning

---

## Key Principles

### 1. Self-Service
If work is in the Ready queue, any agent can pick it up. No approval needed. First claim wins.

### 2. Clear Ownership
Every phase has ONE owner. No "shared responsibility" (which means no responsibility).

### 3. Log Everything
Ideas, discoveries, completions — if it's not logged, it didn't happen. Memory is limited; files persist.

### 4. Spawn, Don't Solo
The main agent coordinates. Sub-agents execute. Don't try to do everything in one context.

### 5. Trust the System
Once it's set up, let it run. The heartbeat keeps things moving. Intervene only when something breaks.

---

## File Structure

```
your-workspace/
├── process/
│   ├── INTAKE.md         # The 5-phase loop (reference doc)
│   ├── ROLES.md          # Role definitions
│   ├── OPPORTUNITIES.md  # Raw discoveries (anyone adds)
│   ├── BACKLOG.md        # Triaged work queue
│   └── STATUS.md         # Current activity
├── HEARTBEAT.md          # Proactive operation triggers
└── skills/
    └── agent-team-kit/   # This skill
```

---

## Customization

The kit is designed to be adapted:

- **Rename roles** to fit your domain (Scout → Researcher, Link → Developer)
- **Add specialized roles** for your work type
- **Adjust cadences** based on your team's rhythm
- **Modify the loop** — add gates, split phases, whatever works

See `SKILL.md` for detailed customization instructions.

---

## Anti-Patterns

These kill autonomous teams:

| ❌ Don't | ✅ Do Instead |
|----------|---------------|
| Human adds every task | Rhythm triages, anyone discovers |
| Wait for approval | Ready = fair game |
| One agent does everything | Spawn specialists |
| Keep ideas in your head | Log to OPPORTUNITIES.md |
| Heartbeat just returns OK | Actually check the loop |

---

## Contributing

PRs welcome. This framework evolved from real multi-agent team operation.

Especially interested in:
- Adaptations for different domains
- Additional role templates
- Metrics and observability patterns
- Integration with other agent frameworks

---

## Related Kits

Part of the Reflectt agent kit family:

- **[agent-memory-kit](https://github.com/reflectt/agent-memory-kit)** — Structured memory patterns for persistent agent context
- **[agent-autonomy-kit](https://github.com/reflectt/agent-autonomy-kit)** — Self-directed operation via heartbeats, cron, and proactive behavior

These kits work great together — memory for continuity, autonomy for self-operation, and team for coordination.

---

## License

MIT — use it, fork it, adapt it.

---

*Built with 📝 by teams that got tired of being bottlenecks.*


path: agent-team-kit-1.0.0/templates/HEARTBEAT.md
content: # HEARTBEAT.md — Team Operations

## Autonomous Team Operations

Heartbeat = keep the team running. NOT "check and chill." Spawn agents, keep work flowing.

### 1. Human First (always)

- [ ] Human messages waiting? → Handle immediately
- [ ] Direct request? → Respond or delegate

### 2. Check Task Queue (`tasks/QUEUE.md`)

- [ ] Any Critical/High priority tasks in Ready?
- [ ] If yes → spawn agent for top task (queue takes priority over discovery loop)
- [ ] Queue tasks = explicit work. Loop tasks = generative work. Explicit > generative.

### 4. Run the Intake Loop (if queue empty)

**Discovery:** Is Scout finding opportunities?
- Check `process/OPPORTUNITIES.md` last modified
- If stale (>4 hours) or empty → spawn Scout to discover

**Triage:** Is Rhythm processing the backlog?
- Check `process/BACKLOG.md` Ready section
- If opportunities sitting untriaged → spawn Rhythm to triage

**Execution:** Is work getting done?
- Check `process/BACKLOG.md` Ready section
- If tasks sitting >2 hours → spawn appropriate agent (Link for dev, Pixel for design, etc.)

### 5. Health Checks

- [ ] Any blockers that need escalation?
- [ ] Any agents stuck or erroring?
- [ ] Status files reflect reality?

### 6. Keep State Updated

- [ ] `process/STATUS.md` — accurate?
- [ ] `process/BACKLOG.md` — queue healthy (5-15 items in Ready)?

### 7. Log Activity

- [ ] Update `memory/YYYY-MM-DD.md` with what happened

---

## The Rule

**If the team isn't working, spawn them.**

Don't do the work yourself. Don't just say HEARTBEAT_OK. Check the loop, spawn agents, keep it moving.

You're the coordinator. The team does the work. Your job is to make sure they're working.

---

## Spawn Quick Reference

| Situation | Spawn |
|-----------|-------|
| No new opportunities in 4h | Scout 🔍 |
| Untriaged items piling up | Rhythm 🥁 |
| Work stuck, needs unblocking | Harmony 🤝 |
| Dev task ready | Link 🔗 |
| Design task ready | Pixel 🎨 |
| Architecture decision needed | Sage 🦉 |
| Content/comms task ready | Echo 📢 |
| Creative task ready | Spark ✨ |

---

## ❌ Anti-Patterns (Don't Do This)

| Bad | Why | Fix |
|-----|-----|-----|
| Return HEARTBEAT_OK without checking | Loop dies silently | Actually run the checklist |
| Do the work yourself instead of spawning | You become the bottleneck | Spawn specialists |
| Ask "what's next?" | That's the team's job to figure out | Check backlog, spawn who's needed |
| Wait for human direction | Defeats autonomy | Execute from Ready queue |
| Spawn and forget | Work may stall | Monitor running agents, follow up |

**The test:** If YOU are doing the work instead of coordinating agents, you're in Task Dispatcher mode. Stop. Spawn. Coordinate.

---

*Idle team = broken autonomy. Fix it.*


path: agent-team-kit-1.0.0/templates/process/BACKLOG.md
content: # Backlog

*Triaged work queue. Self-service from Ready.*

---

## 🟡 Ready (can be picked up)

### High Priority
| Task | Size | Notes |
|------|------|-------|
| | | |

### Medium Priority
| Task | Size | Notes |
|------|------|-------|
| | | |

### Low Priority
| Task | Size | Notes |
|------|------|-------|
| | | |

---

## 🔴 Blocked

| Task | Blocker | Owner |
|------|---------|-------|
| | | |

---

## ✅ Done (this sprint)

| Task | Completed | Agent |
|------|-----------|-------|
| | | |

---

## Notes

- **Ready = fair game** — Any agent can claim without approval
- **Pick top-down** — High priority before medium before low
- **First claim wins** — If conflict, whoever claimed first keeps it
- **Size guide** — S (<1h), M (1-4h), L (4h+)


path: agent-team-kit-1.0.0/templates/process/INTAKE.md
content: # Intake Process: How Work Flows

*The self-sustaining loop that keeps work moving without bottlenecks.*

---

## The Problem We're Solving

Before: One person manually added tasks. Ideas sat in parking lots. Nothing moved unless someone pushed it.

After: A self-sustaining system where work flows continuously and agents can self-serve.

---

## The Intake Loop

```
     ┌─────────────────────────────────────────────────────────┐
     │                                                         │
     ▼                                                         │
┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐      │
│ DISCOVER│───▶│  TRIAGE │───▶│  READY  │───▶│ EXECUTE │──────┘
│         │    │         │    │         │    │         │
│ Scout 🔍│    │Rhythm 🥁│    │Self-Srv │    │ Agents  │
└─────────┘    └─────────┘    └─────────┘    └─────────┘
     ▲                                              │
     │              Feedback Loop                   │
     └──────────────────────────────────────────────┘
```

---

## Phase 1: DISCOVER 🔍

**Owner:** Scout (or any agent who finds something)

**Sources of work:**
- User feedback (community channels, DMs, emails)
- Research findings (gaps, competitors, market shifts)
- Build failures (bugs, broken things, tech debt)
- Shipped work retrospectives (what should we improve?)
- External signals (social mentions, community requests)
- Internal signals (heartbeat checks, monitoring alerts)

**Output:** Raw ideas logged to `process/OPPORTUNITIES.md`

**Format for new entries:**
```markdown
### [Opportunity Name]
**Discovered:** YYYY-MM-DD
**Source:** [where it came from]
**Description:** [what's the opportunity/problem]
**Suggested action:** [rough idea of what to do]
```

**Who can add:** ANYONE. Discovery is open. If you see something, log it.

**Cadence:** 
- Scout does a dedicated discovery pass 2x/week
- Anyone adds opportunistically when they encounter things

---

## Phase 2: TRIAGE 🥁

**Owner:** Rhythm (Backlog Owner)

**When:** 
- Daily quick scan (5 min, async)
- Deep triage session at sprint boundaries

**The Triage Decision:**

For each item in OPPORTUNITIES.md, decide:

| Decision | Criteria | Destination |
|----------|----------|-------------|
| **READY** | Clear scope, high impact, can start now | → BACKLOG.md "Ready" section |
| **BLOCKED** | Needs info, depends on other work | → BACKLOG.md "Blocked" section |
| **PARK** | Good idea, not now | Leave in OPPORTUNITIES.md |
| **KILL** | Not aligned, low value | Delete from OPPORTUNITIES.md |

**Ready Criteria Checklist:**
- [ ] Clear outcome defined (what does "done" look like?)
- [ ] Size estimated (S/M/L)
- [ ] No blocking dependencies
- [ ] Aligned with current sprint/strategy
- [ ] Someone could pick this up without asking questions

---

## Phase 3: READY QUEUE 📋

**Location:** `process/BACKLOG.md` → "Ready" section

**Structure:**
```markdown
## 🟡 Ready (can be picked up)

### High Priority
| Task | Size | Notes |
|------|------|-------|
| [task] | S/M/L | [context] |

### Medium Priority
| Task | Size | Notes |
|------|------|-------|

### Low Priority
| Task | Size | Notes |
|------|------|-------|
```

**Rules:**
1. High priority = needs to happen this sprint
2. Medium priority = should happen soon
3. Low priority = when there's capacity
4. Agents pick from top-down (high before medium before low)
5. If two agents want the same task, first claim wins

---

## Phase 4: SELF-SERVICE EXECUTION 🤖

**How agents claim work:**

1. **Check the queue:** Read `process/BACKLOG.md`
2. **Pick a task:** Choose from Ready section (respect priority order)
3. **Claim it:** Update STATUS.md with your name + task
4. **Work it:** Do the thing
5. **Complete it:** Move to DONE, update STATUS.md

**Claim Format (in STATUS.md):**
```markdown
## Active Work

| Agent | Task | Started | Status |
|-------|------|---------|--------|
| [Agent] | [Task name] | [Date] | 🟡 In Progress |
```

**No bottleneck rule:** Agents don't need permission to pick up Ready tasks. If it's in Ready, it's fair game.

---

## Phase 5: FEEDBACK LOOP 🔄

**Owner:** Whoever completes the work

**After completing any task:**

1. **Log completion:** Update DONE section with what shipped
2. **Capture learnings:** What did we discover while building?
3. **Spawn opportunities:** Did this work reveal new tasks/problems?

**Feedback Template:**
```markdown
### [Task Name] — Completed YYYY-MM-DD

**What shipped:** [brief description]

**Learnings:**
- [what we learned]

**New opportunities discovered:**
- [any new ideas → add to OPPORTUNITIES.md]
```

**This closes the loop:** Completed work generates new discoveries, which feed back into the top of the funnel.

---

## Ownership Summary

| Phase | Owner | Backup |
|-------|-------|--------|
| Discover | Scout 🔍 | Any agent (opportunistic) |
| Triage | Rhythm 🥁 | Human (strategic decisions) |
| Ready Queue | Self-serve | Rhythm maintains queue health |
| Execute | Assigned agent | Spawn sub-agents as needed |
| Feedback | Completing agent | — |

---

## Anti-Patterns to Avoid

❌ **"[Human] will add it"** — No. Anyone adds to OPPORTUNITIES.md.

❌ **"Waiting for approval"** — No. If it's in Ready, pick it up.

❌ **"I'll remember this idea"** — No. Log it or lose it.

❌ **"This is too small to log"** — No. Small tasks clog brains. Log them.

❌ **"Someone else will notice"** — No. You noticed. You log it.

---

*The system runs itself. Your job is to feed it and trust it.*


path: agent-team-kit-1.0.0/templates/process/OPPORTUNITIES.md
content: # Opportunities

*Raw discoveries. Anyone can add. Rhythm triages.*

---

## How to Add

```markdown
### [Opportunity Name]
**Discovered:** YYYY-MM-DD
**Source:** [where it came from]
**Description:** [what's the opportunity/problem]
**Suggested action:** [rough idea of what to do]
```

---

## Pending Triage

<!-- Add new discoveries below this line -->



---

## Parked (good ideas, not now)

<!-- Rhythm moves items here during triage -->




path: agent-team-kit-1.0.0/templates/process/ROLES.md
content: # Team Roles & Ownership

*Who does what. Clear ownership = no bottlenecks.*

---

## Core Roles

### Scout 🔍 — The Discoverer
**Mission:** Find opportunities before they find us.

**Owns:**
- `process/OPPORTUNITIES.md` — keeping it fed with discoveries
- Discovery research (user feedback, competitors, market gaps)
- External monitoring (community channels, social signals)
- Running the DISCOVER phase of the intake loop

**Cadence:**
- Dedicated discovery pass: 2x/week
- Opportunistic: Log anything discovered during other work

**Outputs:**
- New entries in OPPORTUNITIES.md
- Discovery findings docs when deep research is needed

**Does NOT own:**
- Prioritization (that's Rhythm)
- Execution (that's assigned agents)

---

### Rhythm 🥁 — The Backlog Owner
**Mission:** Keep work flowing. Triage ruthlessly.

**Owns:**
- `process/BACKLOG.md` — maintaining queue health
- Triage decisions (what's Ready, what's Blocked, what's Parked)
- Sprint planning
- Queue health (not too full, not empty)

**Cadence:**
- Daily: 5-min scan of OPPORTUNITIES.md
- Sprint boundary: Deep triage session
- Weekly: Queue health check (is Ready section healthy?)

**Triage Power:**
- Can move items to Ready without approval
- Can park/kill low-value items
- Escalates strategic decisions to human lead

**Outputs:**
- Triaged backlog with clear priorities
- Sprint goals
- Triage session logs (optional)

**Does NOT own:**
- Finding opportunities (that's Scout)
- Execution (that's assigned agents)
- Team health (that's Harmony)

---

### Harmony 🤝 — The Facilitator
**Mission:** Keep the team healthy and unblocked.

**Owns:**
- Team health monitoring
- Conflict resolution (when two agents claim same task)
- Retros and process improvements
- Communication health (are status updates happening?)

**Cadence:**
- Continuous: Monitor STATUS.md for stale/stuck work
- Sprint boundary: Facilitate retro
- As-needed: Jump in when conflicts arise

**Powers:**
- Can reassign stuck work
- Can facilitate priority disputes
- Can call for team sync when needed

**Outputs:**
- Unblocked team members
- Process improvement suggestions
- Retro notes (when applicable)

**Does NOT own:**
- Backlog management (that's Rhythm)
- Research (that's Scout)
- Execution (that's assigned agents)

---

## Execution Roles (Spawn as Needed)

### Link 🔗 — The Builder
**Mission:** Ship code. Build things that work.

**Specializes in:**
- Frontend/backend development
- DevOps and deployment
- Technical implementation

**Spawned when:** Development work needs doing

---

### Pixel 🎨 — The Designer
**Mission:** Make it beautiful and usable.

**Specializes in:**
- Visual design
- UX flows
- Brand consistency

**Spawned when:** Design work needs doing

---

### Sage 🦉 — The Architect
**Mission:** Make sure it scales and makes sense.

**Specializes in:**
- System architecture
- Technical decisions
- Code review for structural soundness

**Spawned when:** Architecture decisions needed

---

### Echo 📢 — The Voice
**Mission:** Tell the world what we built.

**Specializes in:**
- Content writing
- Documentation
- Announcements and launches

**Spawned when:** Communication/content work needed

---

### Spark ✨ — The Creative
**Mission:** Make it interesting and memorable.

**Specializes in:**
- Creative direction
- Experience design
- "What if we..." ideas

**Spawned when:** Creative work needed

---

## The Human Lead

### [Your Name] — Strategic Lead
**Role:** Sets direction, makes hard calls, unblocks when system fails.

**DOES:**
- Strategic decisions (what should we be building?)
- Tie-breaker on priority disputes
- Unblock when automation fails
- Spawn new agents when needed

**DOES NOT:**
- Manually add every task to Ready (that's Rhythm's job)
- Be the only source of new ideas (anyone can discover)
- Approve every task pickup (self-serve from Ready)

**When to escalate:**
- Strategic direction unclear
- Major pivot decision
- Resource allocation disputes
- Something broke that the system can't fix

---

## Ownership Matrix

| Process | Primary Owner | Backup |
|---------|---------------|--------|
| Finding opportunities | Scout 🔍 | Anyone (opportunistic) |
| Triage & prioritization | Rhythm 🥁 | Human (strategic) |
| Maintaining Ready queue | Rhythm 🥁 | — |
| Claiming tasks | Self-serve | — |
| Execution | Assigned agent | Sub-agents as needed |
| Unblocking stuck work | Harmony 🤝 | Human |
| Feedback & learning | Completing agent | — |
| Process improvement | Harmony 🤝 | Anyone |
| Strategic direction | Human | — |

---

## Spawning Guidelines

### When to spawn a role:
- Work exists that matches their specialty
- Main agent would context-switch too much
- Parallel work is possible

### When NOT to spawn:
- Task is quick (<10 minutes)
- Task needs back-and-forth with user
- Task needs ongoing conversation context

### Spawn template:
```
Spawn [Role] to: [Clear, scoped task]
Context: [Relevant files/background]
Output: [Expected deliverable]
```

---

## Role Rotation

Roles aren't permanent identities—they're hats. In a small team:

- Main agent might wear Scout hat during discovery
- Main agent might wear Rhythm hat during triage
- Sub-agents get spawned with specific hats for execution

As team grows, roles can become dedicated agents.

---

*Roles exist to clarify ownership, not to create bureaucracy. When in doubt, do the work.*


path: agent-team-kit-1.0.0/templates/process/STATUS.md
content: # Status

*Who's working on what. Self-updated by agents.*

---

## Active Work

| Agent | Task | Started | Status |
|-------|------|---------|--------|
| | | | |

---

## Status Key

- 🟡 In Progress — Working on it
- 🔴 Blocked — Stuck, needs help
- 🟢 Done — Ready to move to Backlog

---

## Recently Completed

| Agent | Task | Completed |
|-------|------|-----------|
| | | |

---

## Notes

- **Claim format:** Add your row when you pick up a task
- **Update often:** Change status as work progresses
- **Move when done:** Completed work → Backlog Done section


path: agent-team-kit-1.0.0/_meta.json
content: ownerId: kn76py1tc3spdqaw1mw9aaxs1580e64b
slug: agent-team-kit
version: 1.0.0
publishedAt: 1770237845906

path: automation-workflows-0.1.0/_meta.json
content: ownerId: kn732qfbv22he1jqm63xbwq6e980kn8s
slug: automation-workflows
version: 0.1.0
publishedAt: 1770341582349

path: background-removal-0.1.0/_meta.json
content: ownerId: kn7c1hgfycdfnrf5w8mp3pf1jd808pjv
slug: background-removal
version: 0.1.0
publishedAt: 1770363182554

path: brainrepo-1.0.0/assets/templates/daily.md
content: ---
created: {{date}}
tags: [journal]
---

# {{date}}

## Captured Today

- Item 1
- Item 2

## Progress

- [[Projects/project-name/index|Project]]: What was done

## Tasks Completed

- [x] Task 1
- [x] Task 2

## Reflections

Optional thoughts about the day.


path: brainrepo-1.0.0/assets/templates/note.md
content: ---
created: {{date}}
tags: []
related: []
---

# {{Note Title}}

## Summary

One-paragraph summary of the concept.

## Details

Main content here. Explain the idea fully.

## Examples

- Example 1
- Example 2

## Related

- [[Notes/related-concept]]
- [[Resources/source-material]]

## Sources

- [Source](url)


path: brainrepo-1.0.0/assets/templates/person.md
content: ---
created: {{date}}
tags: [person]
related: []
---

# {{Person Name}}

Brief description of who they are.

## Relationship

- **Met:** Where/how you met
- **Role:** What they do
- **Context:** Professional/personal relationship

## Contact

- **Email:** 
- **Phone:** 
- **LinkedIn:** 
- **Twitter:** 

## Notes

Key things to remember about this person.

## Interaction Log

### {{date}}
- Initial contact/meeting


path: brainrepo-1.0.0/assets/templates/project.md
content: ---
created: {{date}}
status: active
deadline: 
tags: [project]
related: []
---

# {{Project Name}}

## Overview

Brief description of what this project is about.

## Goals

- [ ] Goal 1
- [ ] Goal 2
- [ ] Goal 3

## Key People

- [[People/person-name]] — Role

## Status

**Current:** Just started

**Next Actions:**
- [ ] First action item

## Resources

- [Link](url) — Description

## Log

### {{date}}
- Project created


path: brainrepo-1.0.0/assets/templates/resource.md
content: ---
created: {{date}}
tags: [resource]
source: {{url}}
related: []
---

# {{Title}}

**Source:** [Original]({{url}})

## Why It's Useful

Why you saved this and when to reference it.

## Key Takeaways

1. First key point
2. Second key point
3. Third key point

## Quotes

> Notable quote from the source

## Related

- [[Notes/related-concept]]
- [[Projects/relevant-project/index]]


path: brainrepo-1.0.0/references/structure.md
content: # BrainRepo Structure Guide

Detailed breakdown of every folder and when to use it.

## Directory Tree

```
brainrepo/
│
├── Inbox/                          # Temporary capture zone
│   └── *.md                        # Unprocessed notes (clear daily)
│
├── Projects/                       # Active work with deadlines
│   └── <project-name>/
│       ├── index.md               # Project overview & status
│       ├── meetings/              # Meeting notes
│       └── *.md                   # Project-specific notes
│
├── Areas/                          # Ongoing responsibilities
│   ├── personal-growth/
│   │   ├── index.md              # Overview, current goals
│   │   ├── health.md             # Fitness, nutrition, medical
│   │   ├── habits.md             # Habit tracking
│   │   ├── learning.md           # Courses, books, skills
│   │   └── career.md             # Career goals, development
│   ├── family/
│   │   ├── index.md              # Overview
│   │   ├── important-dates.md    # Birthdays, anniversaries
│   │   └── traditions.md         # Family rituals
│   └── <area-name>/
│       └── *.md
│
├── Notes/                          # Atomic knowledge (Zettelkasten)
│   └── <note-name>.md             # One idea per note
│
├── Resources/                      # External references
│   ├── articles/                  # Saved articles
│   ├── books/                     # Book notes
│   ├── tools/                     # Tool documentation
│   └── *.md                       # General resources
│
├── Journal/                        # Daily notes
│   └── YYYY-MM-DD.md              # One file per day
│
├── People/                         # Relationship tracking
│   └── <firstname-lastname>.md    # One file per person
│
├── Tasks/                          # Task management
│   └── index.md                   # All tasks, linked to projects
│
└── Archive/                        # Completed/inactive items
    ├── projects/                  # Archived projects
    └── areas/                     # Archived areas
```

## Folder Details

### Inbox/

**Purpose:** Quick capture without friction. Brain dump zone.

**Rules:**
- Anything goes here first
- No organization required
- Clear DAILY during evening processing
- If something sits >3 days, either process or delete

**Example files:**
- `random-thought-2026-02-04.md`
- `meeting-note-quick.md`
- `idea-for-later.md`

---

### Projects/

**Purpose:** Active work with specific outcomes and deadlines.

**Rules:**
- Each project gets its own folder
- Must have an `index.md` with overview
- Move to Archive/ when complete
- Link to relevant People/ and Notes/

**When to create a project:**
- Has a clear deliverable
- Has a deadline (even if fuzzy)
- Requires multiple actions
- Will eventually be "done"

**Example structure:**
```
Projects/
├── website-redesign/
│   ├── index.md          # Goals, status, timeline
│   ├── requirements.md   # Specs
│   └── meetings/
│       └── 2026-02-04.md
└── book-writing/
    ├── index.md
    ├── outline.md
    └── chapters/
```

---

### Areas/

**Purpose:** Ongoing responsibilities without deadlines.

**Rules:**
- Maintained forever, never "complete"
- Standards to uphold, not goals to achieve
- Review monthly for neglected areas
- Keep minimal — don't over-create

**Core Areas (recommended):**
- `personal-growth/` — health, learning, habits, career
- `family/` — relationships, important dates

**When to create an area:**
- Ongoing responsibility
- No end date
- Regular attention needed
- Not a project (no deliverable)

---

### Notes/

**Purpose:** Permanent atomic knowledge. Zettelkasten-style.

**Rules:**
- One idea per note
- Heavily linked with `[[wikilinks]]`
- Evergreen — update as knowledge grows
- Not project-specific (that goes in Projects/)

**Good for:**
- Concepts and mental models
- Lessons learned
- Frameworks and methodologies
- Insights that apply broadly

**Example notes:**
- `compound-interest.md`
- `negotiation-tactics.md`
- `startup-lessons.md`
- `writing-tips.md`

---

### Resources/

**Purpose:** External content worth saving.

**Rules:**
- Always include source URL
- Add why it's valuable
- Summarize key points
- Can be organized in subfolders

**Subfolders:**
- `articles/` — saved articles
- `books/` — book notes & highlights
- `tools/` — software & tool docs
- `courses/` — course notes

---

### Journal/

**Purpose:** Daily chronological record.

**Rules:**
- One file per day: `YYYY-MM-DD.md`
- Created during evening processing
- Links to what was captured/processed
- Personal reflections optional

**Template:**
```markdown
---
created: YYYY-MM-DD
tags: [journal]
---

# YYYY-MM-DD

## Captured Today
- [[Inbox/idea-x]] → moved to [[Notes/concept]]
- New person: [[People/john-doe]]

## Progress
- [[Projects/website/index|Website]]: Finished homepage

## Reflections
Optional thoughts about the day.
```

---

### People/

**Purpose:** Track relationships and interactions.

**Rules:**
- One file per person: `firstname-lastname.md`
- Record how you met, context
- Log significant interactions
- Link to shared projects

**Template:**
```markdown
---
created: YYYY-MM-DD
tags: [person, colleague]
related: ["[[Projects/acme/index|ACME]]"]
---

# John Doe

Brief description of who they are.

## Relationship
- **Met:** Where/when
- **Role:** What they do
- **Context:** How you know them

## Interaction Log

### YYYY-MM-DD
- Topic discussed
- Follow-up needed
```

---

### Tasks/

**Purpose:** Centralized task tracking.

**Rules:**
- Main file: `index.md`
- Tasks linked to projects where relevant
- Use `- [ ]` checkbox format
- Review weekly

**Format:**
```markdown
# Tasks

## Inbox (Unsorted)
- [ ] Random task

## By Project
### [[Projects/website/index|Website]]
- [ ] Design homepage
- [x] Set up hosting

## Waiting For
- [ ] Response from John about X
```

---

### Archive/

**Purpose:** Completed or inactive items.

**Rules:**
- Move completed projects here
- Maintains history without clutter
- Can search when needed
- Subfolders mirror active structure

## Decision Tree

```
New information arrives
│
├─ Is it about an active project?
│  YES → Projects/<project>/
│
├─ Is it about a person?
│  YES → People/<person>.md
│
├─ Is it about personal growth (health, habits, learning, career)?
│  YES → Areas/personal-growth/
│
├─ Is it about family?
│  YES → Areas/family/
│
├─ Is it a task/todo?
│  YES → Tasks/index.md (+ project link if relevant)
│
├─ Is it external content (article, link)?
│  YES → Resources/
│
├─ Is it reusable knowledge (concept, lesson)?
│  YES → Notes/
│
├─ Is it a daily reflection?
│  YES → Journal/YYYY-MM-DD.md
│
└─ Not sure?
   → Inbox/ (process later)
```


path: brainrepo-1.0.0/references/workflows.md
content: # BrainRepo Workflows

Step-by-step guides for common operations.

## Daily Workflow

### Morning Start (Optional, 2 min)

1. Open `Tasks/index.md`
2. Review today's priorities
3. Check yesterday's `Journal/` for context

### During the Day

**Rule: Don't organize, just capture.**

When something comes up:
1. Create note in `Inbox/` or tell AI: "Save this: [content]"
2. Don't think about where it goes
3. Move on with your day

### Evening Processing (5-10 min)

**Goal: Empty Inbox/, update Journal/**

```
For each item in Inbox/:
│
├─ Is it actionable?
│  ├─ YES, for a project → Move to Projects/<project>/
│  ├─ YES, standalone task → Add to Tasks/index.md
│  └─ NO → Continue below
│
├─ Is it reference material?
│  ├─ About a person → Move to People/
│  ├─ External content → Move to Resources/
│  ├─ Reusable knowledge → Move to Notes/
│  └─ Area-related → Move to Areas/<area>/
│
├─ Is it worth keeping?
│  ├─ YES → Move to appropriate location
│  └─ NO → Delete it
│
└─ Still not sure?
   → Leave in Inbox/ for tomorrow (max 3 days)
```

After processing:
1. Create/update `Journal/YYYY-MM-DD.md`
2. Commit: `git add -A && git commit -m "daily: $(date +%Y-%m-%d)"`
3. Push: `git push`

---

## Weekly Review (Sunday, 15-20 min)

### 1. Get Clear (5 min)

- [ ] Process all remaining Inbox items
- [ ] Review Tasks/index.md — update statuses
- [ ] Check calendar for upcoming commitments

### 2. Get Current (5 min)

**Projects:**
- [ ] Review each project in Projects/
- [ ] Update status in each index.md
- [ ] Archive completed projects

**Areas:**
- [ ] Scan Areas/ — anything neglected?
- [ ] Any area needs more attention this week?

### 3. Get Creative (5 min)

- [ ] Review Notes/ — any new connections?
- [ ] Any ideas for new projects?
- [ ] Update priorities for next week

### 4. Commit

```bash
git add -A
git commit -m "weekly review: $(date +%Y-%m-%d)"
git push
```

---

## Monthly Review (1st of month, 30 min)

### Review

- [ ] Read through last month's Journal/ entries
- [ ] Celebrate wins
- [ ] Note lessons learned

### Maintain

- [ ] Archive stale projects (no activity >30 days)
- [ ] Review People/ — anyone to follow up with?
- [ ] Clean up Resources/ — still relevant?

### Plan

- [ ] Set 1-3 focus areas for the month
- [ ] Create new projects if needed
- [ ] Update Areas/ goals

---

## Capture Workflows

### Quick Thought Capture

```
You: "Save this: [thought]"
AI: Creates Inbox/thought-YYYY-MM-DD-HHMM.md
```

### New Project

```
You: "New project: [name]"
AI: 
  1. Creates Projects/<name>/
  2. Creates Projects/<name>/index.md with template
  3. Optionally links to People/ and Notes/
```

**Project index.md template:**
```markdown
---
created: YYYY-MM-DD
status: active
deadline: YYYY-MM-DD
tags: [project]
related: []
---

# Project Name

## Overview
What this project is about.

## Goals
- [ ] Goal 1
- [ ] Goal 2

## Status
Current status and next actions.

## Log
### YYYY-MM-DD
- Created project
```

### New Person

```
You: "Add person: [name], [context]"
AI:
  1. Creates People/<name>.md
  2. Fills template with context
  3. Links to relevant projects
```

### Save Link/Article

```
You: "Save this link: [URL] - [why it's useful]"
AI:
  1. Creates Resources/articles/<title>.md
  2. Includes URL, summary, and your note
```

---

## Search & Retrieval

### Find by Topic

```
You: "What do I know about [topic]?"
AI:
  1. Searches Notes/, Projects/, Resources/
  2. Returns relevant excerpts
  3. Shows connections
```

### Find by Person

```
You: "What's my history with [person]?"
AI:
  1. Reads People/<person>.md
  2. Finds mentions in Journal/, Projects/
  3. Summarizes relationship
```

### Find by Date Range

```
You: "What did I capture last week?"
AI:
  1. Reads Journal/ for date range
  2. Lists items processed
  3. Summarizes activity
```

---

## Git Workflows

### Daily Commit

```bash
git add -A
git commit -m "daily: $(date +%Y-%m-%d)"
git push
```

### After Specific Changes

```bash
# New project
git commit -m "add: project [name]"

# New person
git commit -m "add: person [name]"

# Processing
git commit -m "process: inbox"

# Review
git commit -m "review: weekly"
```

### Sync Across Devices

```bash
# Before starting work
git pull

# After finishing work
git add -A && git commit -m "sync" && git push
```

---

## Linking Best Practices

### Within Notes

```markdown
This relates to [[Notes/concept-name]].
See also [[Notes/another-concept]].
```

### To People

```markdown
Discussed with [[People/john-doe]].
Team: [[People/jane-smith]], [[People/bob-wilson]]
```

### To Projects

```markdown
Part of [[Projects/website/index|Website Redesign]].
Backlog for [[Projects/mobile-app/index|Mobile App]].
```

### In Journal

```markdown
## Today's Progress
- [[Projects/website/index|Website]]: Finished header
- Met with [[People/john-doe]] about launch
- New insight: [[Notes/user-onboarding]]
```

---

## Maintenance Workflows

### Archive a Project

1. Move `Projects/<name>/` to `Archive/projects/<name>/`
2. Update any links pointing to it
3. Commit: `git commit -m "archive: project [name]"`

### Merge Duplicate Notes

1. Identify duplicates in Notes/
2. Combine content into one note
3. Update links to point to merged note
4. Delete duplicate
5. Commit

### Clean Stale Resources

1. Review Resources/ quarterly
2. Delete irrelevant items
3. Update or archive outdated content
4. Commit: `git commit -m "cleanup: resources"`


path: brainrepo-1.0.0/_meta.json
content: ownerId: kn7577c4dmma15j8j677h0sjyd80g2cj
slug: brainrepo
version: 1.0.0
publishedAt: 1770222875327

path: business-model-canvas-0.1.0/_meta.json
content: ownerId: kn732qfbv22he1jqm63xbwq6e980kn8s
slug: business-model-canvas
version: 0.1.0
publishedAt: 1770341750447

path: data-analyst-1.0.0/scripts/data-init.sh
content: #!/bin/bash
# data-init.sh - Initialize data analysis workspace
# Usage: ./data-init.sh

DATA_DIR="${HOME}/.openclaw/workspace/data-analysis"

echo "🚀 Initializing Data Analysis Workspace"
echo "======================================="

# Create directory structure
mkdir -p "$DATA_DIR"/{data,queries,reports,notebooks,scripts}

# Create queries directory with common patterns
cat > "$DATA_DIR/queries/README.md" << 'EOF'
# SQL Queries

Store reusable SQL queries here.

## Naming Convention
- `daily-<name>.sql` - Daily reports
- `weekly-<name>.sql` - Weekly reports
- `adhoc-<name>.sql` - One-off queries
- `template-<name>.sql` - Reusable templates
EOF

cat > "$DATA_DIR/queries/template-exploration.sql" << 'EOF'
-- Data Exploration Template
-- Replace TABLE_NAME with your table

-- Row count
SELECT COUNT(*) as total_rows FROM TABLE_NAME;

-- Sample data
SELECT * FROM TABLE_NAME LIMIT 10;

-- Column overview (PostgreSQL)
-- SELECT column_name, data_type, is_nullable 
-- FROM information_schema.columns 
-- WHERE table_name = 'TABLE_NAME';

-- Null analysis
-- SELECT 
--     COUNT(*) as total,
--     SUM(CASE WHEN column_name IS NULL THEN 1 ELSE 0 END) as nulls,
--     ROUND(SUM(CASE WHEN column_name IS NULL THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) as null_pct
-- FROM TABLE_NAME;
EOF

# Create report templates
cat > "$DATA_DIR/reports/README.md" << 'EOF'
# Reports Directory

Generated reports go here.

## Report Types
- `weekly-YYYY-MM-DD.md` - Weekly analytics
- `monthly-YYYY-MM.md` - Monthly summaries
- `adhoc-<name>.md` - One-off analyses
EOF

cat > "$DATA_DIR/reports/template-analysis.md" << 'EOF'
# Analysis Report: [Title]

**Date:** [Date]
**Author:** [Name]
**Status:** Draft

## Executive Summary
[2-3 sentences with key findings]

## Question
[What are we trying to answer?]

## Data Sources
- [Source 1]: [Description]
- [Source 2]: [Description]

## Methodology
[How we approached the analysis]

## Findings

### Key Metrics
| Metric | Value | Change | Notes |
|--------|-------|--------|-------|
| | | | |

### Insights
1. **[Insight]**: [Supporting evidence]
2. **[Insight]**: [Supporting evidence]

## Visualizations
[Insert charts/graphs]

## Recommendations
1. [Action to take]
2. [Action to take]

## Appendix
[Supporting data tables, SQL queries used]
EOF

# Create Python analysis template
cat > "$DATA_DIR/scripts/analyze_template.py" << 'EOF'
#!/usr/bin/env python3
"""
Data Analysis Template
Usage: python analyze_template.py --input <file.csv>
"""

import pandas as pd
import argparse
from datetime import datetime

def load_data(filepath):
    """Load data from CSV or Excel."""
    if filepath.endswith('.csv'):
        return pd.read_csv(filepath)
    elif filepath.endswith(('.xlsx', '.xls')):
        return pd.read_excel(filepath)
    else:
        raise ValueError(f"Unsupported file type: {filepath}")

def explore_data(df):
    """Basic data exploration."""
    print("\n=== DATA OVERVIEW ===")
    print(f"Shape: {df.shape[0]} rows, {df.shape[1]} columns")
    print(f"\nColumn Types:\n{df.dtypes}")
    print(f"\nMissing Values:\n{df.isnull().sum()}")
    print(f"\nBasic Statistics:\n{df.describe()}")
    return df

def clean_data(df):
    """Basic data cleaning."""
    # Remove duplicates
    initial_rows = len(df)
    df = df.drop_duplicates()
    print(f"Removed {initial_rows - len(df)} duplicate rows")
    
    # Report on nulls
    null_cols = df.columns[df.isnull().any()].tolist()
    if null_cols:
        print(f"Columns with nulls: {null_cols}")
    
    return df

def analyze(df):
    """Main analysis logic - customize this."""
    print("\n=== ANALYSIS ===")
    # Add your analysis here
    # Example:
    # - Aggregations
    # - Groupby operations
    # - Statistical tests
    return df

def main():
    parser = argparse.ArgumentParser(description='Data Analysis Script')
    parser.add_argument('--input', '-i', required=True, help='Input file path')
    parser.add_argument('--output', '-o', help='Output file path')
    args = parser.parse_args()
    
    print(f"Loading data from: {args.input}")
    df = load_data(args.input)
    
    df = explore_data(df)
    df = clean_data(df)
    df = analyze(df)
    
    if args.output:
        df.to_csv(args.output, index=False)
        print(f"\nResults saved to: {args.output}")
    
    print("\n✅ Analysis complete!")

if __name__ == '__main__':
    main()
EOF
chmod +x "$DATA_DIR/scripts/analyze_template.py"

# Create data quality checklist
cat > "$DATA_DIR/data-quality-checklist.md" << 'EOF'
# Data Quality Checklist

Use this for every new dataset.

## Dataset: [Name]
**Source:** [Where it came from]
**Date:** [When received/pulled]
**Rows:** [Count]
**Columns:** [Count]

## Completeness
- [ ] Row count matches expected
- [ ] No unexpected nulls
- [ ] All required columns present

## Accuracy
- [ ] Values in expected ranges
- [ ] Dates are valid
- [ ] IDs/keys are valid

## Consistency
- [ ] No duplicate primary keys
- [ ] Consistent formatting (dates, text case)
- [ ] Referential integrity (foreign keys valid)

## Timeliness
- [ ] Data is current enough for analysis
- [ ] Timestamp columns are recent

## Issues Found
| Issue | Severity | Resolution |
|-------|----------|------------|
| | | |

## Cleaning Actions Taken
1. 
2. 
3. 
EOF

echo "✅ Created: $DATA_DIR/data/"
echo "✅ Created: $DATA_DIR/queries/"
echo "✅ Created: $DATA_DIR/reports/"
echo "✅ Created: $DATA_DIR/scripts/"
echo "✅ Created: $DATA_DIR/data-quality-checklist.md"
echo ""
echo "🎉 Data analysis workspace ready!"
echo ""
echo "Quick start:"
echo "  1. Put data files in data/"
echo "  2. Store SQL queries in queries/"
echo "  3. Use scripts/analyze_template.py as starting point"
echo "  4. Generate reports in reports/"


path: data-analyst-1.0.0/scripts/query.sh
content: #!/bin/bash
# query.sh - Quick SQL query execution
# Usage: ./query.sh [options] [query or --file]

# Configuration - update these for your database
DB_TYPE="${DB_TYPE:-sqlite}"  # sqlite, postgres, mysql
DB_CONNECTION="${DB_CONNECTION:-}"

show_help() {
    echo "SQL Query Tool"
    echo "=============="
    echo ""
    echo "Usage:"
    echo "  $0 \"SELECT * FROM table\"           - Run inline query"
    echo "  $0 --file queries/report.sql       - Run query from file"
    echo "  $0 --file query.sql --output out.csv - Save results to CSV"
    echo ""
    echo "Options:"
    echo "  --file, -f    SQL file to execute"
    echo "  --output, -o  Output file (CSV)"
    echo "  --db          Database connection string"
    echo "  --type        Database type (sqlite, postgres, mysql)"
    echo ""
    echo "Environment Variables:"
    echo "  DB_TYPE       Database type (default: sqlite)"
    echo "  DB_CONNECTION Database connection string"
    echo ""
    echo "Examples:"
    echo "  DB_CONNECTION='host=localhost dbname=mydb' $0 'SELECT COUNT(*) FROM users'"
    echo "  $0 --file queries/daily-report.sql --output reports/daily.csv"
}

run_query() {
    local query="$1"
    local output="$2"
    
    case "$DB_TYPE" in
        sqlite)
            if [ -n "$output" ]; then
                sqlite3 -header -csv "$DB_CONNECTION" "$query" > "$output"
            else
                sqlite3 -header -column "$DB_CONNECTION" "$query"
            fi
            ;;
        postgres|postgresql)
            if [ -n "$output" ]; then
                psql "$DB_CONNECTION" -c "COPY ($query) TO STDOUT WITH CSV HEADER" > "$output"
            else
                psql "$DB_CONNECTION" -c "$query"
            fi
            ;;
        mysql)
            if [ -n "$output" ]; then
                mysql $DB_CONNECTION -e "$query" | sed 's/\t/,/g' > "$output"
            else
                mysql $DB_CONNECTION -e "$query"
            fi
            ;;
        *)
            echo "Unsupported database type: $DB_TYPE"
            echo "Supported: sqlite, postgres, mysql"
            exit 1
            ;;
    esac
}

# Parse arguments
QUERY=""
FILE=""
OUTPUT=""

while [[ $# -gt 0 ]]; do
    case "$1" in
        --help|-h)
            show_help
            exit 0
            ;;
        --file|-f)
            FILE="$2"
            shift 2
            ;;
        --output|-o)
            OUTPUT="$2"
            shift 2
            ;;
        --db)
            DB_CONNECTION="$2"
            shift 2
            ;;
        --type)
            DB_TYPE="$2"
            shift 2
            ;;
        *)
            QUERY="$1"
            shift
            ;;
    esac
done

# Get query from file or argument
if [ -n "$FILE" ]; then
    if [ ! -f "$FILE" ]; then
        echo "❌ File not found: $FILE"
        exit 1
    fi
    QUERY=$(cat "$FILE")
fi

if [ -z "$QUERY" ]; then
    show_help
    exit 1
fi

if [ -z "$DB_CONNECTION" ]; then
    echo "❌ No database connection configured"
    echo ""
    echo "Set DB_CONNECTION environment variable or use --db flag"
    echo "Example: DB_CONNECTION='mydb.sqlite' $0 'SELECT * FROM users'"
    exit 1
fi

echo "🔍 Running query..."
run_query "$QUERY" "$OUTPUT"

if [ -n "$OUTPUT" ]; then
    echo "✅ Results saved to: $OUTPUT"
fi


path: data-analyst-1.0.0/_meta.json
content: ownerId: kn7cpmgq5bpf1mp69bpd7n9as180nssd
slug: data-analyst
version: 1.0.0
publishedAt: 1770410537278

path: deep-research-pro-1.0.2/package.json
content: {
  "name": "deep-research-pro",
  "version": "1.0.0",
  "description": "Multi-source deep research agent. Searches the web, synthesizes findings, and delivers cited reports. No API keys required.",
  "keywords": ["research", "search", "analysis", "citations", "reports", "duckduckgo"],
  "license": "MIT",
  "author": "AstralSage",
  "files": ["SKILL.md", "scripts/research", "package.json"]
}


path: deep-research-pro-1.0.2/README.md
content: # Deep Research Pro 🔬

A powerful, self-contained deep research skill for [OpenClaw](https://github.com/openclaw/openclaw) / Clawdbot agents. Produces thorough, cited reports from multiple web sources.

**No API keys required** — uses DuckDuckGo search.

## Features

- 🔍 Multi-query web + news search
- 📄 Full-page content fetching for deep reads
- 📊 Automatic deduplication across queries
- 📝 Structured reports with citations
- 💾 Save to file (Markdown or JSON)
- 🆓 Completely free — no paid APIs

## Installation

### Via ClawdHub (coming soon)
```bash
clawdhub install deep-research-pro
```

### Manual
```bash
cd your-workspace/skills
git clone https://github.com/parags/deep-research-pro.git
```

## Usage

### As an Agent Skill

Just ask your agent to research something:
```
"Research the current state of nuclear fusion energy"
"Deep dive into Rust vs Go for backend services"
"What's happening with the US housing market?"
```

The agent will follow the workflow in `SKILL.md` to produce a comprehensive report.

### CLI Tool

The `scripts/research` tool can also be used standalone:

```bash
# Basic multi-query search
./scripts/research "query 1" "query 2" "query 3"

# Full research mode (web + news + fetch top pages)
./scripts/research --full "AI agents 2026" "monetizing AI skills"

# Save to file
./scripts/research --full "topic" --output results.md

# JSON output
./scripts/research "topic" --json

# Fetch specific URLs
./scripts/research --fetch "https://example.com/article"
```

### Options

| Flag | Description |
|------|-------------|
| `--full` | Enable news search + fetch top 3 pages |
| `--news` | Include news search |
| `--max N` | Max results per query (default 8) |
| `--fetch-top N` | Fetch full text of top N results |
| `--output FILE` | Save results to file |
| `--json` | Output as JSON |

## How It Works

1. **Plan** — Break topic into 3-5 sub-questions
2. **Search** — Run multiple queries across web + news
3. **Deduplicate** — Remove duplicate sources
4. **Deep Read** — Fetch full content from key sources
5. **Synthesize** — Write structured report with citations

## Report Structure

```markdown
# Topic: Deep Research Report

## Executive Summary
## 1. First Major Theme
## 2. Second Major Theme
## Key Takeaways
## Sources (with links)
## Methodology
```

## Requirements

- Python 3.11+
- [uv](https://github.com/astral-sh/uv) (auto-installs dependencies)

The script is self-contained — dependencies install automatically on first run.

## License

MIT

## Author

Built by [AstralSage](https://moltbook.com/u/AstralSage) 🦞


path: deep-research-pro-1.0.2/_meta.json
content: ownerId: kn7aeqfsshm3b3ywbcttf6749h80e4pp
slug: deep-research-pro
version: 1.0.2
publishedAt: 1770303332827

path: deep-scraper-1.0.1/assets/main_handler.js
content: const { PlaywrightCrawler } = require('crawlee');

/**
 * Deep-Scraper: main_handler.js
 * Optimized for containerized execution in OpenClaw.
 * 
 * Usage: node assets/main_handler.js [TARGET_URL]
 */

const targetUrl = process.argv[2];
const videoId = targetUrl?.split('v=')[1]?.split('&')[0];
const mode = targetUrl?.includes('youtube.com') ? 'YOUTUBE' : 'GENERIC';

if (!targetUrl) {
    console.error('Error: No target URL provided.');
    process.exit(1);
}

const crawler = new PlaywrightCrawler({
    launchContext: {
        launchOptions: {
            headless: true,
            args: ['--no-sandbox', '--disable-setuid-sandbox'], // Required for Docker
        },
    },
    maxRequestRetries: 1,
    requestHandlerTimeoutSecs: 300,
    async requestHandler({ page, log }) {
        log.info(`Deep-Scraper starting in ${mode} mode for: ${targetUrl}`);
        
        // Clear context to ensure a fresh session (avoid cache leakage)
        const context = page.context();
        await context.clearCookies();

        if (mode === 'YOUTUBE') {
            let transcriptUrl = null;
            
            // Network Interception for raw transcript API
            page.on('request', request => {
                const reqUrl = request.url();
                // Filter by Video ID to ensure matching data
                if (reqUrl.includes('youtube.com/api/timedtext') && reqUrl.includes(videoId)) {
                    transcriptUrl = reqUrl;
                }
            });

            await page.goto(targetUrl, { waitUntil: 'networkidle' });
            
            // Induce UI interaction to trigger hidden API requests
            try {
                const moreBtn = await page.waitForSelector('#expand, tp-yt-paper-button#expand', { timeout: 5000 });
                if (moreBtn) await moreBtn.click();
                await page.waitForTimeout(2000);
            } catch (e) {
                log.info('UI trigger failed, proceeding with network capture check...');
            }

            if (transcriptUrl) {
                // Fetch directly from intercepted API for 100% accuracy
                const xmlData = await page.evaluate(async (url) => {
                    const resp = await fetch(url);
                    return await resp.text();
                }, transcriptUrl);
                
                // Strip XML tags and clean whitespace
                const cleanText = xmlData.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
                console.log(JSON.stringify({ 
                    status: 'SUCCESS', 
                    type: 'TRANSCRIPT', 
                    videoId, 
                    data: cleanText.substring(0, 15000) 
                }));
            } else {
                // Fallback to video description if transcript is unavailable
                const desc = await page.evaluate(() => document.querySelector('#description-inline-expander')?.innerText || '');
                console.log(JSON.stringify({ 
                    status: 'PARTIAL', 
                    type: 'DESCRIPTION', 
                    videoId, 
                    data: desc 
                }));
            }
        } else {
            // Generic dynamic page scraping
            await page.goto(targetUrl, { waitUntil: 'networkidle' });
            const title = await page.title();
            const content = await page.evaluate(() => document.body.innerText);
            console.log(JSON.stringify({ 
                status: 'SUCCESS', 
                type: 'GENERIC', 
                title, 
                data: content.substring(0, 10000) 
            }));
        }
    },
});

crawler.run([targetUrl]);


path: deep-scraper-1.0.1/assets/youtube_handler.js
content: const { PlaywrightCrawler } = require('crawlee');

const targetUrl = process.argv[2];
const videoId = targetUrl.split('v=')[1]?.split('&')[0];

const crawler = new PlaywrightCrawler({
    launchContext: {
        launchOptions: {
            headless: true,
            args: ['--no-sandbox', '--disable-setuid-sandbox'],
        },
    },
    maxRequestRetries: 1,
    requestHandlerTimeoutSecs: 300,
    async requestHandler({ page, log }) {
        log.info(`正在尝试强制抓取视频内容 (ID: ${videoId}): ${targetUrl}`);
        
        let transcriptUrl = null;

        // 监听所有网络请求
        page.on('request', request => {
            const reqUrl = request.url();
            // 只要包含 timedtext 且包含当前 videoId 的请求都捕获
            if (reqUrl.includes('youtube.com/api/timedtext') && reqUrl.includes(videoId)) {
                log.info(`截获成功: ${reqUrl}`);
                transcriptUrl = reqUrl;
            }
        });

        // 1. 彻底清除缓存和 Cookie 确保全新加载
        const context = page.context();
        await context.clearCookies();

        // 2. 访问页面并等待
        await page.goto(targetUrl, { waitUntil: 'networkidle' });
        await page.waitForTimeout(5000);

        // 3. 强制触发：展开描述栏并寻找“转录稿”按钮
        try {
            const moreBtn = await page.waitForSelector('#expand, tp-yt-paper-button#expand', { timeout: 10000 });
            await moreBtn.click();
            await page.waitForTimeout(2000);

            // 在描述栏里暴力寻找按钮
            await page.evaluate(() => {
                const btns = Array.from(document.querySelectorAll('button, ytd-button-renderer'));
                const target = btns.find(b => b.innerText.includes('转录') || b.innerText.includes('Transcript'));
                if (target) {
                    target.scrollIntoView();
                    target.click();
                }
            });
            log.info('已尝试点击触发按钮');
            await page.waitForTimeout(5000);
        } catch (e) {
            log.info('UI 触发失败，继续观察网络流量...');
        }

        // 4. 如果还没拿到，尝试开启 CC
        if (!transcriptUrl) {
            try {
                await page.click('.ytp-subtitles-button');
                log.info('已尝试点击 CC 按钮');
                await page.waitForTimeout(5000);
            } catch (e) {}
        }

        if (transcriptUrl) {
            const xmlData = await page.evaluate(async (apiUrl) => {
                const resp = await fetch(apiUrl);
                return await resp.text();
            }, transcriptUrl);

            // 增强清理逻辑
            const cleanText = xmlData.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
            console.log('--- 深度抓取成功 (ID 校验通过) ---');
            console.log(JSON.stringify({ 
                videoId,
                transcript: cleanText.substring(0, 15000) 
            }, null, 2));
        } else {
            // 终极备选方案：直接抓取页面可见的描述文字
            const description = await page.evaluate(() => document.querySelector('#description-inline-expander')?.innerText || '');
            console.log('--- 字幕抓取失败，返回描述信息 ---');
            console.log(JSON.stringify({ videoId, description }, null, 2));
        }
    },
});

crawler.run([targetUrl]);


path: deep-scraper-1.0.1/package.json
content: {
  "name": "deep-scraper",
  "version": "1.0.0",
  "description": "High-performance containerized scraper for YouTube, X (Twitter), and dynamic SPAs. Features raw API interception and ID validation.",
  "main": "assets/main_handler.js",
  "scripts": {
    "test": "node assets/main_handler.js https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  },
  "keywords": [
    "scraper",
    "crawlee",
    "youtube",
    "alpha",
    "openclaw"
  ],
  "author": "Joseph",
  "license": "MIT",
  "dependencies": {
    "crawlee": "^3.0.0",
    "playwright": "^1.40.0"
  },
  "openclaw": {
    "requires": {
      "docker": true
    }
  }
}


path: deep-scraper-1.0.1/_meta.json
content: ownerId: kn76pthph791hzv7dtcww9683d80g0xw
slug: deep-scraper
version: 1.0.1
publishedAt: 1770205151953

path: dreaming-1.0.1/scripts/should-dream.sh
content: #!/bin/bash
# should-dream.sh — Check if the agent should dream during this quiet hour
# Returns 0 (and prints a dream topic) if yes, 1 if no
# Uses data/dream-state.json to track nightly limits

set -e

# Find workspace root (where data/ and memory/ live)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
WORKSPACE="${WORKSPACE:-$(cd "$SCRIPT_DIR/.." && pwd)}"
cd "$WORKSPACE"

# ============================================================================
# CONFIGURATION — Edit these to customize
# ============================================================================

# Quiet hours window (24-hour format)
QUIET_START=23  # 11 PM
QUIET_END=7     # 7 AM

# Dream topics — format: "category:prompt"
# Override by creating data/dream-config.json with a "topics" array
# Example: {"topics": ["future:What could X become?", "creative:Wild ideas"]}
DEFAULT_TOPICS=(
    "future:What could this project become in 5 years if everything goes right?"
    "tangent:An interesting technology or concept worth exploring"
    "strategy:Long-term thinking about goals and direction"
    "creative:A wild idea that might be crazy or brilliant"
    "reflection:Looking back at recent work and what it means"
    "hypothetical:What-if scenarios worth considering"
    "connection:Unexpected links between different domains or concepts"
)

# Load custom topics from config if it exists
CONFIG_FILE="data/dream-config.json"
if [[ -f "$CONFIG_FILE" ]]; then
    CUSTOM_TOPICS=$(jq -r '.topics[]? // empty' "$CONFIG_FILE" 2>/dev/null)
    if [[ -n "$CUSTOM_TOPICS" ]]; then
        TOPICS=()
        while IFS= read -r line; do
            TOPICS+=("$line")
        done <<< "$CUSTOM_TOPICS"
    else
        TOPICS=("${DEFAULT_TOPICS[@]}")
    fi
else
    TOPICS=("${DEFAULT_TOPICS[@]}")
fi

# ============================================================================
# IMPLEMENTATION — Probably don't need to edit below here
# ============================================================================

STATE_FILE="data/dream-state.json"
CURRENT_DATE=$(date +%Y-%m-%d)
CURRENT_HOUR=$(date +%H)

# Check if we're in quiet hours
in_quiet_hours() {
    local hour=$((10#$CURRENT_HOUR))  # Force base-10
    if [[ $QUIET_START -gt $QUIET_END ]]; then
        # Window crosses midnight (e.g., 23:00 - 07:00)
        [[ $hour -ge $QUIET_START || $hour -lt $QUIET_END ]]
    else
        # Window within same day (e.g., 01:00 - 05:00)
        [[ $hour -ge $QUIET_START && $hour -lt $QUIET_END ]]
    fi
}

if ! in_quiet_hours; then
    exit 1
fi

# Ensure data directory exists
mkdir -p "$(dirname "$STATE_FILE")"

# Initialize state file if missing
if [[ ! -f "$STATE_FILE" ]]; then
    echo '{"lastDreamDate":null,"dreamsTonight":0,"maxDreamsPerNight":1,"dreamChance":1.0}' > "$STATE_FILE"
fi

# Read state (requires jq)
if ! command -v jq &>/dev/null; then
    echo "Error: jq required but not installed" >&2
    exit 1
fi

STATE=$(cat "$STATE_FILE")
LAST_DATE=$(echo "$STATE" | jq -r '.lastDreamDate // ""')
DREAMS_TONIGHT=$(echo "$STATE" | jq -r '.dreamsTonight // 0')
MAX_DREAMS=$(echo "$STATE" | jq -r '.maxDreamsPerNight // 1')
DREAM_CHANCE=$(echo "$STATE" | jq -r '.dreamChance // 1.0')

# Reset counter if new night
# "New night" = date changed AND we're in late-night hours (after QUIET_START)
if [[ "$LAST_DATE" != "$CURRENT_DATE" ]]; then
    hour=$((10#$CURRENT_HOUR))
    if [[ $hour -ge $QUIET_START || $hour -lt $QUIET_END ]]; then
        DREAMS_TONIGHT=0
    fi
fi

# Check if we've hit the nightly limit
if [[ "$DREAMS_TONIGHT" -ge "$MAX_DREAMS" ]]; then
    exit 1
fi

# Roll the dice
ROLL=$(python3 -c "import random; print(1 if random.random() < $DREAM_CHANCE else 0)" 2>/dev/null || echo "1")
if [[ "$ROLL" != "1" ]]; then
    exit 1
fi

# Pick a random topic
TOPIC=${TOPICS[$RANDOM % ${#TOPICS[@]}]}

# Update state
NEW_DREAMS=$((DREAMS_TONIGHT + 1))
echo "$STATE" | jq --arg date "$CURRENT_DATE" --argjson dreams "$NEW_DREAMS" \
    '.lastDreamDate = $date | .dreamsTonight = $dreams' > "$STATE_FILE"

# Output the topic
echo "$TOPIC"
exit 0


path: dreaming-1.0.1/_meta.json
content: ownerId: kn701kzxq5tkxw9mypbmspqw5580cxew
slug: dreaming
version: 1.0.1
publishedAt: 1770232055717

path: gitai-skill-1.0.2/_meta.json
content: ownerId: kn79yxn30t12ejhnpkv0dgch3d80mj2j
slug: gitai-skill
version: 1.0.2
publishedAt: 1770374204782

path: gitai-skill-1.0.2/README.md
content: # Gitai: Automated Conventional Commits

**Transform your git history with AI. From chaotic logs to semantic perfection.**

[![Version](https://img.shields.io/badge/version-1.0.0-blue.svg)](https://github.com/leandrosilvaferreira/gitai-skill)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org/)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-orange.svg)](https://github.com/leandrosilvaferreira/gitai-skill/pulls)
[![Ko-fi](https://img.shields.io/badge/Ko--fi-Support%20this%20project-FF5E5B?logo=ko-fi&logoColor=white)](https://ko-fi.com/leandrozuck)

---

## The Problem

Writing meaningful commit messages is often the last thing on a developer's mind. We're focused on the code, not the log. This leads to repositories full of `fix`, `wip`, or `update` messages that make history audits a nightmare.

**Common issues:**
- **Inconsistent History**: "Added feature" vs "feat: add new feature"
- **Mental Fatigue**: Context switching to write summaries breaks flow
- **Lost Context**: "Fixed bug" (Which bug? How? Why?)
- **Time Wasted**: Minutes lost per day thinking of message formatting

## The Solution

Gitai acts as your intelligent pair programmer that handles the bureaucracy of version control. It analyzes your staged changes and generates precise, descriptive, Conventional Commits-compliant messages instantly.

| Feature | Before (Manual) | After (Gitai) |
|---------|-----------------|---------------|
| **Consistency** | Varies by mood/coffee | 100% Conventional Commits |
| **Detail Level** | Often vague | Semantic & Descriptive |
| **Effort** | High friction | One command (`gitai`) |
| **Accuracy** | Human error prone | AI-analyzed diffs |

**Result: A professional, navigable git history with zero extra effort.**

## Efficiency Comparison

| Metric | Manual Commit | Gitai Automation |
|--------|---------------|------------------|
| Time per commit | 30-90 seconds | **3-5 seconds** |
| Cognitive Load | High (Summarizing diffs) | **Zero** (Review only) |
| Standard Compliance | Hit or miss | **Guaranteed** |

## Quick Start

### Installation

**MacOS / Linux:**
```bash
chmod +x scripts/install.sh
./scripts/install.sh
```

**Windows (PowerShell):**
```powershell
.\scripts\install.ps1
```

### Configuration (One Time)

Gitai needs to know your preferred AI provider. Run the setup:

1.  Create `~/.gitai`:
    ```bash
    nano ~/.gitai
    ```
2.  Add your settings:
    ```env
    PROVIDER=openai # or anthropic, groq
    [REDACTED_SECRET]
    MODEL=gpt-4o
    LANGUAGE=en
    ```

## Features

### 1. Universal Language Support
Gitai understands code, not just syntax. Whether you're writing **Node.js, Python, Java, Go, PHP**, or **Rust**, Gitai analyzes the logic changes to generate accurate summaries.

### 2. Multi-LLM Support
Choose your brain. Gitai supports:
- **OpenAI** (GPT-4o, GPT-3.5)
- **Anthropic** (Claude 3.5 Sonnet, Haiku)
- **Groq** (Llama 3, Mixtral - strict/fast)

### 3. Workflow Automation
Combine stages, commits, and pushes into single fluid actions.

**Standard Workflow:**
```bash
# Analyze all changes, commit, and push
gitai . "" --push
```

**Scoped Workflow:**
```bash
# Analyze only frontend folder
gitai ./frontend "ui refresh"
```

## Usage

### Basic Usage
```bash
gitai [path] [base-message] [options]
```

### Examples
| Goal | Command |
|------|---------|
| **Auto-commit everything** | `gitai` |
| **Commit specific path** | `gitai src/components` |
| **Add context hint** | `gitai . "fix login bug"` |
| **Commit & Push** | `gitai . "" --push` |

## Troubleshooting

### Wizard Hangs?
If `gitai` hangs waiting for input, ensure your `~/.gitai` config file exists and is valid. Background agents cannot interact with the setup wizard.

### "Command not found"?
Ensure the installation script completed successfully and added gitai to your PATH.

## Support

- **Issues**: [GitHub Issues](https://github.com/leandrosilvaferreira/gitai-skill/issues)

**If Gitai saves you time, consider supporting development:**

[![Ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/leandrozuck)

## License

MIT. See [LICENSE](LICENSE) for details.

---

**Built with ❤️ by [Leandro Zuck](https://github.com/leandrosilvaferreira)**


path: gitai-skill-1.0.2/skill.json
content: {
  "name": "gitai-skill",
  "version": "1.0.0",
  "summary": "Boost developer productivity with Gitai: An AI-powered Git automation tool that analyzes code changes and generates semantic Conventional Commits instantly.",
  "description": "Boost developer productivity with Gitai: An AI-powered Git automation tool that analyzes code changes and generates semantic Conventional Commits instantly. Supports Node.js, Python, Java, Go, PHP, and more. Compatible with OpenAI, Anthropic, and Groq.",
  "author": "leandrosilvaferreira",
  "license": "MIT",
  "keywords": [
    "git",
    "automation",
    "ai",
    "commit",
    "conventional-commits",
    "workflow",
    "productivity",
    "dev-tools",
    "openai",
    "anthropic",
    "groq",
    "llm"
  ],
  "homepage": "https://github.com/leandrosilvaferreira/gitai-skill",
  "repository": {
    "type": "git",
    "url": "https://github.com/leandrosilvaferreira/gitai-skill.git"
  },
  "triggers": [
    "generate commit",
    "automate git",
    "ai commit",
    "conventional commits",
    "git message",
    "auto commit"
  ]
}


path: github-api-1.0.1/LICENSE.txt
content: The MIT License (MIT)

Copyright (c) 2026 Maton

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


path: github-api-1.0.1/_meta.json
content: ownerId: kn75240wq8bnv2qm2xgry748jd80b9r0
slug: github-api
version: 1.0.1
publishedAt: 1770380279869

path: gmail-oauth-1.0.0/scripts/gmail-auth.sh
content: #!/bin/bash
# Gmail OAuth helper for headless servers
# Usage:
#   ./gmail-auth.sh                    # Interactive setup
#   ./gmail-auth.sh --url              # Just print auth URL
#   ./gmail-auth.sh --exchange CODE    # Exchange code for tokens

set -e

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

# Load credentials from gog config
GOG_CREDS="${HOME}/.config/gogcli/credentials.json"

if [[ ! -f "$GOG_CREDS" ]]; then
    echo -e "${RED}Error: No gog credentials found at $GOG_CREDS${NC}"
    echo "Run: gog auth credentials /path/to/client_secret.json"
    exit 1
fi

CLIENT_ID=$(python3 -c "import json; print(json.load(open('$GOG_CREDS'))['client_id'])")
CLIENT_SECRET=$(python3 -c "import json; print(json.load(open('$GOG_CREDS'))['client_secret'])")

# Default scope - gmail.modify covers most use cases
SCOPE="https://www.googleapis.com/auth/gmail.modify"
REDIRECT_URI="http://localhost"

generate_url() {
    local encoded_scope=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$SCOPE'))")
    echo "https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=${CLIENT_ID}&prompt=consent&redirect_uri=${REDIRECT_URI}&response_type=code&scope=${encoded_scope}"
}

exchange_code() {
    local code="$1"
    local email="$2"
    
    echo -e "${YELLOW}Exchanging code for tokens...${NC}"
    
    response=$(curl -s -X POST https://oauth2.googleapis.com/token \
        -d "code=${code}" \
        -d "client_id=${CLIENT_ID}" \
        -d "client_secret=${CLIENT_SECRET}" \
        -d "redirect_uri=${REDIRECT_URI}" \
        -d "grant_type=authorization_code")
    
    # Check for error
    if echo "$response" | python3 -c "import json,sys; d=json.load(sys.stdin); sys.exit(0 if 'access_token' in d else 1)" 2>/dev/null; then
        refresh_token=$(echo "$response" | python3 -c "import json,sys; print(json.load(sys.stdin)['refresh_token'])")
        
        # Create token file for gog import
        token_file=$(mktemp)
        cat > "$token_file" << EOF
{
  "email": "${email}",
  "client": "default",
  "refresh_token": "${refresh_token}",
  "scopes": ["${SCOPE}"]
}
EOF
        
        echo -e "${GREEN}Token exchange successful!${NC}"
        echo ""
        echo "Importing to gog..."
        
        if [[ -z "$GOG_KEYRING_PASSWORD" ]]; then
            echo -e "${YELLOW}Note: Set GOG_KEYRING_PASSWORD environment variable for non-interactive import${NC}"
        fi
        
        gog auth tokens import "$token_file"
        rm "$token_file"
        
        echo ""
        echo -e "${GREEN}Done! Test with:${NC}"
        echo "  gog gmail search 'is:unread' --max 5 --account ${email}"
    else
        echo -e "${RED}Token exchange failed:${NC}"
        echo "$response" | python3 -m json.tool 2>/dev/null || echo "$response"
        exit 1
    fi
}

# Parse arguments
case "${1:-}" in
    --url)
        generate_url
        ;;
    --exchange)
        if [[ -z "${2:-}" ]]; then
            echo "Usage: $0 --exchange CODE [EMAIL]"
            exit 1
        fi
        email="${3:-}"
        if [[ -z "$email" ]]; then
            read -p "Gmail address to authorize: " email
        fi
        exchange_code "$2" "$email"
        ;;
    --help|-h)
        echo "Gmail OAuth Helper"
        echo ""
        echo "Usage:"
        echo "  $0              Interactive setup"
        echo "  $0 --url        Print auth URL only"
        echo "  $0 --exchange CODE [EMAIL]  Exchange code for tokens"
        echo ""
        echo "Environment:"
        echo "  GOG_KEYRING_PASSWORD  Required for non-interactive token import"
        ;;
    *)
        # Interactive mode
        echo -e "${GREEN}Gmail OAuth Setup${NC}"
        echo ""
        
        read -p "Gmail address to authorize: " email
        
        echo ""
        echo -e "${YELLOW}Step 1: Open this URL in a browser${NC}"
        echo ""
        generate_url
        echo ""
        echo -e "${YELLOW}Step 2: Sign in with ${email} and approve access${NC}"
        echo ""
        echo -e "${YELLOW}Step 3: Copy the authorization code shown on the page${NC}"
        echo ""
        read -p "Paste the code here: " code
        
        exchange_code "$code" "$email"
        ;;
esac


path: gmail-oauth-1.0.0/_meta.json
content: ownerId: kn7dda8ejtkkez11r454axbrys80nnnm
slug: gmail-oauth
version: 1.0.0
publishedAt: 1770338436440

path: mcp-ssh-manager-0.1.1/_meta.json
content: ownerId: kn76rjq5djsk27w11wjjxqays580pdzc
slug: mcp-ssh-manager
version: 0.1.1
publishedAt: 1770463776741

path: mineru-1.0.1/_meta.json
content: ownerId: kn7f1yrn047e38qxrcaqpyzdqh80mjsj
slug: mineru
version: 1.0.1
publishedAt: 1770380318908

path: openclaw-multi-brain-1.0.0/_meta.json
content: ownerId: kn7ej6qm2paeg06zxa2qah0yp180k8dc
slug: openclaw-multi-brain
version: 1.0.0
publishedAt: 1770334235020

path: privatedeepsearch-melt-1.0.0/_meta.json
content: ownerId: kn7f8jx9c7q25wanfw77szm67d80hanp
slug: privatedeepsearch-melt
version: 1.0.0
publishedAt: 1770208869492

path: proactive-agent-1-2-4-1.0.0/_meta.json
content: ownerId: kn7e6gjx8tfha97v6gt2qpr641808vqh
slug: proactive-agent-1-2-4
version: 1.0.0
publishedAt: 1770234924679

path: project-orchestrator-0.1.0/src/meilisearch/mod.rs
content: //! Meilisearch client and index management

pub mod client;
pub mod indexes;

pub use client::MeiliClient;


path: project-orchestrator-0.1.0/src/plan/mod.rs
content: //! Plan management module

pub mod manager;
pub mod models;

pub use manager::PlanManager;
pub use models::*;


Security scan verdicts — ClawScan: suspicious | static analysis:  | VirusTotal: malicious | SkillSpector: suspicious (CRITICAL)