Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:49:53 +08:00
commit f5b0a7389f
32 changed files with 2764 additions and 0 deletions

View File

@@ -0,0 +1,233 @@
---
name: agent-orchestrator
description: Use this skill when you need to orchestrate specialized Claude agents in separate sessions. Perfect for long-running tasks, specialized agents with MCP tools, and resumable workflows.
---
# Agent Orchestrator Skill
## What & When
**What**: Commands for managing specialized Claude AI agent sessions with optional agent definitions and MCP server integration.
**When to use**:
- Delegate tasks to specialized sessions with different MCP configurations
- Run long-running operations that can be resumed later
- Use agent definitions for specialized behavior (research, testing, etc.)
- Manage multiple concurrent agent conversations
- Work with persistent sessions using simple names (no session ID management)
**Key Benefits**:
- Session names instead of session IDs (simpler tracking)
- Automatic session management and persistence
- Built-in result extraction (no manual JSON parsing)
- Optional agent definitions for specialized capabilities
- Sessions can be resumed (even after finished)
---
## Quick Reference
### `ao-new` - Create new session
```bash
uv run commands/ao-new <session-name>
```
**Use when**: Starting a new Claude agent session. Reads prompt from stdin or `-p` flag.
### `ao-resume` - Continue existing session
```bash
uv run commands/ao-resume <session-name>
```
**Use when**: Adding messages to an existing session. Reads prompt from stdin or `-p` flag.
### `ao-status` - Check session state
```bash
uv run commands/ao-status <session-name>
```
**Use when**: Need to know if session is `running`, `finished`, or `not_existent`.
### `ao-get-result` - Extract result from finished session
```bash
uv run commands/ao-get-result <session-name>
```
**Use when**: Session is finished and you need the final result text.
### `ao-list-sessions` - List all sessions
```bash
uv run commands/ao-list-sessions
```
**Use when**: Need to see available sessions with their IDs and project directories.
### `ao-list-agents` - List available agent definitions
```bash
uv run commands/ao-list-agents
```
**Use when**: Need to see what specialized agent definitions are available.
### `ao-show-config` - Display session configuration
```bash
uv run commands/ao-show-config <session-name>
```
**Use when**: Need to see session metadata (project dir, agent used, timestamps, etc.).
### `ao-clean` - Remove all sessions
```bash
uv run commands/ao-clean
```
**Use when**: Need to delete all session data. **Use with caution.**
---
## Command Location
**IMPORTANT**: All commands are located in the `commands/` subdirectory of this skill folder.
Before using commands for the first time:
1. Locate this skill's root folder (same directory as this SKILL.md)
2. Commands are in: `<skill-root>/commands/ao-*`
3. Execute using: `uv run <skill-root>/commands/ao-<command> <args>`
**Example**:
```bash
# If skill is at /path/to/skills/agent-orchestrator
uv run /path/to/skills/agent-orchestrator/commands/ao-new my-session -p "Research topic X"
```
---
## Parameters Reference
### Required
- `<session-name>` - Alphanumeric + dash/underscore, max 60 chars (e.g., `research-task`, `code_review_123`)
### Common Options
- `-p "prompt"` or `--prompt "prompt"` - Provide prompt via CLI instead of stdin
- `--agent <agent-name>` - Use specialized agent definition (only for `ao-new`)
- `--project-dir <path>` - Override project directory (default: current directory)
---
## Typical Workflows
### Basic Session Workflow
```bash
# Create new session
echo "Analyze this codebase structure" | uv run commands/ao-new analysis
# Check status
uv run commands/ao-status analysis # Output: finished
# Get result
uv run commands/ao-get-result analysis
# Resume with follow-up
echo "Now focus on security patterns" | uv run commands/ao-resume analysis
```
### Using Specialized Agents
```bash
# List available agents
uv run commands/ao-list-agents
# Create session with specific agent
uv run commands/ao-new research-task --agent web-researcher -p "Research Claude AI capabilities"
# View agent configuration
uv run commands/ao-show-config research-task
```
### Managing Sessions
```bash
# List all active sessions
uv run commands/ao-list-sessions
# Check specific session
uv run commands/ao-status my-session
# Clean up all sessions
uv run commands/ao-clean
```
---
## Key Concepts
### Session States
- **`not_existent`** - Session doesn't exist
- **`running`** - Session active, ready to resume
- **`finished`** - Session complete, result available
### Working Directory
- Sessions operate in `--project-dir` (default: current directory)
- All file operations within the session are relative to this directory
### Agents vs Sessions
- **Agent**: Reusable configuration (system prompt + MCP tools)
- **Session**: Running conversation instance
- One agent can be used by multiple sessions
- Sessions can run without agents (general purpose)
---
## Notes for AI Assistants
1. **Always check status** before resuming: `ao-status <name>` → only resume if `running` or `finished`
2. **Session names** must be unique and valid (no spaces, max 60 chars, alphanumeric + dash/underscore)
3. **Prompt input**: Use stdin (pipe) OR `-p` flag, not both (stdin takes precedence)
4. **Get result** only works on `finished` sessions - check status first
5. **Agent definitions** are read-only - list them with `ao-list-agents` before using `--agent`
6. **Sessions are persistent** - they survive between command invocations
7. **Command location** - Always use commands from this skill's `commands/` folder
8. **Async execution** - Sessions run in Claude Code, commands return immediately after submission
---
## Error Handling
Common errors and solutions:
| Error | Cause | Solution |
|-------|-------|----------|
| "Session already exists" | Creating duplicate session | Use `ao-resume` or choose different name |
| "Session not found" | Wrong name or doesn't exist | Check `ao-list-sessions` |
| "Session is not finished" | Getting result from running session | Check `ao-status`, wait for `finished` |
| "Invalid session name" | Bad characters or too long | Use alphanumeric + dash/underscore, max 60 chars |
| "No prompt provided" | Missing `-p` and stdin | Provide prompt via stdin or `-p` flag |
| "Agent not found" | Agent definition missing | Check `ao-list-agents` for available agents |
---
## Exit Codes
- `0` - Success
- `1` - Error (invalid input, session not found, etc.)
---
## Quick Decision Tree
**Want to start a new agent conversation?**`ao-new <name>`
- With specialized agent? → Add `--agent <agent-name>`
- In specific location? → Add `--project-dir <path>`
**Want to continue a conversation?**`ao-resume <name>`
- Not sure if it exists? → Check with `ao-status <name>` first
**Want to see the result?**`ao-get-result <name>`
- Must check status first → `ao-status <name>` (must be `finished`)
**Want to see what exists?**
- Sessions → `ao-list-sessions`
- Agents → `ao-list-agents`
**Want session details?**`ao-show-config <name>`
**Want to clean up?**`ao-clean` (removes all sessions)
---
## Additional Resources
- **Example Agents**: See `example/agents/` folder for working examples
- **Agent Details & Usage**: See `references/EXAMPLE-AGENTS.md`
- **Architecture & Agent Creation**: See `references/AGENT-ORCHESTRATOR.md`
- **Environment Variables**: See `references/ENV_VARS.md` for configuration options

View File

@@ -0,0 +1,95 @@
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "typer",
# "httpx",
# ]
# ///
"""
Remove all agent orchestrator sessions.
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent / "lib"))
import typer
from typing import Optional
import httpx
app = typer.Typer(add_completion=False)
def delete_from_observability(session_id: str, observability_url: str) -> bool:
"""
Delete session from observability backend.
Returns True if successful or session not found, False on error.
"""
try:
response = httpx.delete(
f"{observability_url}/sessions/{session_id}",
timeout=2.0
)
# 200 = deleted, 404 = not found (both OK)
return response.status_code in (200, 404)
except Exception:
# Silent failure - don't block cleanup
return False
@app.command()
def main(
project_dir: Optional[Path] = typer.Option(None, "--project-dir", help="Project directory"),
sessions_dir: Optional[Path] = typer.Option(None, "--sessions-dir", help="Sessions directory"),
):
"""
Remove all sessions.
Examples:
ao-clean
ao-clean --sessions-dir /custom/path
"""
from config import load_config
from session import list_all_sessions
import shutil
try:
# Load configuration with CLI overrides
config = load_config(
cli_project_dir=str(project_dir) if project_dir else None,
cli_sessions_dir=str(sessions_dir) if sessions_dir else None,
cli_agents_dir=None,
)
# Check if sessions directory exists
if config.sessions_dir.exists():
# Delete from observability if enabled
if config.observability_enabled:
try:
sessions = list_all_sessions(config.sessions_dir)
for session_name, session_id, project_dir_path in sessions:
if session_id and session_id != "unknown":
delete_from_observability(
session_id,
config.observability_url
)
except Exception:
# Ignore errors - sessions might not exist or be incomplete
pass
# Remove entire directory
shutil.rmtree(config.sessions_dir)
print("All sessions removed")
else:
print("No sessions to remove")
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
raise typer.Exit(1)
if __name__ == "__main__":
app()

View File

@@ -0,0 +1,80 @@
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "typer",
# ]
# ///
"""
Extract the result from a completed agent orchestrator session.
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent / "lib"))
import typer
from typing import Optional
app = typer.Typer(add_completion=False)
@app.command()
def main(
session_name: str = typer.Argument(..., help="Name of the session"),
project_dir: Optional[Path] = typer.Option(None, "--project-dir", help="Project directory"),
sessions_dir: Optional[Path] = typer.Option(None, "--sessions-dir", help="Sessions directory"),
):
"""
Extract the result from a completed session.
Examples:
ao-get-result mysession
"""
from config import load_config
from session import validate_session_name, get_session_status, extract_result
try:
# Validate session name
validate_session_name(session_name)
# Load configuration with CLI overrides
config = load_config(
cli_project_dir=str(project_dir) if project_dir else None,
cli_sessions_dir=str(sessions_dir) if sessions_dir else None,
cli_agents_dir=None,
)
# Check session status
status = get_session_status(session_name, config.sessions_dir)
if status == "not_existent":
print(f"Error: Session '{session_name}' does not exist", file=sys.stderr)
raise typer.Exit(1)
if status == "running":
print(f"Error: Session '{session_name}' is still running. Wait for completion or check status with ao-status.", file=sys.stderr)
raise typer.Exit(1)
# Extract and print result
session_file = config.sessions_dir / f"{session_name}.jsonl"
result = extract_result(session_file)
print(result)
except ValueError as e:
# Session validation errors or result extraction errors
print(f"Error: {e}", file=sys.stderr)
raise typer.Exit(1)
except FileNotFoundError as e:
# Session file not found
print(f"Error: {e}", file=sys.stderr)
raise typer.Exit(1)
except Exception as e:
# Unexpected errors
print(f"Error: {e}", file=sys.stderr)
raise typer.Exit(1)
if __name__ == "__main__":
app()

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "typer",
# ]
# ///
"""
List all available agent definitions.
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent / "lib"))
import typer
from typing import Optional
from config import load_config
from agent import list_all_agents
app = typer.Typer(add_completion=False)
@app.command()
def main(
project_dir: Optional[Path] = typer.Option(None, "--project-dir", help="Project directory"),
agents_dir: Optional[Path] = typer.Option(None, "--agents-dir", help="Agents directory"),
):
"""
List all available agent definitions.
Displays: agent name, description
Examples:
ao-list-agents
ao-list-agents --agents-dir /path/to/agents
ao-list-agents --project-dir /my/project
"""
# 1. Load configuration
config = load_config(
cli_project_dir=str(project_dir) if project_dir else None,
cli_agents_dir=str(agents_dir) if agents_dir else None,
)
# 2. Get list of agents (list_all_agents handles missing directory gracefully)
agents = list_all_agents(config.agents_dir)
# 3. Handle empty case
if not agents:
print("No agent definitions found")
return
# 4. Display agents with bash-compatible formatting
first = True
for name, description in agents:
if first:
first = False
else:
# Add separator before subsequent agents
print("---")
print()
print(f"{name}:")
print(description)
print()
if __name__ == "__main__":
app()

View File

@@ -0,0 +1,74 @@
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "typer",
# ]
# ///
"""
List all agent orchestrator sessions with metadata.
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent / "lib"))
import typer
from typing import Optional
app = typer.Typer(add_completion=False)
@app.command()
def main(
project_dir: Optional[Path] = typer.Option(None, "--project-dir", help="Project directory"),
sessions_dir: Optional[Path] = typer.Option(None, "--sessions-dir", help="Sessions directory"),
):
"""
List all sessions with metadata.
Displays: session name (session-id: session_id, project-dir: project_dir)
Examples:
ao-list-sessions
ao-list-sessions --sessions-dir /custom/path
"""
from config import load_config
from session import list_all_sessions
from utils import debug_log
# DEBUG LOGGING - Command entry
debug_log("COMMAND - ao-list-sessions", {
"cwd": str(Path.cwd()),
"argv": sys.argv,
"project_dir": str(project_dir) if project_dir else "None",
"sessions_dir": str(sessions_dir) if sessions_dir else "None",
})
try:
# Load configuration with CLI overrides
config = load_config(
cli_project_dir=str(project_dir) if project_dir else None,
cli_sessions_dir=str(sessions_dir) if sessions_dir else None,
cli_agents_dir=None,
)
# Get all sessions (list_all_sessions handles missing directory gracefully)
sessions = list_all_sessions(config.sessions_dir)
# Display results
if not sessions:
print("No sessions found")
else:
for session_name, session_id, project_dir_path in sessions:
print(f"{session_name} (session-id: {session_id}, project-dir: {project_dir_path})")
except Exception as e:
# Handle errors
print(f"Error: {e}", file=sys.stderr)
raise typer.Exit(1)
if __name__ == "__main__":
app()

View File

@@ -0,0 +1,186 @@
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "claude-agent-sdk",
# "typer",
# "httpx",
# ]
# ///
"""
Create a new agent orchestrator session.
This command creates a new Claude AI session, optionally with an agent configuration.
"""
import sys
from pathlib import Path
# Add lib to path for shared modules
sys.path.insert(0, str(Path(__file__).parent / "lib"))
import typer
from typing import Optional
app = typer.Typer(add_completion=False)
@app.command()
def main(
session_name: str = typer.Argument(..., help="Name of the session"),
prompt: Optional[str] = typer.Option(None, "-p", "--prompt", help="Session prompt"),
agent: Optional[str] = typer.Option(None, "--agent", help="Agent to use"),
project_dir: Optional[Path] = typer.Option(None, "--project-dir", help="Project directory"),
sessions_dir: Optional[Path] = typer.Option(None, "--sessions-dir", help="Sessions directory"),
agents_dir: Optional[Path] = typer.Option(None, "--agents-dir", help="Agents directory"),
):
"""
Create a new agent orchestrator session.
Examples:
ao-new mysession -p "Write hello world"
ao-new research --agent web-researcher -p "Research AI"
cat prompt.md | ao-new mysession
"""
from config import load_config
from session import (
validate_session_name,
get_session_status,
save_session_metadata,
)
from agent import load_agent_config, build_mcp_servers_dict
from claude_client import run_session_sync
from utils import (
get_prompt_from_args_and_stdin,
ensure_directory_exists,
log_command,
log_result,
error_exit,
debug_log,
)
# DEBUG LOGGING - Command entry
debug_log("COMMAND - ao-new", {
"cwd": str(Path.cwd()),
"argv": sys.argv,
"session_name": session_name,
"prompt": prompt or "None (will read from stdin)",
"agent": agent or "None",
"project_dir": str(project_dir) if project_dir else "None",
"sessions_dir": str(sessions_dir) if sessions_dir else "None",
"agents_dir": str(agents_dir) if agents_dir else "None",
})
try:
# 1. Validate session name
validate_session_name(session_name)
# 2. Load configuration
config = load_config(
cli_project_dir=str(project_dir) if project_dir else None,
cli_sessions_dir=str(sessions_dir) if sessions_dir else None,
cli_agents_dir=str(agents_dir) if agents_dir else None,
)
# 3. Check session doesn't already exist
status = get_session_status(session_name, config.sessions_dir)
if status != "not_existent":
error_exit(
f"Session '{session_name}' already exists. "
"Use 'ao-resume' command to continue or choose a different name"
)
# 4. Get prompt (from -p and/or stdin)
user_prompt = get_prompt_from_args_and_stdin(prompt)
# 5. Load agent if specified
final_prompt = user_prompt
mcp_servers = None
agent_name = None
if agent:
agent_config = load_agent_config(agent, config.agents_dir)
agent_name = agent_config.name
# Prepend system prompt if available
if agent_config.system_prompt:
final_prompt = f"{agent_config.system_prompt}\n\n---\n\n{user_prompt}"
# Build MCP servers dict
mcp_servers = build_mcp_servers_dict(agent_config.mcp_config)
# 6. Ensure directories exist
ensure_directory_exists(config.sessions_dir)
# 7. STAGE 1: Save initial session metadata WITHOUT session_id
# This allows users to see the session was started
save_session_metadata(
session_name=session_name,
agent=agent_name,
project_dir=config.project_dir,
agents_dir=config.agents_dir,
sessions_dir=config.sessions_dir,
session_id=None, # Will be added in Stage 2 during streaming
)
# 8. Log command (if logging enabled)
if config.enable_logging:
# Build command string for logging (similar to bash)
mcp_info = f"with MCP servers: {list(mcp_servers.keys())}" if mcp_servers else "no MCP"
full_command = (
f"cd {config.project_dir} && "
f"query(prompt=<prompt>, cwd={config.project_dir}, "
f"permission_mode=bypassPermissions, {mcp_info})"
)
log_command(
session_name=session_name,
command_type="new",
agent_name=agent_name,
mcp_config_path=str(agent_config.mcp_config) if agent and agent_config.mcp_config else None,
full_command=full_command,
prompt=final_prompt,
sessions_dir=config.sessions_dir,
project_dir=config.project_dir,
agents_dir=config.agents_dir,
enable_logging=config.enable_logging,
)
# 9. Run Claude session
# STAGE 2 happens automatically during streaming when session_id is received
session_file = config.sessions_dir / f"{session_name}.jsonl"
session_id, result = run_session_sync(
prompt=final_prompt,
session_file=session_file,
project_dir=config.project_dir,
session_name=session_name, # For Stage 2 metadata update
sessions_dir=config.sessions_dir, # For Stage 2 metadata update
mcp_servers=mcp_servers,
observability_enabled=config.observability_enabled,
observability_url=config.observability_url,
agent_name=agent_name,
)
# 10. Log result (if logging enabled)
if config.enable_logging:
log_result(session_name, result, config.sessions_dir, config.enable_logging)
# 11. Print result to stdout
print(result)
except ValueError as e:
# Session validation errors, prompt errors, etc.
error_exit(str(e))
except FileNotFoundError as e:
# Agent not found, config file issues, etc.
error_exit(str(e))
except ImportError as e:
# SDK not installed
error_exit(str(e))
except Exception as e:
# Unexpected errors (SDK errors, etc.)
error_exit(f"Unexpected error: {e}")
if __name__ == "__main__":
app()

View File

@@ -0,0 +1,196 @@
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "claude-agent-sdk",
# "typer",
# "httpx",
# ]
# ///
"""
Resume an existing agent orchestrator session.
This command continues a previous session with a new prompt.
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent / "lib"))
import typer
from typing import Optional
app = typer.Typer(add_completion=False)
@app.command()
def main(
session_name: str = typer.Argument(..., help="Name of the session"),
prompt: Optional[str] = typer.Option(None, "-p", "--prompt", help="Continuation prompt"),
project_dir: Optional[Path] = typer.Option(None, "--project-dir", help="Project directory"),
sessions_dir: Optional[Path] = typer.Option(None, "--sessions-dir", help="Sessions directory"),
agents_dir: Optional[Path] = typer.Option(None, "--agents-dir", help="Agents directory"),
):
"""
Resume an existing agent orchestrator session.
Examples:
ao-resume mysession -p "Add error handling"
cat additional-requirements.md | ao-resume mysession
"""
from config import load_config
from session import (
validate_session_name,
get_session_status,
load_session_metadata,
update_session_metadata,
)
from agent import load_agent_config, build_mcp_servers_dict
from claude_client import run_session_sync
from utils import (
get_prompt_from_args_and_stdin,
log_command,
log_result,
error_exit,
debug_log,
)
# DEBUG LOGGING - Command entry
debug_log("COMMAND - ao-resume", {
"cwd": str(Path.cwd()),
"argv": sys.argv,
"session_name": session_name,
"prompt": prompt or "None (will read from stdin)",
"project_dir": str(project_dir) if project_dir else "None",
"sessions_dir": str(sessions_dir) if sessions_dir else "None",
"agents_dir": str(agents_dir) if agents_dir else "None",
})
try:
# 1. Validate session name
validate_session_name(session_name)
# 2. Load configuration
config = load_config(
cli_project_dir=str(project_dir) if project_dir else None,
cli_sessions_dir=str(sessions_dir) if sessions_dir else None,
cli_agents_dir=str(agents_dir) if agents_dir else None,
)
# 3. Check session exists
status = get_session_status(session_name, config.sessions_dir)
if status == "not_existent":
error_exit(
f"Session '{session_name}' does not exist. "
"Use 'ao-new' command to create it"
)
# 4. Load session metadata (contains session_id, agent, paths)
metadata = load_session_metadata(session_name, config.sessions_dir)
# 5. Context consistency validation
# Warn if CLI overrides differ from metadata (but don't fail)
if project_dir and Path(project_dir).resolve() != metadata.project_dir:
print(
f"Warning: --project-dir override ignored. "
f"Using session metadata value: {metadata.project_dir}",
file=sys.stderr,
)
if agents_dir and Path(agents_dir).resolve() != metadata.agents_dir:
print(
f"Warning: --agents-dir override ignored. "
f"Using session metadata value: {metadata.agents_dir}",
file=sys.stderr,
)
# 6. Extract session_id from metadata
resume_session_id = metadata.session_id
if not resume_session_id:
error_exit(
f"Session '{session_name}' has no session_id in metadata. "
"Cannot resume incomplete session"
)
# 7. Get prompt (from -p and/or stdin)
user_prompt = get_prompt_from_args_and_stdin(prompt)
# 8. Load agent configuration if session has agent
# NOTE: Do NOT prepend system prompt for resume (only for new sessions)
mcp_servers = None
agent_config = None
if metadata.agent:
agent_config = load_agent_config(metadata.agent, metadata.agents_dir)
# Build MCP servers dict for SDK
mcp_servers = build_mcp_servers_dict(agent_config.mcp_config)
# 9. Log command (if logging enabled)
if config.enable_logging:
# Build command string for logging (similar to bash)
mcp_info = f"with MCP servers: {list(mcp_servers.keys())}" if mcp_servers else "no MCP"
full_command = (
f"cd {metadata.project_dir} && "
f"query(prompt=<prompt>, cwd={metadata.project_dir}, "
f"permission_mode=bypassPermissions, resume={resume_session_id}, {mcp_info})"
)
log_command(
session_name=session_name,
command_type="resume",
agent_name=metadata.agent,
mcp_config_path=str(agent_config.mcp_config) if agent_config and agent_config.mcp_config else None,
full_command=full_command,
prompt=user_prompt,
sessions_dir=config.sessions_dir,
project_dir=config.project_dir,
agents_dir=config.agents_dir,
enable_logging=config.enable_logging,
)
# 10. Run Claude session with resume
# Use metadata paths (not CLI overrides) to ensure context consistency
session_file = config.sessions_dir / f"{session_name}.jsonl"
session_id, result = run_session_sync(
prompt=user_prompt, # No system prompt prepended!
session_file=session_file,
project_dir=metadata.project_dir, # From metadata
session_name=session_name,
sessions_dir=config.sessions_dir,
mcp_servers=mcp_servers,
resume_session_id=resume_session_id, # KEY: Enable resume
observability_enabled=config.observability_enabled,
observability_url=config.observability_url,
agent_name=metadata.agent,
)
# 11. Update session metadata timestamp
update_session_metadata(session_name, config.sessions_dir)
# 12. Log result (if logging enabled)
if config.enable_logging:
log_result(session_name, result, config.sessions_dir, config.enable_logging)
# 13. Print result to stdout
print(result)
except ValueError as e:
# Session validation errors, prompt errors, etc.
error_exit(str(e))
except FileNotFoundError as e:
# Session not found, agent not found, etc.
error_exit(str(e))
except ImportError as e:
# SDK not installed
error_exit(
f"Claude SDK not installed: {e}\n"
"Install with: uv pip install claude-agent-sdk"
)
except Exception as e:
# Unexpected errors (SDK errors, etc.)
error_exit(f"Unexpected error: {e}")
if __name__ == "__main__":
app()

View File

@@ -0,0 +1,92 @@
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "typer",
# ]
# ///
"""
Display session configuration and context.
"""
import sys
import json
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent / "lib"))
import typer
from typing import Optional
app = typer.Typer(add_completion=False)
@app.command()
def main(
session_name: str = typer.Argument(..., help="Name of the session"),
project_dir: Optional[Path] = typer.Option(None, "--project-dir", help="Project directory"),
sessions_dir: Optional[Path] = typer.Option(None, "--sessions-dir", help="Sessions directory"),
):
"""
Display session configuration and context.
Shows: agent used, directories, session metadata
Examples:
ao-show-config mysession
ao-show-config mysession --project-dir /my/project
"""
from config import load_config
from session import validate_session_name, load_session_metadata
try:
# Validate session name
validate_session_name(session_name)
# Load configuration with CLI overrides
config = load_config(
cli_project_dir=str(project_dir) if project_dir else None,
cli_sessions_dir=str(sessions_dir) if sessions_dir else None,
cli_agents_dir=None,
)
# Check if session exists
meta_file = config.sessions_dir / f"{session_name}.meta.json"
if not meta_file.exists():
print(f"Error: Session '{session_name}' does not exist", file=sys.stderr)
raise typer.Exit(1)
# Load session metadata
metadata = load_session_metadata(session_name, config.sessions_dir)
# Display configuration matching bash format
print(f"Configuration for session '{session_name}':")
print(f" Session file: {config.sessions_dir}/{session_name}.jsonl")
print(f" Project dir: {metadata.project_dir} (from meta.json)")
print(f" Agents dir: {metadata.agents_dir} (from meta.json)")
print(f" Sessions dir: {config.sessions_dir} (current)")
print(f" Agent: {metadata.agent if metadata.agent else 'none'}")
print(f" Created: {metadata.created_at.isoformat()}Z")
print(f" Last resumed: {metadata.last_resumed_at.isoformat()}Z")
print(f" Schema version: {metadata.schema_version}")
except ValueError as e:
# Session validation errors
print(f"Error: {e}", file=sys.stderr)
raise typer.Exit(1)
except FileNotFoundError as e:
# Session metadata not found
print(f"Error: {e}", file=sys.stderr)
raise typer.Exit(1)
except (json.JSONDecodeError, KeyError) as e:
# JSON parsing errors
print(f"Error: Invalid session metadata: {e}", file=sys.stderr)
raise typer.Exit(1)
except Exception as e:
# Unexpected errors
print(f"Error: {e}", file=sys.stderr)
raise typer.Exit(1)
if __name__ == "__main__":
app()

View File

@@ -0,0 +1,68 @@
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "typer",
# ]
# ///
"""
Check the status of an agent orchestrator session.
Returns: running, finished, or not_existent
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent / "lib"))
import typer
from typing import Optional
app = typer.Typer(add_completion=False)
@app.command()
def main(
session_name: str = typer.Argument(..., help="Name of the session"),
project_dir: Optional[Path] = typer.Option(None, "--project-dir", help="Project directory"),
sessions_dir: Optional[Path] = typer.Option(None, "--sessions-dir", help="Sessions directory"),
):
"""
Check the status of a session.
Outputs one of: running, finished, not_existent
Examples:
ao-status mysession
"""
from config import load_config
from session import validate_session_name, get_session_status
try:
# Validate session name
validate_session_name(session_name)
# Load configuration with CLI overrides
config = load_config(
cli_project_dir=str(project_dir) if project_dir else None,
cli_sessions_dir=str(sessions_dir) if sessions_dir else None,
cli_agents_dir=None,
)
# Get and print session status
status = get_session_status(session_name, config.sessions_dir)
print(status)
except ValueError as e:
# Session validation errors
print(f"Error: {e}", file=sys.stderr)
raise typer.Exit(1)
except Exception as e:
# Unexpected errors
print(f"Error: {e}", file=sys.stderr)
raise typer.Exit(1)
if __name__ == "__main__":
app()

View File

@@ -0,0 +1,4 @@
{
"name": "browser-tester",
"description": "Specialist in browser automation and end-to-end testing using Playwright"
}

View File

@@ -0,0 +1,10 @@
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest"
]
}
}
}

View File

@@ -0,0 +1,22 @@
You are a browser automation and testing specialist with expertise in end-to-end testing using Playwright.
Your expertise includes:
- Browser automation across Chromium, Firefox, and WebKit
- End-to-end test design and implementation
- Test selectors and locator strategies
- Handling async operations and waiters
- Screenshot and video capture for debugging
- Cross-browser compatibility testing
- Accessibility testing
When creating tests:
1. Write clear, maintainable test code
2. Use reliable selectors (prefer data-testid, role, or text)
3. Implement proper wait strategies
4. Add meaningful assertions
5. Consider edge cases and error scenarios
6. Follow Playwright best practices
You have access to the Playwright MCP server which provides browser automation capabilities. Use it to navigate web pages, interact with elements, take screenshots, and verify behavior.
Be practical and focus on creating robust, reliable tests that provide real value.

View File

@@ -0,0 +1,27 @@
# Confluence Researcher Agent
This agent uses the **mcp-atlassian** MCP server for Confluence integration.
**MCP Server:** [sooperset/mcp-atlassian](https://github.com/sooperset/mcp-atlassian)
## Environment Variables
This agent requires Atlassian credentials. Set these in `.claude/settings.local.json`:
```json
{
"env": {
"CONFLUENCE_URL": "https://your-domain.atlassian.net",
"CONFLUENCE_USERNAME": "your-email@example.com",
"CONFLUENCE_API_TOKEN": "your-confluence-api-token"
}
}
```
## Required Variables
- `CONFLUENCE_URL` - Your Confluence instance URL
- `CONFLUENCE_USERNAME` - Your Confluence email
- `CONFLUENCE_API_TOKEN` - Confluence API token (generate at atlassian.com)
**Note:** The tokens can be the same if using a unified Atlassian account.

View File

@@ -0,0 +1,4 @@
{
"name": "confluence-researcher",
"description": "Conducts iterative Confluence research to answer questions, generates concise answers with documented JSON sources. Input: working_folder (path for sources file), question (research query)"
}

View File

@@ -0,0 +1,19 @@
{
"mcpServers": {
"mcp-atlassian": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e", "CONFLUENCE_URL",
"-e", "CONFLUENCE_USERNAME",
"-e", "CONFLUENCE_API_TOKEN",
"-e", "JIRA_URL",
"-e", "JIRA_USERNAME",
"-e", "JIRA_API_TOKEN",
"ghcr.io/sooperset/mcp-atlassian:latest"
]
}
}
}

View File

@@ -0,0 +1,86 @@
You are a Confluence Research Specialist with expertise in conducting thorough, iterative Confluence searches to answer user questions.
Your expertise includes:
- Formulating effective Confluence CQL (Confluence Query Language) queries
- Evaluating search result relevance
- Extracting key information from Confluence pages
- Iteratively refining searches when information is insufficient
- Documenting sources with precision
## Workflow
When conducting research:
1. **Initial Search**
- Use the mcp__mcp-atlassian__confluence_search tool with a well-crafted query based on the user's question
- Analyze the search results to identify the most promising pages
- You can use simple text queries or CQL queries
2. **Fetch & Evaluate**
- Use the mcp__mcp-atlassian__confluence_get_page tool to retrieve content from the top relevant results
- Evaluate if the fetched information is sufficient to answer the question
- Track which page IDs and URLs actually contributed to your answer
3. **Iterate if Needed**
- If information is insufficient, formulate a refined search query
- Adjust your search strategy based on what you've learned
- Consider using CQL for more precise searches (e.g., 'type=page AND space=DEV')
- Repeat the fetch and evaluate process
- Continue until you have adequate information
4. **Generate Answer, Result File & Sources File**
- Create a result markdown file summarizing your findings
- Provide a concise, direct answer to the research question
- Create a JSON sources file in the specified working folder
- Only include pages that actually contributed to your answer
- Reference the sources file and the result file in your response
## Input Expectations
You will receive:
- **working_folder**: The directory path where you should save the sources JSON file and the result file
- **question**: The research question to investigate
## Output Requirements
Your response must be:
- **Concise**: Brief and to-the-point answer
- **Accurate**: Based only on fetched information
- **Sourced**: Reference the JSON sources file you created and also the result file
### Sources File Format
Create a JSON file named `research-sources.json` in the working folder with this structure:
```json
{
"question": "The original research question",
"sources": [
{
"page_id": "123456789",
"url": "https://your-instance.atlassian.net/wiki/spaces/SPACE/pages/123456789/Page+Title",
"title": "Page title",
"space": "SPACE",
"relevance": "Why this source was used"
}
],
"search_iterations": 2,
"timestamp": "ISO 8601 timestamp"
}
```
### Result File
Create a result markdown file named `research-result.md` summarizing your findings.
## Quality Standards
- Only document sources that directly contributed to your answer
- Be strategic with search queries - adjust them intelligently
- Avoid redundant searches
- Prioritize authoritative and recent pages
- Keep your final answer concise but complete
Be practical, thorough in research, but concise in communication.

View File

@@ -0,0 +1,27 @@
# Jira Researcher Agent
This agent uses the **mcp-atlassian** MCP server for Jira integration.
**MCP Server:** [sooperset/mcp-atlassian](https://github.com/sooperset/mcp-atlassian)
## Environment Variables
This agent requires Jira credentials. Set these in `.claude/settings.local.json`:
```json
{
"env": {
"JIRA_URL": "https://your-domain.atlassian.net",
"JIRA_USERNAME": "your-email@example.com",
"JIRA_API_TOKEN": "your-jira-api-token"
}
}
```
## Required Variables
- `JIRA_URL` - Your Jira instance URL
- `JIRA_USERNAME` - Your Jira email
- `JIRA_API_TOKEN` - Jira API token (generate at atlassian.com)
**Note:** If the MCP server also supports Confluence, you may need to include Confluence variables as well, but they are not required for Jira-only operations.

View File

@@ -0,0 +1,4 @@
{
"name": "jira-researcher",
"description": "Conducts iterative Jira research to answer questions using JQL queries, generates concise answers with documented JSON sources. Input: working_folder (path for sources file), question (research query)"
}

View File

@@ -0,0 +1,19 @@
{
"mcpServers": {
"mcp-atlassian": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e", "CONFLUENCE_URL",
"-e", "CONFLUENCE_USERNAME",
"-e", "CONFLUENCE_API_TOKEN",
"-e", "JIRA_URL",
"-e", "JIRA_USERNAME",
"-e", "JIRA_API_TOKEN",
"ghcr.io/sooperset/mcp-atlassian:latest"
]
}
}
}

View File

@@ -0,0 +1,93 @@
You are a Jira Research Specialist with expertise in conducting thorough, iterative Jira searches to answer user questions.
Your expertise includes:
- Formulating effective JQL (Jira Query Language) queries
- Evaluating search result relevance
- Extracting key information from Jira issues
- Analyzing linked issues when they provide relevant context
- Iteratively refining searches when information is insufficient
- Documenting sources with precision
## Workflow
When conducting research:
1. **Initial Search**
- Use the mcp__mcp-atlassian__jira_search tool with a well-crafted JQL query based on the user's question
- Analyze the search results to identify the most promising issues
- You can use simple text queries or JQL queries
- Example JQL: 'project = PROJ AND status != Closed AND text ~ "keyword"'
2. **Fetch & Evaluate**
- Use the mcp__mcp-atlassian__jira_get_issue tool to retrieve content from the top relevant results
- Initially focus on issue key, summary, description, status, and assignee
- If prompted for deeper search, also examine comments using the appropriate tool
- Check linked issues to determine if they provide helpful context
- Evaluate if the fetched information is sufficient to answer the question
- Track which issue keys and URLs actually contributed to your answer
3. **Iterate if Needed**
- If information is insufficient, formulate a refined JQL query
- Adjust your search strategy based on what you've learned
- Consider refining by project, status, issue type, or other fields
- Example refined JQL: 'project = PROJ AND issuetype = Bug AND status = Open'
- Repeat the fetch and evaluate process
- Continue until you have adequate information
4. **Generate Answer, Result File & Sources File**
- Create a result markdown file summarizing your findings
- Provide a concise, direct answer to the research question
- Create a JSON sources file in the specified working folder
- Only include issues that actually contributed to your answer
- Reference the sources file and the result file in your response
## Input Expectations
You will receive:
- **working_folder**: The directory path where you should save the sources JSON file and the result file
- **question**: The research question to investigate
## Output Requirements
Your response must be:
- **Concise**: Brief and to-the-point answer
- **Accurate**: Based only on fetched information
- **Sourced**: Reference the JSON sources file you created and also the result file
### Sources File Format
Create a JSON file named `research-sources.json` in the working folder with this structure:
```json
{
"question": "The original research question",
"sources": [
{
"key": "PROJ-123",
"url": "https://your-instance.atlassian.net/browse/PROJ-123",
"title": "Issue summary",
"relevance": "Why this source was used"
}
],
"search_iterations": 2,
"timestamp": "ISO 8601 timestamp"
}
```
### Result File
Create a result markdown file named `research-result.md` summarizing your findings.
## Quality Standards
- Only document sources that directly contributed to your answer
- Be strategic with JQL queries - adjust them intelligently
- Avoid redundant searches
- Prioritize relevant issues based on status, priority, and recency
- When project scope is specified in JQL, respect those boundaries
- Check linked issues only when they add relevant context
- Keep your final answer concise but complete
Be practical, thorough in research, but concise in communication.

View File

@@ -0,0 +1,4 @@
{
"name": "web-researcher",
"description": "Conducts iterative web research to answer questions, generates concise answers with documented JSON sources. Input: working_folder (path for sources file), question (research query)"
}

View File

@@ -0,0 +1,82 @@
You are a Web Research Specialist with expertise in conducting thorough, iterative internet research to answer user questions.
Your expertise includes:
- Formulating effective web search queries
- Evaluating search result relevance
- Extracting key information from web pages
- Iteratively refining searches when information is insufficient
- Documenting sources with precision
## Workflow
When conducting research:
1. **Initial Search**
- Use the WebSearch tool with a well-crafted query based on the user's question
- Analyze the search results to identify the most promising sources
2. **Fetch & Evaluate**
- Use the WebFetch tool to retrieve content from the top relevant results
- Evaluate if the fetched information is sufficient to answer the question
- Track which URLs actually contributed to your answer
3. **Iterate if Needed**
- If information is insufficient, formulate a refined search query
- Adjust your search strategy based on what you've learned
- Repeat the fetch and evaluate process
- Continue until you have adequate information
4. **Generate Answer, Result File & Sources File**
- Create an result mardown file summarizing your findings
- Provide a concise, direct answer to the research question
- Create a JSON sources file in the specified working folder
- Only include URLs that actually contributed to your answer
- Reference the sources file and the result file in your response
## Input Expectations
You will receive:
- **working_folder**: The directory path where you should save the sources JSON file and the result file
- **question**: The research question to investigate
## Output Requirements
Your response must be:
- **Concise**: Brief and to-the-point answer
- **Accurate**: Based only on fetched information
- **Sourced**: Reference the JSON sources file you created and also the result file
### Sources File Format
Create a JSON file named `research-sources.json` in the working folder with this structure:
```json
{
"question": "The original research question",
"sources": [
{
"url": "https://example.com/page1",
"title": "Page title or brief description",
"relevance": "Why this source was used"
}
],
"search_iterations": 2,
"timestamp": "ISO 8601 timestamp"
}
```
### Result File
Create a result markdown file name `research-result.md` summarizing your findings.
## Quality Standards
- Only document sources that directly contributed to your answer
- Be strategic with search queries - adjust them intelligently
- Avoid redundant searches
- Prioritize authoritative and recent sources
- Keep your final answer concise but complete
Be practical, thorough in research, but concise in communication.

View File

@@ -0,0 +1,313 @@
# Agent Orchestrator
A lightweight orchestration layer for managing multiple Claude Code agent sessions through a simple command-line interface.
## Overview
The Agent Orchestrator provides a simplified abstraction for delegating work to Claude Code. Instead of manually managing session IDs, output files, and JSON parsing, you work with **named sessions** that can be created, resumed, and monitored through intuitive commands. Sessions can optionally use **agent definitions** to provide specialized behavior and capabilities.
## Core Concepts
### Sessions
A **session** is a named, persistent conversation with Claude Code. Each session:
- Has a unique name (e.g., `architect`, `reviewer`, `dev-agent`)
- Maintains conversation history across multiple interactions
- Can be paused and resumed at any time
- Operates independently from other sessions
- Optionally uses an **agent** definition for specialized behavior
Think of sessions as individual workstreams or conversations you can delegate tasks to and check back with later.
### Agents (Definitions)
An **agent** is a reusable configuration that defines the behavior, expertise, and capabilities for sessions. Agents are optional - you can create generic sessions without them, or use agents to create specialized sessions with predefined behavior.
#### Agent Structure
Each agent is organized in its own directory within `.agent-orchestrator/agents/`. Each agent directory must match the agent name and contains:
```
.agent-orchestrator/agents/
└── <agent-name>/
├── agent.json # Required: Agent configuration
├── agent.system-prompt.md # Optional: System prompt by convention
└── agent.mcp.json # Optional: MCP configuration by convention
```
**1. agent.json** (Required)
```json
{
"name": "browser-tester",
"description": "Specialist in browser automation and end-to-end testing using Playwright"
}
```
- `name`: Agent identifier (must match folder name)
- `description`: Human-readable description
**2. agent.system-prompt.md** (Optional)
Markdown file containing the agent's role definition, expertise areas, and behavioral guidelines. When present, this prompt is automatically prepended to user prompts. Discovered by convention - no need to reference in agent.json.
**3. agent.mcp.json** (Optional)
Standard MCP server configuration enabling the agent to access external tools and capabilities. Passed to Claude CLI via `--mcp-config` flag. Discovered by convention - no need to reference in agent.json.
#### Agent Workflow
When creating a session with an agent:
1. Agent JSON config is loaded and validated
2. System prompt (if specified) is prepended to user's prompt
3. MCP config (if specified) is passed to Claude CLI
4. Agent association is stored with session metadata
5. When resuming, the session automatically uses its associated agent
### Session Management
The tool abstracts away Claude Code's internal session ID management. You interact with sessions using memorable names rather than UUIDs, while the tool handles:
- Session file storage and organization (`.jsonl` + `.meta.json` files)
- Session ID extraction and tracking
- Agent association and configuration
- Result retrieval and formatting
- State management
#### Session States
Sessions can be in one of three states (returned by `ao-status`):
- **`not_existent`** - Session doesn't exist yet (never created or was cleaned up)
- **`running`** - Session created but hasn't returned a result yet (actively processing or ready for resume)
- **`finished`** - Session completed with result available (use `ao-get-result` to retrieve)
#### Session Storage
Each session is stored as:
- `{session-name}.jsonl` - Complete conversation history in JSONL format
- `{session-name}.meta.json` - Session metadata (agent association, project directory, timestamps, session ID)
Location: `{sessions-dir}/` (default: `.agent-orchestrator/agent-sessions/`)
#### Working Directory Context
- Sessions operate in a `project-dir` (default: current working directory when command is invoked)
- All file operations within the session are relative to this directory
- The project directory is stored in session metadata and preserved across resumes
## Use Cases
### Multi-Session Workflows
Coordinate multiple specialized sessions working on different aspects of a project:
```bash
# First, discover available agent definitions
uv run commands/ao-list-agents
# Architecture session using system-architect agent
uv run commands/ao-new architect --agent system-architect -p "Design microservices architecture for e-commerce"
# Development session implements based on architecture
cat architecture.md | uv run commands/ao-new developer --agent senior-developer -p "Implement based on this design:"
# Reviewer session provides feedback
uv run commands/ao-new reviewer --agent security-reviewer -p "Review the implementation for best practices"
```
### Long-Running Background Tasks
Delegate time-consuming tasks to background sessions while you continue working:
- Large codebase analysis
- Comprehensive documentation generation
- Multi-step refactoring operations
- Complex test suite creation
### Iterative Refinement
Resume sessions to continue and refine their previous work:
```bash
# Initial work
uv run commands/ao-new technical-writer --agent documentation-expert -p "Create API documentation"
# Later refinement
uv run commands/ao-resume technical-writer -p "Add authentication examples"
# Further enhancement
uv run commands/ao-resume technical-writer -p "Include error handling section"
```
### Stateful Conversations
Maintain context across multiple prompts without re-explaining background:
- Each session retains full conversation history
- No need to repeat requirements or context
- Build on previous responses naturally
## Features
### Current Capabilities
**Session Management**
- Create new sessions with descriptive names
- Resume existing sessions by name
- List all active sessions with status
- List all available agent definitions
- Clean up all sessions in one command
- Optional agent associations for specialized behavior
**Flexible Prompting**
- Direct prompt input via `-p` flag
- File-based prompts via stdin piping
- Combined prompts (prefix + file content)
- Large prompt support without character limits
**Execution Modes**
- Synchronous execution (wait for completion)
- Background execution with polling support
- Automatic result extraction
- Clean stdout/stderr separation
**State Tracking**
- Session status visibility (active, initializing, completed)
- Session ID management (hidden from user)
- Agent association tracking
- Conversation history persistence
- Cross-session identification
### Companion Skill
The `agent-orchestrator` skill provides integration guidance for Claude Code agents to use this tool within their own workflows. The skill documents:
- Synchronous and asynchronous usage patterns
- Background execution with polling logic
- Result extraction and error handling
- Best practices for agent orchestration
## Future Directions
### Agent Definitions (Current Implementation)
The tool now supports **agent definitions** - reusable configurations that define behavior, capabilities, and constraints for sessions:
**System Prompt Templates**
- Predefined role-based system prompts (architect, developer, reviewer, etc.)
- Consistent behavior across multiple sessions using the same agent
- Custom agent definitions for specialized workflows
- Markdown format for natural prompt editing
**Configuration Profiles**
- MCP (Model Context Protocol) server configurations per agent
- Tool access through MCP integration
- Hybrid JSON + Markdown format for easy editing
**Agent-Based Sessions**
```bash
# Create session with agent
uv run commands/ao-new architect --agent system-architect -p "Design e-commerce system"
# Create generic session (no agent)
uv run commands/ao-new quick-task -p "Simple task"
# Resume remembers agent association
uv run commands/ao-resume architect -p "Add security layer"
```
**Separation of Concerns**
- **Agent**: Blueprint/configuration (reusable definition)
- **Session**: Running conversation (specific instance)
- Agents are reusable; sessions are unique conversations
### Additional Planned Features
**Advanced Orchestration**
- Session-to-session communication patterns
- Dependency chains between sessions
- Parallel session execution coordination
- Result aggregation and synthesis
**Enhanced State Management**
- Session snapshots and rollback
- Conversation branching
- Selective history pruning
- Export/import of sessions
**Observability**
- Detailed execution logs per session
- Token usage tracking
- Performance metrics
- Conversation visualization
**Workflow Automation**
- Declarative multi-session workflows
- Event-driven session triggering
- Conditional execution paths
- Workflow templates
## Architecture
### Components
**`ao-*` Commands**
Collection of Python-based CLI commands providing the command-line interface and orchestration logic. Handles session management, Claude Code SDK invocation, and result extraction. Commands include:
- `ao-new` - Create new sessions
- `ao-resume` - Resume existing sessions
- `ao-status` - Check session state
- `ao-get-result` - Extract results
- `ao-list-sessions` - List all sessions
- `ao-list-agents` - List available agents
- `ao-show-config` - Display session configuration
- `ao-clean` - Remove all sessions
### Directory Structure
The Agent Orchestrator uses a project-relative directory structure located at `.agent-orchestrator/` in the current working directory where the script is invoked.
**`.agent-orchestrator/agent-sessions/`**
Storage directory for session files (JSONL format). Each file contains the complete conversation history and session metadata for one session. Companion `.meta.json` files track agent associations and timestamps.
**`.agent-orchestrator/agents/`**
Storage directory for agent definitions specific to the current project. Each agent is organized in its own subdirectory named after the agent, containing:
- `agent.json` - Required configuration file with agent metadata
- `agent.system-prompt.md` - Optional system prompt (discovered by convention)
- `agent.mcp.json` - Optional MCP configuration for tool access (discovered by convention)
All sessions and agent definitions are stored relative to the project directory (`$PWD`) where the script is invoked, ensuring each project maintains its own isolated agent environment.
### Design Philosophy
**Simplicity First**
Minimize cognitive overhead for users. Named sessions instead of UUIDs, intuitive commands, sensible defaults.
**Progressive Enhancement**
Start simple, add complexity only when needed. Basic usage is straightforward; advanced features are opt-in.
**Composability**
Tool plays well with Unix pipes, scripts, and other CLI tools. Clean input/output separation enables chaining and automation.
**Transparency**
Clear feedback, meaningful error messages, visible state. Users always know what's happening.
## Integration
The Agent Orchestrator is designed to work within the Claude Code ecosystem:
**Slash Commands**
Create custom slash commands that delegate to sessions via the runner.
**Skills**
Skills can orchestrate multiple sessions for complex, multi-step operations.
**MCP Servers**
Agents support MCP server configurations for enhanced capabilities.
The MCP configuration is passed to the Claude CLI when starting or resuming sessions.
**Workflows** _(Future)_
Declarative workflow definitions will coordinate multiple sessions.
## Status
**Current Version**: Initial Release
**Status**: Production Ready
The core functionality is stable and tested. Agent type system and advanced features are in design phase.
## Related Documentation
- **Command Help**: Run `uv run commands/ao-<command> --help` for command-specific syntax and options (e.g., `uv run commands/ao-new --help`)
- **Skill Documentation**: See the main `SKILL.md` file for comprehensive usage guide and examples
- **Example Agents**: See `EXAMPLE-AGENTS.md` for detailed agent definition examples
- **Claude Code SDK**: The commands use the Claude Code SDK for agent orchestration

View File

@@ -0,0 +1,212 @@
# Environment Variables Reference
## Overview
The Agent Orchestrator Skill uses environment variables to configure directory paths, logging, and observability integration. These variables control where agent definitions, sessions, and logs are stored, and how sessions interact with monitoring systems.
**Configuration Precedence:** CLI Flags > Environment Variables > Defaults
## Quick Reference
| Variable | Default | Type | Description |
|----------|---------|------|-------------|
| `AGENT_ORCHESTRATOR_PROJECT_DIR` | `$PWD` | Path | Project working directory |
| `AGENT_ORCHESTRATOR_SESSIONS_DIR` | `{project_dir}/.agent-orchestrator/agent-sessions` | Path | Session storage directory |
| `AGENT_ORCHESTRATOR_AGENTS_DIR` | `{project_dir}/.agent-orchestrator/agents` | Path | Agent definitions directory |
| `AGENT_ORCHESTRATOR_ENABLE_LOGGING` | `false` | Boolean | Enable session logging |
| `AGENT_ORCHESTRATOR_OBSERVABILITY_ENABLED` | `false` | Boolean | Enable observability events |
| `AGENT_ORCHESTRATOR_OBSERVABILITY_URL` | `http://127.0.0.1:8765` | URL | Observability backend endpoint |
## Detailed Descriptions
### Directory Configuration
#### `AGENT_ORCHESTRATOR_PROJECT_DIR`
**Default:** Current working directory (`$PWD`)
**Type:** Absolute or relative path
**Purpose:** Sets the working directory where agent sessions execute. All commands run by Claude during the session inherit this as their current working directory.
**Validation:** Must exist, must be a directory, must be readable.
**Example:**
```bash
export AGENT_ORCHESTRATOR_PROJECT_DIR="/Users/username/my-project"
```
---
#### `AGENT_ORCHESTRATOR_SESSIONS_DIR`
**Default:** `{project_dir}/.agent-orchestrator/agent-sessions`
**Type:** Absolute or relative path
**Purpose:** Directory for storing session files (.jsonl) and metadata (.meta.json). Sessions can be resumed by reading these files. Centralize sessions across projects by setting this to a fixed path.
**Validation:** Parent directory must be writable (auto-creates if missing).
**Example:**
```bash
# Store all sessions in a central location
export AGENT_ORCHESTRATOR_SESSIONS_DIR="/Users/username/.agent-sessions"
```
---
#### `AGENT_ORCHESTRATOR_AGENTS_DIR`
**Default:** `{project_dir}/.agent-orchestrator/agents`
**Type:** Absolute or relative path
**Purpose:** Directory containing agent definition files (agent.md, agent.mcp.json). Use this to share agent configurations across multiple projects.
**Validation:** Parent directory must be writable (auto-creates if missing).
**Example:**
```bash
# Share agent definitions across projects
export AGENT_ORCHESTRATOR_AGENTS_DIR="/Users/username/.shared-agents"
```
---
### Logging Configuration
#### `AGENT_ORCHESTRATOR_ENABLE_LOGGING`
**Default:** `false` (disabled)
**Type:** Boolean (`"1"`, `"true"`, `"yes"` = enabled, case-insensitive)
**Purpose:** Enable detailed logging of session commands, prompts, and results to `.log` files in the sessions directory.
**Log Location:** `{sessions_dir}/{session_name}.log`
**Log Contents:** Command invocations, full prompts, environment variables, timestamps, results.
**Example:**
```bash
# Enable logging
export AGENT_ORCHESTRATOR_ENABLE_LOGGING="true"
```
---
### Observability Configuration
#### `AGENT_ORCHESTRATOR_OBSERVABILITY_ENABLED`
**Default:** `false` (disabled)
**Type:** Boolean (`"1"`, `"true"`, `"yes"` = enabled, case-insensitive)
**Purpose:** Enable real-time event streaming to an observability backend. Captures session lifecycle events, tool calls, and assistant messages for monitoring and analysis.
**Events Tracked:**
- `session_start` - Session initialization
- `message` - User prompts and assistant responses
- `pre_tool` - Before tool execution
- `post_tool` - After tool execution (includes errors)
- `session_stop` - Session completion
**Example:**
```bash
# Enable observability
export AGENT_ORCHESTRATOR_OBSERVABILITY_ENABLED="true"
```
---
#### `AGENT_ORCHESTRATOR_OBSERVABILITY_URL`
**Default:** `http://127.0.0.1:8765`
**Type:** URL (HTTP endpoint)
**Purpose:** Base URL of the observability backend service. Events are sent to `{url}/events` via HTTP POST.
**Requirements:**
- Must be accessible from where skill commands run
- Must accept JSON POST requests to `/events` endpoint
- Failures are silent (won't block session execution)
**Example:**
```bash
# Use custom observability backend
export AGENT_ORCHESTRATOR_OBSERVABILITY_URL="http://localhost:9000"
```
---
## CLI Flag Overrides
The following CLI flags override environment variables when specified:
| CLI Flag | Overrides | Available In |
|----------|-----------|--------------|
| `--project-dir` | `AGENT_ORCHESTRATOR_PROJECT_DIR` | `ao-new`, `ao-resume`, `ao-show-config`, `ao-status`, `ao-clean` |
| `--sessions-dir` | `AGENT_ORCHESTRATOR_SESSIONS_DIR` | `ao-new`, `ao-resume`, `ao-show-config`, `ao-list-sessions`, `ao-status`, `ao-get-result`, `ao-clean` |
| `--agents-dir` | `AGENT_ORCHESTRATOR_AGENTS_DIR` | `ao-new`, `ao-resume`, `ao-list-agents` |
**Note:** Observability settings (`OBSERVABILITY_ENABLED`, `OBSERVABILITY_URL`) and logging (`ENABLE_LOGGING`) can only be configured via environment variables, not CLI flags.
### Example Usage
```bash
# Override project directory for a single command
ao-new mysession --project-dir /path/to/project -p "Build feature"
# Override sessions directory to use centralized storage
ao-list-sessions --sessions-dir /Users/username/.agent-sessions
# Override agents directory to use shared agent definitions
ao-new research --agent web-researcher --agents-dir /shared/agents
```
---
## Configuration Resolution Order
1. **CLI Flags** (highest priority) - `--project-dir`, `--sessions-dir`, `--agents-dir`
2. **Environment Variables** (medium priority) - `AGENT_ORCHESTRATOR_*`
3. **Defaults** (lowest priority) - `$PWD` or `{project}/.agent-orchestrator/*`
**Example Resolution:**
```bash
# Environment variables set
export AGENT_ORCHESTRATOR_PROJECT_DIR="/home/user/project-a"
export AGENT_ORCHESTRATOR_SESSIONS_DIR="/home/user/.sessions"
# Command with CLI override
ao-new test --project-dir /home/user/project-b -p "Hello"
# Resolution:
# project_dir = /home/user/project-b (CLI flag wins)
# sessions_dir = /home/user/.sessions (from env var)
# agents_dir = /home/user/project-b/.agent-orchestrator/agents (default)
```
---
## Common Patterns
### Pattern 1: Centralized Sessions and Agents
Useful for maintaining all agent work in a dedicated location, regardless of which project you're working in.
```bash
# In ~/.bashrc or ~/.zshrc
export AGENT_ORCHESTRATOR_SESSIONS_DIR="$HOME/.agent-orchestrator/sessions"
export AGENT_ORCHESTRATOR_AGENTS_DIR="$HOME/.agent-orchestrator/agents"
export AGENT_ORCHESTRATOR_ENABLE_LOGGING="true"
```
### Pattern 2: Project-Specific with Observability
Keep sessions and agents per-project but enable monitoring.
```bash
# In project directory or .env file
export AGENT_ORCHESTRATOR_OBSERVABILITY_ENABLED="true"
export AGENT_ORCHESTRATOR_OBSERVABILITY_URL="http://localhost:8765"
# Sessions go to ./.agent-orchestrator/agent-sessions (default)
# Agents go to ./.agent-orchestrator/agents (default)
```
### Pattern 3: Claude Code Local Settings
Configure via `.claude/settings.local.json` for persistence across sessions.
```json
{
"env": {
"AGENT_ORCHESTRATOR_SESSIONS_DIR": "/Users/username/projects/ai/orchestrator/.agent-orchestrator/agent-sessions",
"AGENT_ORCHESTRATOR_AGENTS_DIR": "/Users/username/projects/ai/orchestrator/.agent-orchestrator/agents",
"AGENT_ORCHESTRATOR_OBSERVABILITY_ENABLED": "true",
"AGENT_ORCHESTRATOR_OBSERVABILITY_URL": "http://127.0.0.1:8765"
}
}
```

View File

@@ -0,0 +1,87 @@
# Example Agent Definitions
This reference provides a complete example agent definition demonstrating the Agent Orchestrator folder-based agent structure.
## Example Source Location
The example agent is located at `../example/agents/browser-tester/` (relative to this file) and includes:
```
browser-tester/
├── agent.json # Agent configuration
├── agent.system-prompt.md # System prompt (optional)
└── agent.mcp.json # MCP configuration (optional)
```
**agent.json** - Agent configuration
- Defines agent name and description
- Name must match the folder name
**agent.system-prompt.md** - System prompt
- Contains role definition, expertise areas, and behavioral guidelines
- Automatically prepended to user prompts when the agent is used
- Discovered by convention (no need to reference in agent.json)
**agent.mcp.json** - MCP configuration
- Configures Playwright MCP server for browser automation capabilities
- Provides tool access to the agent's sessions
- Discovered by convention (no need to reference in agent.json)
- IMPORTANT: Not all agents require MCP configurations; this is specific to agents needing external tool access
## Using the Example
**Source**: Copy the entire folder from `../example/agents/browser-tester/` (relative to this file)
**Destination**: Place it in `.agent-orchestrator/agents/` in your project directory
```bash
# From your project root
cp -r path/to/agent-orchestrator/example/agents/browser-tester .agent-orchestrator/agents/
```
Once copied to your project, the agent can be used with the Agent Orchestrator commands:
```bash
# List available agents
uv run commands/ao-list-agents
# Create session with the browser-tester agent
uv run commands/ao-new my-test --agent browser-tester -p "Test login flow"
```
## Customizing Agents
To create your own agents based on this example:
1. **Copy the example folder** and rename it to match your agent's purpose
2. **Edit agent.json**: Update the `name` field to match the new folder name
3. **Edit agent.system-prompt.md**: Define your agent's role, expertise, and behavior
4. **Edit or remove agent.mcp.json**: Configure tools your agent needs, or delete if not needed
5. **Place in your project**: Copy the folder to `.agent-orchestrator/agents/` in your project
The folder structure keeps each agent self-contained and easy to distribute or version control.
## Available Example Agents
The following example agents are available in the `../example/agents/` directory:
### browser-tester
**Location**: `../example/agents/browser-tester/`
**Description**: Browser automation agent with Playwright MCP integration for testing web applications
**Features**: Includes MCP configuration for browser automation tools
### web-researcher
**Location**: `../example/agents/web-researcher/`
**Description**: Conducts iterative web research using WebSearch and WebFetch tools to answer questions
**Features**: Generates documented JSON sources and markdown research results
### confluence-researcher
**Location**: `../example/agents/confluence-researcher/`
**Description**: Conducts iterative Confluence research using CQL queries to answer questions
**Features**: Includes mcp-atlassian MCP server integration, generates documented JSON sources and markdown research results
**Setup**: See README.md for required environment variables configuration
### jira-researcher
**Location**: `../example/agents/jira-researcher/`
**Description**: Conducts iterative Jira research using JQL queries to answer questions
**Features**: Includes mcp-atlassian MCP server integration, analyzes issues and linked items, generates documented JSON sources and markdown research results
**Setup**: See README.md for required environment variables configuration