Files
gh-musingfox-cc-plugins-omt/commands/init-agents.md
2025-11-30 08:41:39 +08:00

15 KiB

name, description, model
name description model
init-agents Initialize Agent-First workflow structure in the current project. Sets up agent workspace, task management, and configuration. claude-haiku-4-5

Init Agents Workspace

Initialize Agent-First workflow structure in the current project.

What this command does

  1. Creates .agents/ directory structure
  2. Configures task management system (Linear/GitHub Issues/Jira/Local)
  3. Initializes state definitions
  4. Configures gitignore rules
  5. Creates agent helper library

Usage

Run this command in any project root to set up the agent workspace.

IMPORTANT: This command will ask you to configure the task management system for this project.


Please initialize the Agent-First workflow structure in the current project with the following setup:

Step 0: Configuration

Package Manager Selection

First, ask the user which package manager they prefer:

📦 Package Manager Setup

Which JavaScript package manager do you prefer for this project?

A) npm (Node.js default)
B) pnpm (Fast, disk-efficient)
C) bun (Ultra-fast, modern)

Please select (A/B/C):

Store the selection for later use in dependency installation.

Task Management System Configuration

Then, ask the user:

🔧 Task Management System Setup

Which task management system does this project use?

A) Linear (with MCP integration)
B) GitHub Issues
C) Jira
D) Local files (.agents/tasks/)
E) Other

Please select (A/B/C/D/E):

Based on user selection, collect required information:

If Linear (A):

Linear Configuration:
- Team ID or name: _______________
- API Key (optional, for MCP): _______________
- Workspace: _______________

If GitHub Issues (B):

GitHub Configuration:
- Repository: _______________
- Owner: _______________

If Jira (C):

Jira Configuration:
- Project Key: _______________
- Site URL: _______________

Note on Jira Integration: This project uses Atlassian CLI (acli) for direct Jira management. After /init-agents completes, ensure you have installed and authenticated Atlassian CLI:

  1. Install ACLI: https://developer.atlassian.com/cloud/acli/guides/install-acli/
  2. Authenticate with OAuth:
    acli jira auth
    
    Follow the browser OAuth flow to complete authentication.
  3. Verify connection:
    acli jira workspace list
    

See jira_cli_integration.md for detailed usage in agent workflows.

If Local (D):

Local Task Management:
✅ Tasks will be stored in .agents/tasks/
✅ No external integration needed

Create CLAUDE.md in project root with STABLE configuration only:

# Project Configuration

## Task Management System

**System**: [Linear/GitHub/Jira/Local]
**Configuration**:
- [Key configuration details based on selection]

## Agent Workspace

Location: `.agents/`
See @.agents/README.md for usage guide.

1. Create Directory Structure

mkdir -p .agents/tasks
mkdir -p .agents/retro

2. Install Dependencies

Based on user's package manager selection, run the appropriate command:

If npm (A):

cd .agents
npm init -y
npm install yaml
cd ..

If pnpm (B):

cd .agents
pnpm init
pnpm add yaml
cd ..

If bun (C):

cd .agents
bun init -y
# Remove "type": "module" to use CommonJS (lib.js uses require/module.exports)
sed -i.bak '/"type": "module"/d' package.json && rm package.json.bak
bun add yaml
cd ..

Note: Bun init defaults to ESM ("type": "module"), but lib.js uses CommonJS format. The sed command removes this field to ensure compatibility.

This creates:

  • .agents/package.json - Dependency manifest
  • .agents/node_modules/ - Installed packages (will be gitignored)
  • .agents/package-lock.json / pnpm-lock.yaml / bun.lockb - Lock file

3. Create Agent Config (.agents/config.yml)

# Agent Workspace Configuration
# This file contains DYNAMIC state and runtime information

workspace:
  version: "1.0.0"
  initialized_at: "[CURRENT_TIMESTAMP]"
  location: ".agents/"

task_management:
  system: "[Linear/GitHub/Jira/Local]"
  # Configuration details are stored in project root CLAUDE.md
  # This section tracks runtime state only

runtime:
  last_cleanup: null
  total_tasks_created: 0
  total_tasks_completed: 0

4. Create State Definitions (.agents/states.yml)

# Agent Task States Definition
task_states:
  pending:
    description: "Task created, waiting to start"
    next_states: ["in_progress", "blocked", "cancelled"]

  in_progress:
    description: "Task in progress"
    next_states: ["completed", "blocked", "failed"]

  blocked:
    description: "Task blocked, requires human intervention"
    next_states: ["in_progress", "cancelled"]

  completed:
    description: "Task completed"
    next_states: []

  failed:
    description: "Task failed, cannot complete"
    next_states: ["pending", "cancelled"]

  cancelled:
    description: "Task cancelled"
    next_states: []

agent_states:
  idle:
    description: "Agent idle, waiting for tasks"
  working:
    description: "Agent working"
  completed:
    description: "Agent completed its part"
  blocked:
    description: "Agent encountered issues, cannot continue"
  skipped:
    description: "Agent skipped"

complexity_scale:
  values: [1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
  token_estimates:
    1: 1000
    2: 2000
    3: 3000
    5: 5000
    8: 8000
    13: 13000
    21: 21000
    34: 34000
    55: 55000
    89: 89000

5. Create Agent Helper Library (.agents/lib.js)

const fs = require('fs');
const path = require('path');
const yaml = require('yaml');

class AgentTask {
  constructor(taskId) {
    this.taskId = taskId;
    this.jsonPath = `.agents/tasks/${taskId}.json`;
    this.dirPath = `.agents/tasks/${taskId}`;
  }

  // Load task
  load() {
    if (!fs.existsSync(this.jsonPath)) {
      throw new Error(`Task ${this.taskId} not found`);
    }
    return JSON.parse(fs.readFileSync(this.jsonPath, 'utf8'));
  }

  // Save task
  save(task) {
    fs.writeFileSync(this.jsonPath, JSON.stringify(task, null, 2));
  }

  // Create new task
  static create(taskId, title, complexity = 5) {
    const states = yaml.parse(fs.readFileSync('.agents/states.yml', 'utf8'));
    const estimatedTokens = states.complexity_scale.token_estimates[complexity];

    const task = {
      task_id: taskId,
      title: title,
      status: 'pending',
      current_agent: null,
      complexity: {
        estimated: complexity,
        estimated_tokens: estimatedTokens,
        actual: null,
        actual_tokens: null
      },
      agents: {},
      metadata: {
        created_at: new Date().toISOString(),
        updated_at: new Date().toISOString()
      }
    };

    const jsonPath = `.agents/tasks/${taskId}.json`;
    const dirPath = `.agents/tasks/${taskId}`;

    fs.writeFileSync(jsonPath, JSON.stringify(task, null, 2));
    fs.mkdirSync(dirPath, { recursive: true });

    return new AgentTask(taskId);
  }

  // Set complexity
  setComplexity(complexity, estimatedTokens = null) {
    const task = this.load();
    task.complexity.estimated = complexity;

    if (estimatedTokens) {
      task.complexity.estimated_tokens = estimatedTokens;
    } else {
      const states = yaml.parse(fs.readFileSync('.agents/states.yml', 'utf8'));
      task.complexity.estimated_tokens = states.complexity_scale.token_estimates[complexity];
    }

    task.metadata.updated_at = new Date().toISOString();
    this.save(task);
  }

  // Update agent status
  updateAgent(agentName, data) {
    const task = this.load();

    if (!task.agents[agentName]) {
      task.agents[agentName] = {};
    }

    Object.assign(task.agents[agentName], data);

    if (data.status === 'working' && !task.agents[agentName].started_at) {
      task.agents[agentName].started_at = new Date().toISOString();
    }

    if (data.status === 'completed' && !task.agents[agentName].completed_at) {
      task.agents[agentName].completed_at = new Date().toISOString();
    }

    if (data.handoff_to) {
      task.current_agent = data.handoff_to;
    }

    task.metadata.updated_at = new Date().toISOString();
    this.save(task);
  }

  // Write agent output to markdown
  writeAgentOutput(agentName, content) {
    fs.mkdirSync(this.dirPath, { recursive: true });
    const outputPath = path.join(this.dirPath, `${agentName}.md`);
    fs.writeFileSync(outputPath, content);

    const task = this.load();
    if (!task.agents[agentName]) {
      task.agents[agentName] = {};
    }
    task.agents[agentName].output_file = `${agentName}.md`;
    task.metadata.updated_at = new Date().toISOString();
    this.save(task);
  }

  // Append to agent output
  appendAgentOutput(agentName, content) {
    const outputPath = path.join(this.dirPath, `${agentName}.md`);
    fs.appendFileSync(outputPath, '\n' + content);
  }

  // Read agent output
  readAgentOutput(agentName) {
    const outputPath = path.join(this.dirPath, `${agentName}.md`);
    if (!fs.existsSync(outputPath)) return null;
    return fs.readFileSync(outputPath, 'utf8');
  }

  // Mark task as completed
  complete() {
    const task = this.load();
    task.status = 'completed';
    task.current_agent = null;
    task.metadata.updated_at = new Date().toISOString();

    // Calculate actual complexity
    let totalTokens = 0;
    Object.values(task.agents).forEach(agent => {
      if (agent.tokens_used) {
        totalTokens += agent.tokens_used;
      }
    });

    task.complexity.actual_tokens = totalTokens;
    task.complexity.actual = this.mapToFibonacci(totalTokens);

    this.save(task);
  }

  // Map tokens to Fibonacci scale
  mapToFibonacci(tokens) {
    const states = yaml.parse(fs.readFileSync('.agents/states.yml', 'utf8'));
    const scale = states.complexity_scale.values;
    const estimates = states.complexity_scale.token_estimates;

    for (let i = scale.length - 1; i >= 0; i--) {
      if (tokens >= estimates[scale[i]]) {
        return scale[i];
      }
    }
    return scale[0];
  }

  // Find tasks for specific agent
  static findMyTasks(agentName) {
    const tasksDir = '.agents/tasks';
    if (!fs.existsSync(tasksDir)) return [];

    return fs.readdirSync(tasksDir)
      .filter(f => f.endsWith('.json'))
      .map(f => {
        const task = JSON.parse(fs.readFileSync(path.join(tasksDir, f), 'utf8'));
        return task;
      })
      .filter(t => t.current_agent === agentName && t.status === 'in_progress');
  }

  // Cleanup old tasks
  static cleanup(daysOld = 90) {
    const tasksDir = '.agents/tasks';
    const now = Date.now();
    const cutoff = daysOld * 24 * 60 * 60 * 1000;
    let cleaned = 0;

    fs.readdirSync(tasksDir).forEach(file => {
      if (!file.endsWith('.json')) return;

      const filePath = path.join(tasksDir, file);
      const task = JSON.parse(fs.readFileSync(filePath, 'utf8'));

      if (!['completed', 'cancelled'].includes(task.status)) return;

      const stats = fs.statSync(filePath);
      const age = now - stats.mtimeMs;

      if (age > cutoff) {
        fs.unlinkSync(filePath);
        const taskDir = path.join(tasksDir, task.task_id);
        if (fs.existsSync(taskDir)) {
          fs.rmSync(taskDir, { recursive: true });
        }
        cleaned++;
      }
    });

    return cleaned;
  }
}

module.exports = { AgentTask };

6. Update .gitignore

Add the following rules to .gitignore:

# Agent Workspace - Local state and dependencies
.agents/tasks/
.agents/retro/
.agents/node_modules/
.agents/package-lock.json
.agents/pnpm-lock.yaml
.agents/bun.lockb

# Keep these files in version control:
# .agents/package.json
# .agents/config.yml
# .agents/states.yml
# .agents/lib.js
# .agents/README.md

7. Create README (.agents/README.md)

# Agent Workspace

This directory contains the Agent-First workflow workspace for this project.

## Structure

- `package.json` - **Dependencies** (yaml package)
- `node_modules/` - **Installed packages** (gitignored)
- `config.yml` - **Dynamic configuration** (initialization time, runtime stats)
- `states.yml` - **State definitions** (task states, agent states, complexity scale)
- `lib.js` - **Agent helper library** (AgentTask class)
- `tasks/` - **Active tasks** (JSON + markdown details, gitignored)
  - `{task-id}.json` - Task state and metadata
  - `{task-id}/` - Detailed agent outputs
    - `planner.md` - Planning documents
    - `coder.md` - Implementation logs
    - `reviewer.md` - Review results
    - `retro.md` - Retrospective analysis
- `retro/` - **Retrospective analysis reports** (gitignored)

## Setup

### First Time Setup
After running `/init-agents`, dependencies are automatically installed. If you clone this repo:

\`\`\`bash
cd .agents
npm install    # or: pnpm install / bun install
\`\`\`

## Task Lifecycle

1. **Create**: `AgentTask.create(taskId, title, complexity)`
2. **Work**: Agents update status and write outputs
3. **Complete**: Mark as done, calculate actual complexity
4. **Cleanup**: Auto-delete after 90 days (based on file mtime)

## Usage Examples

### Create a task
\`\`\`javascript
const { AgentTask } = require('./.agents/lib');
const task = AgentTask.create('LIN-123', 'Implement auth API', 8);
\`\`\`

### Agent updates status
\`\`\`javascript
task.updateAgent('planner', {
  status: 'completed',
  tokens_used: 1200,
  handoff_to: 'coder'
});
\`\`\`

### Write detailed output
\`\`\`javascript
task.writeAgentOutput('planner', \`
# Planning Document
## Requirements
...
\`);
\`\`\`

### Find my tasks
\`\`\`javascript
const myTasks = AgentTask.findMyTasks('coder');
\`\`\`

### Cleanup old tasks
\`\`\`javascript
const cleaned = AgentTask.cleanup(90); // 90 days
console.log(\`Cleaned \${cleaned} old tasks\`);
\`\`\`

## States

Check `states.yml` for:
- Task states (pending, in_progress, blocked, completed, failed, cancelled)
- Agent states (idle, working, completed, blocked, skipped)
- Complexity scale (Fibonacci: 1, 2, 3, 5, 8, 13, 21, 34, 55, 89)

## Maintenance

Tasks are automatically cleaned up 90 days after completion based on file modification time. No archive directory needed.

Summary

After running this command, your project will have:

CLAUDE.md - Stable configuration (Task Management System setup) .agents/package.json - Dependency manifest (yaml package) .agents/node_modules/ - Installed packages (gitignored) .agents/config.yml - Dynamic state (initialization time, runtime stats) .agents/states.yml - State definitions and complexity scale .agents/lib.js - Agent helper library .agents/README.md - Usage documentation .gitignore - Updated to exclude runtime files and dependencies

The workspace is now ready for Agent-First development!

File Organization Principle

  • CLAUDE.md: Stable configuration that rarely changes (task management type, API connections)
  • .agents/config.yml: Dynamic state that changes during runtime (timestamps, counters)
  • .agents/states.yml: Shared state definitions (task states, complexity scale)
  • .agents/tasks/: Active task data (automatically cleaned after 90 days)

Next Steps

  1. Understand the workflow: Read @~/.claude/workflow.md for the complete Agent-First workflow
  2. Technical details: See @~/.claude/agent-workspace-guide.md for API usage and examples
  3. Start using agents: Begin with /product_owner or /techlead commands

References

  • @~/.claude/workflow.md - Complete Agent-First workflow overview
  • @~/.claude/agent-workspace-guide.md - Technical implementation guide
  • @~/.claude/CLAUDE.md - Global configuration and preferences