Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:49:58 +08:00
commit 7611f46284
10 changed files with 1475 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
{
"name": "cli-agent-runner",
"description": "Use this skill when you need to invoke another Claude Code session via the cli-agent-runner.sh script to perform specialized, potentially long-running tasks in a simplified way. This wrapper handles session management, result extraction, and can be run in background with polling support.",
"version": "1.0.0",
"author": {
"name": "rawe",
"email": "noreply@example.com"
},
"skills": [
"./skills"
]
}

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# cli-agent-runner
Use this skill when you need to invoke another Claude Code session via the cli-agent-runner.sh script to perform specialized, potentially long-running tasks in a simplified way. This wrapper handles session management, result extraction, and can be run in background with polling support.

69
plugin.lock.json Normal file
View File

@@ -0,0 +1,69 @@
{
"$schema": "internal://schemas/plugin.lock.v1.json",
"pluginId": "gh:rawe/claude-dev-skills:cli-agent-runner",
"normalized": {
"repo": null,
"ref": "refs/tags/v20251128.0",
"commit": "120aeaa7273221ac9f4fe7061e98f36358091a59",
"treeHash": "dbe0a06005459691e5b7dbb50b969faa8489159b4284f097d999811dbfb17c32",
"generatedAt": "2025-11-28T10:27:49.421750Z",
"toolVersion": "publish_plugins.py@0.2.0"
},
"origin": {
"remote": "git@github.com:zhongweili/42plugin-data.git",
"branch": "master",
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
},
"manifest": {
"name": "cli-agent-runner",
"description": "Use this skill when you need to invoke another Claude Code session via the cli-agent-runner.sh script to perform specialized, potentially long-running tasks in a simplified way. This wrapper handles session management, result extraction, and can be run in background with polling support.",
"version": "1.0.0"
},
"content": {
"files": [
{
"path": "README.md",
"sha256": "8ce8214cabc24388e5d703e4f0452974269c2cf02b0274d00a689bfdbed55707"
},
{
"path": ".claude-plugin/plugin.json",
"sha256": "1aeb918cd70dbc3e4020cda6dd7075c8444487acee9ec96558a4381fd75fc669"
},
{
"path": "skills/cli-agent-runner/cli-agent-runner.sh",
"sha256": "d800e321785b197c82f7729778364a0347b0ca5445f5ef3bac26316b13331c41"
},
{
"path": "skills/cli-agent-runner/SKILL.md",
"sha256": "c28d5fd08243a775b30cab60c353470c29ce850fb6d85b6d4eff8ef7118a1dd0"
},
{
"path": "skills/cli-agent-runner/references/EXAMPLE-AGENTS.md",
"sha256": "6bf9be3fffe64262395ecf1f9c82193816d736faa1b76847c97cdc3c0a636df6"
},
{
"path": "skills/cli-agent-runner/references/CLI-AGENT-RUNNER.md",
"sha256": "4792ad75cf01f443594a464fab86e083dd76ec8bfebd0906fbd46043a5d7dd01"
},
{
"path": "skills/cli-agent-runner/example/agents/browser-tester/agent.system-prompt.md",
"sha256": "8d0b3775bcbb89dfae710e254106cfdefce6924d41ed4b532d595b6b18606161"
},
{
"path": "skills/cli-agent-runner/example/agents/browser-tester/agent.json",
"sha256": "dff9be637b27366ab797ce01eb14d522fe2dd7d540d906ebda4d0a8137dc8b04"
},
{
"path": "skills/cli-agent-runner/example/agents/browser-tester/agent.mcp.json",
"sha256": "77a711f0ed6c082ede0094fd212fe8a7d440bf72074150021a3b152f2683da04"
}
],
"dirSha256": "dbe0a06005459691e5b7dbb50b969faa8489159b4284f097d999811dbfb17c32"
},
"security": {
"scannedAt": null,
"scannerVersion": null,
"flags": []
}
}

View File

@@ -0,0 +1,423 @@
---
name: cli-agent-runner
description: Use this skill when you need to invoke another Claude Code session via the cli-agent-runner.sh script to perform specialized, potentially long-running tasks in a simplified way. This wrapper handles session management, result extraction, and can be run in background with polling support.
---
# CLI Agent Runner Skill
## Intro
This skill provides guidance on using the `cli-agent-runner.sh` script to delegate work to Claude Code sessions.
Use this when you need to:
- Delegate a task to a specialized session for long-running operations
- Resume tasks later using a simple session name (no session ID management needed)
- Run sessions in the background with polling support
- Get clean result output without manual JSON parsing
- Optionally use agent definitions for specialized behavior
**Key Benefits:**
- Session names instead of session IDs (simpler to track and resume)
- Automatic session file management in `.cli-agent-runner/agent-sessions/` directory
- Built-in result extraction (no need for head/tail/jq commands)
- Clean output to stdout, errors to stderr
- Optional agent associations for specialized capabilities
## Terminology
- **Session**: A named, running conversation with Claude Code
- **Agent**: A reusable configuration/definition that provides specialized behavior for sessions
- **Session Name**: The unique identifier you give to a conversation (e.g., `architect`, `reviewer`)
- **Agent Name**: The identifier for a reusable agent definition (e.g., `system-architect`, `security-reviewer`)
## Variables
The following variables are used in the commands and instructions:
- `<session-name>`: A unique identifier for the session (alphanumeric, dash, underscore only; max 30 chars)
- `<agent-name>`: Optional agent definition to use for the session
- `<initial-prompt>`: The prompt or task description for a new session
- `<resume-prompt>`: The prompt or task description to continue an existing session's work
- `<POLL_INTERVAL>`: The interval in seconds to wait between polling attempts. Default is 60 seconds.
## Script Location
**IMPORTANT:** The `cli-agent-runner.sh` script is located in the same directory as this SKILL.md file.
So it is in the root folder of the skill plugin.
Before using the script for the first time in a conversation, you MUST locate it:
1. Identify the root folder of the plugin skill and append the script name:
```
<path-to-skill-root-folder>/cli-agent-runner.sh
```
2. Store this path mentally for the rest of the conversation: <absolute-path-to-cli-agent-runner.sh>
3. Use the absolute path in all subsequent commands
**Example:**
```bash
# Use that exact path in all commands:
<absolute-path-to-cli-agent-runner.sh> new <session-name> -p "<prompt>"
```
**Note:** In all examples below, `cli-agent-runner.sh` represents the absolute path <absolute-path-to-cli-agent-runner.sh> you discovered. Replace it with the actual path when executing commands.
## Commands Overview
The cli-agent-runner.sh supports five commands:
1. **new** - Create a new session (optionally with an agent)
2. **resume** - Resume an existing session by name
3. **list** - List all sessions with their session IDs
4. **list-agents** - List all available agent definitions
5. **clean** - Remove all sessions
## Usage Patterns
### Pattern 1: Synchronous Execution (Wait for Completion)
Use this when you want to wait for the session to complete and get the result immediately.
**Creating a new session:**
```bash
./cli-agent-runner.sh new <session-name> -p "<initial-prompt>"
```
**Creating a new session with an agent:**
```bash
./cli-agent-runner.sh new <session-name> --agent <agent-name> -p "<initial-prompt>"
```
**Creating a new session with prompt from file/stdin:**
This should be considered when the prompt is large or complex or already a prompt file exists potentially created by another session.
```bash
cat prompt.md | ./cli-agent-runner.sh new <session-name>
```
**Resuming an existing session:**
```bash
./cli-agent-runner.sh resume <session-name> -p "<resume-prompt>"
```
**Example:**
```bash
# Create new session with agent
./cli-agent-runner.sh new architect --agent system-architect -p "Create a high-level architecture document for a user authentication system"
# The script blocks until completion and outputs the result
# Output: <result from session>
# Resume the session later (agent association is remembered)
./cli-agent-runner.sh resume architect -p "Add API endpoint specifications to the architecture"
```
### Pattern 2: Background Execution with Polling
Use this when you want to start the session in the background and poll for completion.
**Instructions:**
**1. Start the session in the background:**
- Use Bash tool with `run_in_background: true`
- Use either `new` or `resume` command
- **Important:** Note the bash_id returned by the Bash tool
**Example for new session:**
```bash
./cli-agent-runner.sh new <session-name> -p "<initial-prompt>"
```
**Example for new session with agent:**
```bash
./cli-agent-runner.sh new <session-name> --agent <agent-name> -p "<initial-prompt>"
```
**Example for resuming session:**
```bash
./cli-agent-runner.sh resume <session-name> -p "<resume-prompt>"
```
**2. Initial Polling Wait:**
- Use Bash tool (NOT background): `sleep <POLL_INTERVAL>`
- Default POLL_INTERVAL is 60 seconds
**3. Check if background process is still running:**
- Use BashOutput tool with the bash_id from step 1
- The tool returns shell status showing if process is running or completed
- If status shows still running: continue to step 4
- If status shows completed: continue to step 5
- **Do NOT use:** kill -0, pgrep, ps, or any other process checking commands
**4. Polling Wait Loop:**
- Use Bash tool (NOT background): `sleep <POLL_INTERVAL>`
- Return to step 3
**5. Process Completed - Get Results:**
- The result is already captured in the Bash tool's output when the process completes
- Simply read the output from the completed Bash execution
- The output will be the session's result (already extracted by the script)
**Full Background Example:**
```bash
# Step 1: Start in background
./cli-agent-runner.sh new architect --agent system-architect -p "Design authentication system"
# Returns bash_id: abc123
# Step 2: Initial wait
sleep 60
# Step 3: Check status
# Use BashOutput with bash_id: abc123
# If status: running, continue to step 4
# If status: completed, read the output - it contains the result
# Step 4: If still running, wait and check again
sleep 60
# Return to step 3
```
### Pattern 3: Listing Sessions
Use this to see all existing sessions and their status.
```bash
./cli-agent-runner.sh list
```
**Output format:**
```
session-name (session: session-id)
architect (session: 3db5dca9-6829-4cb7-a645-c64dbd98244d)
reviewer (session: initializing)
```
- "initializing" means the session file exists but hasn't started yet (empty file)
- "unknown" means the session ID couldn't be extracted
- Otherwise, shows the actual session ID
### Pattern 4: Listing Available Agent Definitions
Use this to discover what agent definitions are available before creating a session.
```bash
./cli-agent-runner.sh list-agents
```
**Output format:**
```
agent-name:
description
---
next-agent-name:
description
---
another-agent-name:
description
```
**Example output:**
```
code-reviewer:
Reviews code for best practices, bugs, and potential improvements
---
documentation-writer:
Creates comprehensive technical documentation and guides
---
system-architect:
Expert in designing scalable system architectures
```
**Use Case:**
- Discover available agents before creating a new session
- Understand what specialized capabilities are available
- Choose the appropriate agent for your task
**Important Notes:**
- Each agent definition is separated by `---` for clear parsing
- Agent names can be used with `--agent` flag when creating sessions
- If no agents exist, outputs: "No agent definitions found"
### Pattern 5: Cleaning All Sessions
Use this to remove all sessions and start fresh.
```bash
./cli-agent-runner.sh clean
```
**Behavior:**
- Removes the entire `.cli-agent-runner/agent-sessions/` directory
- All session files and history are permanently deleted
- No confirmation prompt - immediate deletion
- Safe to run even if no sessions exist
**Output:**
```
All sessions removed
```
or
```
No sessions to remove
```
## Prompt Input Methods
The script supports flexible prompt input:
1. **Via `-p` flag only:** `./cli-agent-runner.sh new architect -p "Your prompt here"`
2. **Via stdin only:** `echo "Your prompt" | ./cli-agent-runner.sh new architect`
3. **Both combined:** `cat file.md | ./cli-agent-runner.sh new architect -p "Context:"`
**Concatenation:** If both `-p` and stdin are provided, they are concatenated with `-p` content first, then a newline, then stdin content. This is useful for adding context before piping in a file.
**IMPORTANT** STDIN should be used if it is neccessarry to provide a a large complex promt to the agent or the result of another command output. e.g. `tree` for listing a directory structure.
**Example:**
```bash
cat requirements.md | ./cli-agent-runner.sh new architect -p "Create an architecture document based on these requirements:"
```
Results in prompt:
```
Create an architecture document based on these requirements:
<contents of requirements.md>
```
## Error Handling
All errors are output to stderr and the script exits with code 1:
- **Session name validation errors:**
- Empty name
- Name too long (>30 characters)
- Invalid characters (only alphanumeric, dash, underscore allowed)
- **Session lifecycle errors:**
- Creating session that already exists → Use `resume` instead
- Resuming session that doesn't exist → Use `new` instead
- **Agent errors:**
- Agent definition not found
- Invalid agent configuration
- **Prompt errors:**
- No prompt provided (neither `-p` nor stdin)
- **Execution errors:**
- Claude command failed
- Could not extract session_id or result
## Session Files
- **Location:** `.cli-agent-runner/agent-sessions/<session-name>.jsonl`
- **Metadata:** `.cli-agent-runner/agent-sessions/<session-name>.meta.json` (tracks agent association)
- **Format:** Line-delimited JSON (JSONL)
- **Management:** Fully automatic - you don't need to manage these files
## Agent Definitions
- **Location:** `.cli-agent-runner/agents/<agent-name>.json` (configuration)
- **Prompts:** `.cli-agent-runner/agents/<agent-name>.prompt.md` (system prompt)
- **Format:** Hybrid JSON + Markdown
- **Usage:** Optional - sessions can run without agents
## Best Practices
1. **Session naming:** Use descriptive names like `architect`, `reviewer`, `dev-agent`, `po-agent`
2. **Agent discovery:** Use `list-agents` to discover available agents before creating sessions
3. **Agent selection:** Use agents for specialized behavior, skip for generic tasks
4. **Background execution:** Use for long-running tasks (>1 minute expected)
5. **Synchronous execution:** Use for quick tasks (<1 minute expected)
6. **Polling interval:** Start with 60 seconds, adjust based on expected task duration
7. **Resume strategy:** Use meaningful resume prompts that build on previous work
## Example Workflow
```bash
# 1. Discover available agents
./cli-agent-runner.sh list-agents
# Output shows:
# system-architect:
# Expert in designing scalable system architectures
# ---
# code-reviewer:
# Reviews code for best practices, bugs, and potential improvements
# ---
# documentation-writer:
# Creates comprehensive technical documentation and guides
# 2. Create new architect session with agent in background
# Use Bash tool with run_in_background: true
./cli-agent-runner.sh new architect --agent system-architect -p "Create architecture for microservices-based e-commerce system"
# Note bash_id: xyz789
# 3. Wait 60 seconds
sleep 60
# 4. Check if completed using BashOutput with bash_id xyz789
# Status: running
# 5. Wait another 60 seconds
sleep 60
# 6. Check again with BashOutput
# Status: completed
# Output contains the architecture document result
# 7. Later, resume the session for additional work (agent association remembered)
./cli-agent-runner.sh resume architect -p "Add security considerations to the architecture"
# 8. List all sessions to see status
./cli-agent-runner.sh list
# Output: architect (session: 3db5dca9-6829-4cb7-a645-c64dbd98244d)
```
## Important: Working Directory Requirements
**The `cli-agent-runner.sh` script must be run from your project root** where the `.cli-agent-runner/` directory exists or will be created.
### Common Pitfall
If you change directories during your workflow, the script will look for `.cli-agent-runner/` relative to your current location and may fail silently.
**Example - What NOT to do:**
```bash
cd .cli-agent-runner/agent-sessions # Changed directory
cli-agent-runner.sh clean # ❌ Returns "No sessions to remove"
# Script looks for: .cli-agent-runner/agent-sessions/.cli-agent-runner/agent-sessions/
Example - Correct approach:
cd /path/to/your/project # ✅ Back to project root
cli-agent-runner.sh clean # ✅ Works correctly
# Script looks for: /path/to/your/project/.cli-agent-runner/agent-sessions/
Best Practice
Always use absolute paths when running the script from non-root directories:
# Safe - works from any directory
cd /path/to/your/project && /path/to/cli-agent-runner.sh clean
# Or explicitly change to project root first
cd "$(git rev-parse --show-toplevel)" && cli-agent-runner.sh clean
Shell Persistence Note
In background shells or long-running terminal sessions, cd commands persist across multiple commands. Always verify your working directory with pwd before running cli-agent-runner.sh
commands.
## Additional Documentation
**Creating Custom Agents**: See `references/EXAMPLE-AGENTS.md` for a complete agent definition example showing how to create agents with JSON configuration, system prompts, and MCP server integration.
**Architecture & Design Details**: See `references/CLI-AGENT-RUNNER.md` for comprehensive documentation on the CLI Agent Runner's architecture, design philosophy, directory structure, and advanced usage patterns.

View File

@@ -0,0 +1,589 @@
#!/bin/bash
set -euo pipefail
# Constants
PROJECT_DIR="$PWD"
AGENT_SESSIONS_DIR="$PROJECT_DIR/.cli-agent-runner/agent-sessions"
AGENTS_DIR="$PROJECT_DIR/.cli-agent-runner/agents"
MAX_NAME_LENGTH=30
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Show help message
show_help() {
cat << EOF
Usage:
cli-agent-runner.sh new <session-name> [--agent <agent-name>] [-p <prompt>]
cli-agent-runner.sh resume <session-name> [-p <prompt>]
cli-agent-runner.sh list
cli-agent-runner.sh list-agents
cli-agent-runner.sh clean
Commands:
new Create a new session (optionally with an agent)
resume Resume an existing session
list List all sessions with metadata
list-agents List all available agent definitions
clean Remove all sessions
Arguments:
<session-name> Name of the session (alphanumeric, dash, underscore only; max 30 chars)
<agent-name> Name of the agent definition to use (optional for new command)
Options:
-p <prompt> Session prompt (can be combined with stdin; -p content comes first)
--agent <name> Use a specific agent definition (only for new command)
Examples:
# Create new session (generic, no agent)
./cli-agent-runner.sh new architect -p "Design user auth system"
# Create new session with agent
./cli-agent-runner.sh new architect --agent system-architect -p "Design user auth system"
# Create new session from file
cat prompt.md | ./cli-agent-runner.sh new architect --agent system-architect
# Resume session (agent association remembered)
./cli-agent-runner.sh resume architect -p "Continue with API design"
# Resume from file
cat continue.md | ./cli-agent-runner.sh resume architect
# Combine -p and stdin (concatenated)
cat requirements.md | ./cli-agent-runner.sh new architect -p "Create architecture based on:"
# List all sessions
./cli-agent-runner.sh list
# List all agent definitions
./cli-agent-runner.sh list-agents
# Remove all sessions
./cli-agent-runner.sh clean
EOF
}
# Error message helper
error() {
echo -e "${RED}Error: $1${NC}" >&2
exit 1
}
# Ensure required directories exist
ensure_directories() {
mkdir -p "$AGENT_SESSIONS_DIR"
mkdir -p "$AGENTS_DIR"
}
# Validate session name
validate_session_name() {
local name="$1"
# Check if empty
if [ -z "$name" ]; then
error "Session name cannot be empty"
fi
# Check length
if [ ${#name} -gt $MAX_NAME_LENGTH ]; then
error "Session name too long (max $MAX_NAME_LENGTH characters): $name"
fi
# Check for valid characters (alphanumeric, dash, underscore only)
if [[ ! "$name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
error "Session name contains invalid characters. Only alphanumeric, dash (-), and underscore (_) are allowed: $name"
fi
}
# Get prompt from -p flag and/or stdin
get_prompt() {
local prompt_arg="$1"
local final_prompt=""
# Add -p content first if provided
if [ -n "$prompt_arg" ]; then
final_prompt="$prompt_arg"
fi
# Check if stdin has data
if [ ! -t 0 ]; then
# Read from stdin
local stdin_content
stdin_content=$(cat)
if [ -n "$stdin_content" ]; then
# If we already have prompt from -p, add newline separator
if [ -n "$final_prompt" ]; then
final_prompt="${final_prompt}"$'\n'"${stdin_content}"
else
final_prompt="$stdin_content"
fi
fi
fi
# Check if we got any prompt at all
if [ -z "$final_prompt" ]; then
error "No prompt provided. Use -p flag or pipe prompt via stdin"
fi
echo "$final_prompt"
}
# Extract result from last line of agent session file
extract_result() {
local session_file="$1"
if [ ! -f "$session_file" ]; then
error "Session file not found: $session_file"
fi
local result
result=$(tail -n 1 "$session_file" | jq -r '.result // empty' 2>/dev/null)
if [ -z "$result" ]; then
error "Could not extract result from session file"
fi
echo "$result"
}
# Extract session_id from first line of agent session file
extract_session_id() {
local session_file="$1"
if [ ! -f "$session_file" ]; then
error "Session file not found: $session_file"
fi
local session_id
session_id=$(head -n 1 "$session_file" | jq -r '.session_id // empty' 2>/dev/null)
if [ -z "$session_id" ]; then
error "Could not extract session_id from session file"
fi
echo "$session_id"
}
# Load agent configuration from agent directory
# Args: $1 - Agent name (must match folder name)
# Sets global vars: AGENT_NAME, AGENT_DESCRIPTION, SYSTEM_PROMPT_FILE (full path), MCP_CONFIG (full path)
load_agent_config() {
local agent_name="$1"
local agent_dir="$AGENTS_DIR/${agent_name}"
local agent_file="$agent_dir/agent.json"
if [ ! -d "$agent_dir" ]; then
error "Agent not found: $agent_name (expected directory: $agent_dir)"
fi
if [ ! -f "$agent_file" ]; then
error "Agent configuration not found: $agent_file"
fi
# Validate JSON
if ! jq empty "$agent_file" 2>/dev/null; then
error "Invalid JSON in agent configuration: $agent_file"
fi
# Extract fields
AGENT_NAME=$(jq -r '.name' "$agent_file")
AGENT_DESCRIPTION=$(jq -r '.description' "$agent_file")
# Validate name matches folder name
if [ "$AGENT_NAME" != "$agent_name" ]; then
error "Agent name mismatch: folder=$agent_name, config name=$AGENT_NAME"
fi
# Check for optional files by convention
SYSTEM_PROMPT_FILE=""
if [ -f "$agent_dir/agent.system-prompt.md" ]; then
SYSTEM_PROMPT_FILE="$agent_dir/agent.system-prompt.md"
fi
MCP_CONFIG=""
if [ -f "$agent_dir/agent.mcp.json" ]; then
MCP_CONFIG="$agent_dir/agent.mcp.json"
fi
}
# Load system prompt from file and return its content
# Args: $1 - Full path to prompt file (already resolved by load_agent_config)
# Returns: File content via stdout, or empty string if path is empty
load_system_prompt() {
local prompt_file="$1"
if [ -z "$prompt_file" ]; then
echo ""
return
fi
if [ ! -f "$prompt_file" ]; then
error "System prompt file not found: $prompt_file"
fi
cat "$prompt_file"
}
# Save session metadata
save_session_metadata() {
local session_name="$1"
local agent_name="$2" # Can be empty for generic sessions
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
local meta_file="$AGENT_SESSIONS_DIR/${session_name}.meta.json"
cat > "$meta_file" <<EOF
{
"session_name": "$session_name",
"agent": $([ -n "$agent_name" ] && echo "\"$agent_name\"" || echo "null"),
"created_at": "$timestamp",
"last_resumed_at": "$timestamp"
}
EOF
}
# Load session metadata
load_session_metadata() {
local session_name="$1"
local meta_file="$AGENT_SESSIONS_DIR/${session_name}.meta.json"
if [ ! -f "$meta_file" ]; then
# No metadata - treat as generic session (backward compatibility)
SESSION_AGENT=""
return
fi
SESSION_AGENT=$(jq -r '.agent // empty' "$meta_file")
}
# Update session metadata timestamp
update_session_metadata() {
local session_name="$1"
local agent_name="$2" # Optional: agent name if known
local meta_file="$AGENT_SESSIONS_DIR/${session_name}.meta.json"
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
if [ -f "$meta_file" ]; then
# Update last_resumed_at
jq ".last_resumed_at = \"$timestamp\"" "$meta_file" > "${meta_file}.tmp"
mv "${meta_file}.tmp" "$meta_file"
else
# Create meta.json if it doesn't exist (backward compatibility)
save_session_metadata "$session_name" "$agent_name"
fi
}
# Build MCP config argument for Claude CLI
# Args: $1 - Full path to MCP config file (already resolved by load_agent_config)
# Returns: Claude CLI argument string "--mcp-config <path>", or empty string if path is empty
build_mcp_arg() {
local mcp_config="$1"
if [ -z "$mcp_config" ]; then
echo ""
return
fi
if [ ! -f "$mcp_config" ]; then
error "MCP config file not found: $mcp_config"
fi
echo "--mcp-config $mcp_config"
}
# Command: new
cmd_new() {
local session_name="$1"
local prompt_arg="$2"
local agent_name="$3" # Optional
validate_session_name "$session_name"
local session_file="$AGENT_SESSIONS_DIR/${session_name}.jsonl"
# Check if session already exists
if [ -f "$session_file" ]; then
error "Session '$session_name' already exists. Use 'resume' command to continue or choose a different name"
fi
# Get user prompt
local user_prompt
user_prompt=$(get_prompt "$prompt_arg")
# Load agent configuration if specified
local final_prompt="$user_prompt"
local mcp_arg=""
if [ -n "$agent_name" ]; then
load_agent_config "$agent_name"
# Load and prepend system prompt
if [ -n "$SYSTEM_PROMPT_FILE" ]; then
local system_prompt
system_prompt=$(load_system_prompt "$SYSTEM_PROMPT_FILE")
final_prompt="${system_prompt}"$'\n\n---\n\n'"${user_prompt}"
fi
# Build MCP argument
mcp_arg=$(build_mcp_arg "$MCP_CONFIG")
fi
# Ensure required directories exist
ensure_directories
# Save session metadata immediately
save_session_metadata "$session_name" "$agent_name"
# Run claude command
if ! claude -p "$final_prompt" $mcp_arg --output-format stream-json --permission-mode bypassPermissions >> "$session_file" 2>&1; then
error "Claude command failed"
fi
# Extract and output result
extract_result "$session_file"
}
# Command: resume
cmd_resume() {
local session_name="$1"
local prompt_arg="$2"
validate_session_name "$session_name"
local session_file="$AGENT_SESSIONS_DIR/${session_name}.jsonl"
# Check if session exists
if [ ! -f "$session_file" ]; then
error "Session '$session_name' does not exist. Use 'new' command to create it"
fi
# Load session metadata to get agent
load_session_metadata "$session_name"
# Extract session_id
local session_id
session_id=$(extract_session_id "$session_file")
# Get prompt
local prompt
prompt=$(get_prompt "$prompt_arg")
# Load agent configuration if session has an agent
local mcp_arg=""
if [ -n "$SESSION_AGENT" ]; then
load_agent_config "$SESSION_AGENT"
mcp_arg=$(build_mcp_arg "$MCP_CONFIG")
fi
# Run claude command with resume
if ! claude -r "$session_id" -p "$prompt" $mcp_arg --output-format stream-json --permission-mode bypassPermissions >> "$session_file" 2>&1; then
error "Claude resume command failed"
fi
# Update session metadata timestamp (or create if missing)
update_session_metadata "$session_name" "$SESSION_AGENT"
# Extract and output result
extract_result "$session_file"
}
# Command: list
cmd_list() {
# Ensure required directories exist
ensure_directories
# Check if there are any sessions
local session_files=("$AGENT_SESSIONS_DIR"/*.jsonl)
if [ ! -f "${session_files[0]}" ]; then
echo "No sessions found"
return
fi
# List all sessions with metadata
for session_file in "$AGENT_SESSIONS_DIR"/*.jsonl; do
local session_name
session_name=$(basename "$session_file" .jsonl)
local session_id
# Extract session_id without calling error function (for empty/initializing sessions)
if [ -s "$session_file" ]; then
session_id=$(head -n 1 "$session_file" 2>/dev/null | jq -r '.session_id // "unknown"' 2>/dev/null || echo "unknown")
else
session_id="initializing"
fi
echo "$session_name (session: $session_id)"
done
}
# Command: list-agents - List all available agent definitions from agent directories
# Scans AGENTS_DIR for subdirectories containing agent.json files
# Outputs: Agent name and description in formatted list
cmd_list_agents() {
# Ensure required directories exist
ensure_directories
# Check if there are any agent directories
local found_agents=false
for agent_dir in "$AGENTS_DIR"/*; do
if [ -d "$agent_dir" ] && [ -f "$agent_dir/agent.json" ]; then
found_agents=true
break
fi
done
if [ "$found_agents" = false ]; then
echo "No agent definitions found"
return
fi
# List all agent definitions
local first=true
for agent_dir in "$AGENTS_DIR"/*; do
# Skip if not a directory or doesn't have agent.json
if [ ! -d "$agent_dir" ] || [ ! -f "$agent_dir/agent.json" ]; then
continue
fi
local agent_name
local agent_description
local agent_file="$agent_dir/agent.json"
# Extract name and description from JSON
agent_name=$(jq -r '.name // "unknown"' "$agent_file" 2>/dev/null)
agent_description=$(jq -r '.description // "No description available"' "$agent_file" 2>/dev/null)
# Add separator before each agent (except the first)
if [ "$first" = true ]; then
first=false
else
echo "---"
echo ""
fi
# Display in requested format
echo "${agent_name}:"
echo "${agent_description}"
echo ""
done
}
# Command: clean
cmd_clean() {
# Remove the entire agent-sessions directory
if [ -d "$AGENT_SESSIONS_DIR" ]; then
rm -rf "$AGENT_SESSIONS_DIR"
echo "All sessions removed"
else
echo "No sessions to remove"
fi
}
# Main script logic
main() {
# Check if no arguments provided
if [ $# -eq 0 ]; then
show_help
exit 1
fi
local command="$1"
shift
case "$command" in
new)
# Parse arguments
if [ $# -eq 0 ]; then
error "Session name required for 'new' command"
fi
local session_name="$1"
shift
local prompt_arg=""
local agent_name=""
while [ $# -gt 0 ]; do
case "$1" in
-p)
if [ $# -lt 2 ]; then
error "-p flag requires a prompt argument"
fi
prompt_arg="$2"
shift 2
;;
--agent)
if [ $# -lt 2 ]; then
error "--agent flag requires an agent name"
fi
agent_name="$2"
shift 2
;;
*)
error "Unknown option: $1"
;;
esac
done
cmd_new "$session_name" "$prompt_arg" "$agent_name"
;;
resume)
# Parse arguments
if [ $# -eq 0 ]; then
error "Session name required for 'resume' command"
fi
local session_name="$1"
shift
local prompt_arg=""
while [ $# -gt 0 ]; do
case "$1" in
-p)
if [ $# -lt 2 ]; then
error "-p flag requires a prompt argument"
fi
prompt_arg="$2"
shift 2
;;
*)
error "Unknown option: $1"
;;
esac
done
cmd_resume "$session_name" "$prompt_arg"
;;
list)
cmd_list
;;
list-agents)
cmd_list_agents
;;
clean)
cmd_clean
;;
-h|--help)
show_help
exit 0
;;
*)
error "Unknown command: $command\n\nRun './cli-agent-runner.sh' for usage information"
;;
esac
}
# Run main function
main "$@"

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,282 @@
# CLI Agent Runner
A lightweight orchestration layer for managing multiple Claude Code agent sessions through a simple command-line interface.
## Overview
The CLI Agent Runner 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 `.cli-agent-runner/agents/`. Each agent directory must match the agent name and contains:
```
.cli-agent-runner/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
- Session ID extraction and tracking
- Agent association and configuration
- Result retrieval and formatting
- State management (initializing, active, completed)
## Use Cases
### Multi-Session Workflows
Coordinate multiple specialized sessions working on different aspects of a project:
```bash
# First, discover available agent definitions
./cli-agent-runner.sh list-agents
# Architecture session using system-architect agent
./cli-agent-runner.sh new architect --agent system-architect -p "Design microservices architecture for e-commerce"
# Development session implements based on architecture
cat architecture.md | ./cli-agent-runner.sh new developer --agent senior-developer -p "Implement based on this design:"
# Reviewer session provides feedback
./cli-agent-runner.sh 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
./cli-agent-runner.sh new technical-writer --agent documentation-expert -p "Create API documentation"
# Later refinement
./cli-agent-runner.sh resume technical-writer -p "Add authentication examples"
# Further enhancement
./cli-agent-runner.sh 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 `cli-agent-runner` 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
./cli-agent-runner.sh new architect --agent system-architect -p "Design e-commerce system"
# Create generic session (no agent)
./cli-agent-runner.sh new quick-task -p "Simple task"
# Resume remembers agent association
./cli-agent-runner.sh 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
**`cli-agent-runner.sh`**
Core bash script providing the command-line interface and orchestration logic. Handles session management, Claude Code CLI invocation, and result extraction.
### Directory Structure
The CLI Agent Runner uses a project-relative directory structure located at `.cli-agent-runner/` in the current working directory where the script is invoked.
**`.cli-agent-runner/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.
**`.cli-agent-runner/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 CLI Agent Runner 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
- **Script Help**: Run `./cli-agent-runner.sh --help` for command syntax and examples
- **Claude Code CLI**: Refer to Claude Code CLI documentation for underlying command options and usage: https://docs.claude.com/en/docs/claude-code/cli-reference

View File

@@ -0,0 +1,61 @@
# Example Agent Definitions
This reference provides a complete example agent definition demonstrating the CLI Agent Runner 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 `.cli-agent-runner/agents/` in your project directory
```bash
# From your project root
cp -r path/to/cli-agent-runner/example/agents/browser-tester .cli-agent-runner/agents/
```
Once copied to your project, the agent can be used with the CLI Agent Runner script:
```bash
# List available agents
./cli-agent-runner.sh list-agents
# Create session with the browser-tester agent
./cli-agent-runner.sh 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 `.cli-agent-runner/agents/` in your project
The folder structure keeps each agent self-contained and easy to distribute or version control.