--- name: init-agents description: Initialize Agent-First workflow structure in the current project. Sets up agent workspace, task management, and configuration. model: 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: ```bash acli jira auth ``` Follow the browser OAuth flow to complete authentication. 3. Verify connection: ```bash 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:** ```markdown # 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 ```bash 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): ```bash cd .agents npm init -y npm install yaml cd .. ``` ### If pnpm (B): ```bash cd .agents pnpm init pnpm add yaml cd .. ``` ### If bun (C): ```bash 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) ```yaml # 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) ```yaml # 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) ```javascript 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) ```markdown # 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