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
- Creates
.agents/directory structure - Configures task management system (Linear/GitHub Issues/Jira/Local)
- Initializes state definitions
- Configures gitignore rules
- 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:
- Install ACLI: https://developer.atlassian.com/cloud/acli/guides/install-acli/
- Authenticate with OAuth:
Follow the browser OAuth flow to complete authentication.
acli jira auth - 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
- Understand the workflow: Read @~/.claude/workflow.md for the complete Agent-First workflow
- Technical details: See @~/.claude/agent-workspace-guide.md for API usage and examples
- Start using agents: Begin with
/product_owneror/techleadcommands
References
- @~/.claude/workflow.md - Complete Agent-First workflow overview
- @~/.claude/agent-workspace-guide.md - Technical implementation guide
- @~/.claude/CLAUDE.md - Global configuration and preferences