feat(phase3): Full Phase 3 implementation - Chat Agent, PM Agent, and Integration #32

Merged
shoko merged 14 commits from feat/issue-19-phase3 into main 2026-03-31 04:55:21 +02:00
5 changed files with 290 additions and 108 deletions
Showing only changes of commit b3171ed632 - Show all commits

View File

@@ -21,15 +21,11 @@ hermes config show # Check Telegram is configured
```bash
# Create skill directories
mkdir -p ~/.hermes/skills/kugetsu-chat
mkdir -p ~/.hermes/skills/kugetsu-pm
mkdir -p ~/.hermes/skills/kugetsu-helpers
# Link skills from kugetsu repo (adjust path as needed)
KUGEETSU_DIR="/path/to/kugetsu" # e.g., ~/repositories/kugetsu
ln -sf "$KUGEETSU_DIR/skills/kugetsu-chat" ~/.hermes/skills/kugetsu-chat
ln -sf "$KUGEETSU_DIR/skills/kugetsu-pm ~/.hermes/skills/kugetsu-pm
ln -sf "$KUGEETSU_DIR/skills/kugetsu-helpers" ~/.hermes/skills/kugetsu-helpers
```
## Step 3: Install Chat Agent SOUL
@@ -39,18 +35,7 @@ ln -sf "$KUGEETSU_DIR/skills/kugetsu-helpers" ~/.hermes/skills/kugetsu-helpers
cp "$KUGEETSU_DIR/skills/kugetsu-chat/SOUL.md" ~/.hermes/SOUL-chat.md
```
## Step 4: Install Helper Scripts
```bash
# Copy helper script to PATH
cp "$KUGEETSU_DIR/skills/kugetsu-helpers/scripts/kugetsu-helpers" ~/.local/bin/kugetsu-helper
chmod +x ~/.local/bin/kugetsu-helper
# Verify
kugetsu-helper help
```
## Step 5: Verify Gateway is Running
## Step 4: Verify Gateway is Running
```bash
hermes gateway status
@@ -58,7 +43,7 @@ hermes gateway status
hermes gateway start
```
## Step 6: Initialize kugetsu
## Step 5: Initialize kugetsu
**WARNING:** This requires an interactive terminal (TTY) because it spawns the opencode TUI.
@@ -75,22 +60,22 @@ kugetsu init # Run manually in the SSH session
This creates:
- **Base session** (for forking dev agents)
- **PM Agent session** (persistent coordinator)
- **PM Agent session** (persistent coordinator, loaded with kugetsu-pm context)
If you get `Error: init requires a terminal (TTY)`, you're running via non-interactive SSH. Use `-t` flag or connect directly.
## Step 7: Verify Setup
## Step 6: Verify Setup
```bash
# Check kugetsu status
kugetsu list
# Check PM agent exists
kugetsu-helper check-status
kugetsu status
# Should output: ok
# List all sessions
kugetsu list
```
## Step 8: Test via Telegram
## Step 7: Test via Telegram
Start a conversation with your bot (@your_bot_username):
@@ -102,7 +87,7 @@ Start a conversation with your bot (@your_bot_username):
## Troubleshooting
### kugetsu-helper not found
### kugetsu command not found
```bash
export PATH="$HOME/.local/bin:$PATH"
# Or add to ~/.bashrc
@@ -114,22 +99,46 @@ echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
hermes gateway restart
```
### PM agent missing
### PM agent issues
```bash
# Reinitialize
# Diagnose
kugetsu doctor
# Fix (if needed)
kugetsu doctor --fix
# Or reinitialize
kugetsu destroy --pm-agent -y
kugetsu init
```
## kugetsu Commands
| Command | Description |
|---------|-------------|
| `kugetsu init` | Initialize base + PM agent sessions |
| `kugetsu status` | Check if kugetsu is ready |
| `kugetsu delegate <msg>` | Send message to PM agent |
| `kugetsu doctor [--fix]` | Diagnose and fix issues |
| `kugetsu start <issue-ref> <msg>` | Start dev agent for issue |
| `kugetsu continue <issue-ref> <msg>` | Continue existing issue session |
| `kugetsu list` | List all tracked sessions |
| `kugetsu prune [--force]` | Clean up orphaned sessions |
## File Locations
| File | Location | Purpose |
|------|----------|---------|
| Chat Agent SOUL | `~/.hermes/SOUL-chat.md` | Personality |
| kugetsu-chat skill | `~/.hermes/skills/kugetsu-chat/` | Routing behavior |
| kugetsu-pm skill | `~/.hermes/skills/kugetsu-pm/` | PM Agent docs |
| kugetsu-helpers | `~/.hermes/skills/kugetsu-helpers/` | Helper functions |
| Helper script | `~/.local/bin/kugetsu-helper` | CLI helper |
| kugetsu | `~/.local/bin/kugetsu` | Main CLI |
~/.kugetsu/
├── sessions/
│ ├── base.json # Base opencode session
│ └── pm-agent.json # PM Agent opencode session
├── index.json # Session registry
└── pm-agent.md # PM context (optional, injected at init)
## Architecture Summary
@@ -137,60 +146,22 @@ kugetsu init
~/.hermes/
├── SOUL-chat.md # Chat Agent personality
└── skills/
── kugetsu-chat/ # Routing + delegation logic
├── kugetsu-pm/ # PM Agent documentation
└── kugetsu-helpers/ # Shell helpers for terminal()
── kugetsu-chat/ # Routing + delegation via kugetsu CLI
~/.kugetsu/
├── sessions/
│ ├── base.json # Base opencode session
│ └── pm-agent.json # PM Agent opencode session
── index.json # Session registry
── index.json # Session registry
└── pm-agent.md # PM context (optional)
~/.local/bin/
└── kugetsu-helper # CLI helper script
└── kugetsu # Main CLI (handles delegation, status, doctor)
```
## Testing Plan (Manual)
## PM Context (Optional)
### Test 1: Casual Conversation
**Objective:** Verify Hermes handles small talk directly without delegation
| Step | Action | Expected Result |
|------|--------|-----------------|
| 1 | Send `hi` to @your_bot_username | Bot responds with greeting |
| 2 | Send `how are you?` | Bot responds naturally |
### Test 2: Task Delegation
**Objective:** Verify Hermes delegates task to PM Agent via `kugetsu-helper`
| Step | Action | Expected Result |
|------|--------|-----------------|
| 1 | Send `status?` to bot | Bot routes to PM, PM responds |
| 2 | Send `fix issue #5` to bot | PM agent receives task via opencode |
| 3 | Send `Work on issue #35` to bot | PM agent creates branch, worktree, PR |
### Test 3: Error Handling
**Objective:** Verify graceful error handling
| Step | Action | Expected Result |
|------|--------|-----------------|
| 1 | Send `status?` with PM agent stopped | Bot says "PM agent not available" |
| 2 | Send `status?` before `kugetsu init` | Bot says "kugetsu not initialized" |
### Debugging
If delegation fails:
```bash
# Check Hermes logs
hermes gateway logs
# Check PM agent is running
kugetsu-helper check-status
# Check kugetsu-helper directly
~/.local/bin/kugetsu-helper delegate-to-pm "test"
```
To customize PM Agent behavior, create `~/.kugetsu/pm-agent.md` with additional context. This file is injected into the PM Agent session at init time.
## Security Notes

View File

@@ -5,7 +5,7 @@ license: MIT
compatibility: Requires Hermes agent with Telegram configured, kugetsu CLI, opencode sessions.
metadata:
author: shoko
version: "2.0"
version: "3.0"
---
# kugetsu-chat - REQUIRED SKILL FOR KUGETSU ROUTING
@@ -37,12 +37,12 @@ When you MUST use this skill:
### Step 2: Check if kugetsu is initialized
```
terminal(command="~/.local/bin/kugetsu-helper check-status", timeout=10)
terminal(command="kugetsu status", timeout=10)
```
### Step 3: If initialized, DELEGATE immediately
```
terminal(command="~/.local/bin/kugetsu-helper delegate-to-pm '<entire user message>'", timeout=120)
terminal(command="kugetsu delegate '<entire user message>'", timeout=120)
```
### Step 4: Relay the response to the user
@@ -52,12 +52,12 @@ terminal(command="~/.local/bin/kugetsu-helper delegate-to-pm '<entire user messa
The ONLY command you should use for delegation:
```bash
~/.local/bin/kugetsu-helper delegate-to-pm '<user message>'
kugetsu delegate '<user message>'
```
Example:
```
terminal(command="~/.local/bin/kugetsu-helper delegate-to-pm 'fix issue #5 in github.com/shoko/kugetsu'", timeout=120)
terminal(command="kugetsu delegate 'fix issue #5 in github.com/shoko/kugetsu'", timeout=120)
```
## Error Handling
@@ -67,26 +67,28 @@ terminal(command="~/.local/bin/kugetsu-helper delegate-to-pm 'fix issue #5 in gi
| `ok` | kugetsu is ready | Proceed with delegation |
| `kugetsu_not_initialized` | Not set up | Tell user to run `kugetsu init` |
| `pm_agent_missing` | PM not created | Tell user to run `kugetsu init` |
| `pm_agent_expired` | PM session expired | Tell user to run `kugetsu doctor --fix` |
## Quick Reference
**DELEGATION COMMAND:**
```
terminal(command="~/.local/bin/kugetsu-helper delegate-to-pm '<message>'", timeout=120)
terminal(command="kugetsu delegate '<message>'", timeout=120)
```
**CHECK STATUS:**
```
terminal(command="~/.local/bin/kugetsu-helper check-status", timeout=10)
terminal(command="kugetsu status", timeout=10)
```
## Required Files
## Required Dependencies
- `~/.local/bin/kugetsu-helper` - The delegation helper script
- `kugetsu` CLI installed and in PATH
- kugetsu initialized via `kugetsu init`
## Notes
- ALWAYS use the full path `~/.local/bin/kugetsu-helper`
- ALWAYS use `delegate-to-pm` subcommand
- ALWAYS use `kugetsu delegate` command (not kugetsu-helper)
- ALWAYS wrap user message in single quotes inside the command
- ALWAYS use timeout of at least 120 seconds for delegation
- kugetsu delegates to the persistent PM agent session created during init

View File

@@ -32,7 +32,7 @@ For ANY message that is not casual conversation, you MUST:
## Required Delegation Command
```
terminal(command="~/.local/bin/kugetsu-helper delegate-to-pm '<user message>'", timeout=120)
terminal(command="kugetsu delegate '<user message>'", timeout=120)
```
## When NOT to Delegate

View File

@@ -15,10 +15,13 @@ Usage:
kugetsu init [--force] Initialize base + pm-agent sessions (requires TTY)
kugetsu start <issue-ref> <message> [--debug] Start task for issue (forks base session)
kugetsu continue <issue-ref> [message] [--debug] Continue existing task for issue
kugetsu delegate <message> Send message to PM agent
kugetsu status Check kugetsu initialization status
kugetsu doctor [--fix] Diagnose and fix kugetsu issues
kugetsu list List all tracked sessions
kugetsu prune [--force] Remove orphaned sessions (keeps base + pm-agent)
kugetsu destroy <issue-ref> [-y] Delete session for issue
kugetsu destroy --pm-agent [-y] Delete pm-agent session
kugetsu destroy --pm-agent [-y] Delete pm-agent session (not recommended)
kugetsu destroy --base [-y] Delete base session
kugetsu help Show this help
@@ -32,6 +35,10 @@ Commands:
start Fork new session from base for specific issue.
Requires pm-agent to be running (created by init).
continue Continue work on existing issue session.
delegate Send message to PM agent for task coordination.
PM context is loaded once at init time.
status Check if kugetsu is initialized and PM agent is active.
doctor Diagnose kugetsu issues. Use --fix to attempt repairs.
list Show all sessions (base + pm-agent + forked issues).
prune Remove sessions not in index (orphaned from opencode).
Use --force to skip confirmation.
@@ -40,14 +47,20 @@ Commands:
Options:
--debug Show real-time debug output and capture to debug.log
PM Context:
kugetsu reads ~/.kugetsu/pm-agent.md (if exists) and injects it
into the PM agent session at init time. This allows customizing PM
behavior without recreating the session.
Examples:
kugetsu init
kugetsu status
kugetsu delegate "work on issue #5"
kugetsu doctor
kugetsu doctor --fix
kugetsu start github.com/shoko/kugetsu#14 "fix bug"
kugetsu continue github.com/shoko/kugetsu#14 "add tests"
kugetsu list
kugetsu prune
kugetsu prune --force
kugetsu destroy github.com/shoko/kugetsu#14
EOF
}
@@ -283,6 +296,188 @@ check_opencode_session_exists() {
opencode session list 2>/dev/null | grep -q "^$session_id"
}
kugetsu_get_pm_context() {
local pm_context_file="${KUGETSU_DIR}/pm-agent.md"
if [ -f "$pm_context_file" ]; then
cat "$pm_context_file"
else
echo ""
fi
}
cmd_status() {
if [ ! -f "$INDEX_FILE" ]; then
echo "kugetsu_not_initialized"
return
fi
local base=$(get_base_session_id)
local pm_agent=$(get_pm_agent_session_id)
if [ -z "$base" ] || [ "$base" = "null" ]; then
echo "base_session_missing"
return
fi
if [ -z "$pm_agent" ] || [ "$pm_agent" = "null" ] || [ "$pm_agent" = "None" ]; then
echo "pm_agent_missing"
return
fi
if ! check_opencode_session_exists "$pm_agent"; then
echo "pm_agent_expired"
return
fi
echo "ok"
}
cmd_delegate() {
local message="${1:-}"
if [ -z "$message" ]; then
echo "Error: message is required" >&2
echo "Usage: kugetsu delegate <message>" >&2
exit 1
fi
local pm_session=$(get_pm_agent_session_id)
if [ -z "$pm_session" ] || [ "$pm_session" = "null" ] || [ "$pm_session" = "None" ]; then
echo "Error: PM agent session not found. Run 'kugetsu init' first." >&2
exit 1
fi
if ! check_opencode_session_exists "$pm_session"; then
echo "Error: PM agent session has expired. Run 'kugetsu init' again." >&2
exit 1
fi
opencode run --continue --session "$pm_session" "$message" 2>&1
}
cmd_doctor() {
local fix=false
while [ $# -gt 0 ]; do
case "$1" in
--fix)
fix=true
;;
*)
;;
esac
shift
done
echo "=== kugetsu doctor ==="
echo ""
local issues=0
if [ ! -f "$INDEX_FILE" ]; then
echo "[ISSUE] kugetsu not initialized (index.json missing)"
issues=$((issues + 1))
else
echo "[OK] kugetsu initialized"
local base=$(get_base_session_id)
if [ -z "$base" ] || [ "$base" = "null" ]; then
echo "[ISSUE] Base session missing"
issues=$((issues + 1))
else
echo "[OK] Base session: $base"
if check_opencode_session_exists "$base"; then
echo "[OK] Base session active"
else
echo "[ISSUE] Base session expired"
issues=$((issues + 1))
fi
fi
local pm_agent=$(get_pm_agent_session_id)
if [ -z "$pm_agent" ] || [ "$pm_agent" = "null" ] || [ "$pm_agent" = "None" ]; then
echo "[ISSUE] PM agent session missing"
issues=$((issues + 1))
else
echo "[OK] PM agent: $pm_agent"
if check_opencode_session_exists "$pm_agent"; then
echo "[OK] PM agent session active"
else
echo "[ISSUE] PM agent session expired"
issues=$((issues + 1))
fi
fi
local pm_context_file="${KUGETSU_DIR}/pm-agent.md"
if [ -f "$pm_context_file" ]; then
echo "[OK] PM context file exists"
else
echo "[INFO] PM context file not found (optional): $pm_context_file"
fi
fi
echo ""
if [ $issues -eq 0 ]; then
echo "No issues found."
else
echo "Found $issues issue(s)."
fi
if [ "$fix" = true ] && [ $issues -gt 0 ]; then
echo ""
echo "Running fixes..."
if [ ! -f "$INDEX_FILE" ]; then
echo "Cannot fix: not initialized. Run 'kugetsu init' first."
else
local pm_agent=$(get_pm_agent_session_id)
if [ -n "$pm_agent" ] && [ "$pm_agent" != "null" ] && [ "$pm_agent" != "None" ]; then
if ! check_opencode_session_exists "$pm_agent"; then
echo "[FIX] Recreating expired PM agent session..."
local base=$(get_base_session_id)
if [ -n "$base" ] && [ "$base" != "null" ]; then
rm -f "$SESSIONS_DIR/pm-agent.json"
local before_sessions=$(opencode session list 2>/dev/null | grep -oP '^ses_\w+' | sort)
local before_set="${before_sessions//$'\n'/|}"
local pm_context=$(kugetsu_get_pm_context)
if [ -n "$pm_context" ]; then
opencode run --fork --session "$base" "You are a PM (Project Manager) agent. Your role is to coordinate task delegation and review PRs. $pm_context" 2>&1 || true
else
opencode run --fork --session "$base" "You are a PM (Project Manager) agent. Your role is to coordinate task delegation and review PRs. Wait for instructions." 2>&1 || true
fi
local after_sessions=$(opencode session list 2>/dev/null | grep -oP '^ses_\w+' | sort)
local new_pm_session_id=""
while IFS= read -r sess; do
if [[ ! "$before_set" =~ \|${sess}\| ]] && [[ "$sess" != "$base" ]]; then
new_pm_session_id="$sess"
break
fi
done <<< "$after_sessions"
if [ -n "$new_pm_session_id" ]; then
printf '{"type": "pm_agent", "opencode_session_id": "%s", "created_at": "%s", "state": "idle"}\n' \
"$new_pm_session_id" "$(date -Iseconds)" > "$SESSIONS_DIR/pm-agent.json"
set_pm_agent_in_index "$new_pm_session_id"
echo "[FIX] PM agent recreated: $new_pm_session_id"
else
echo "[FIX] Warning: Could not detect new PM session ID"
fi
else
echo "[FIX] Cannot recreate PM agent: base session missing"
fi
else
echo "[FIX] PM agent is active, no fix needed"
fi
else
echo "[FIX] Cannot fix: PM agent not initialized. Run 'kugetsu init' first."
fi
fi
fi
}
DEBUG_MODE=false
set_debug_mode() {
@@ -365,7 +560,13 @@ cmd_init() {
local before_sessions=$(opencode session list 2>/dev/null | grep -oP '^ses_\w+' | sort)
local before_set="${before_sessions//$'\n'/|}"
opencode run --fork --session "$new_session_id" "You are a PM (Project Manager) agent. Your role is to coordinate task delegation and review PRs. Wait for instructions." 2>&1 || true
local pm_context=$(kugetsu_get_pm_context)
local pm_prompt="You are a PM (Project Manager) agent. Your role is to coordinate task delegation and review PRs. Wait for instructions."
if [ -n "$pm_context" ]; then
pm_prompt="You are a PM (Project Manager) agent. Your role is to coordinate task delegation and review PRs. $pm_context"
fi
opencode run --fork --session "$new_session_id" "$pm_prompt" 2>&1 || true
local after_sessions=$(opencode session list 2>/dev/null | grep -oP '^ses_\w+' | sort)
local new_pm_session_id=""
@@ -474,22 +675,22 @@ cmd_start() {
}
cmd_continue() {
local issue_ref=""
local session_name=""
local message=""
local args=("$@")
args=$(set_debug_mode "${args[@]}")
for arg in $args; do
if [ -z "$issue_ref" ]; then
issue_ref="$arg"
if [ -z "$session_name" ]; then
session_name="$arg"
elif [ -z "$message" ]; then
message="$arg"
fi
done
if [ -z "$issue_ref" ]; then
echo "Error: continue requires <issue-ref>" >&2
if [ -z "$session_name" ]; then
echo "Error: continue requires <session-name>" >&2
exit 1
fi
@@ -498,19 +699,17 @@ cmd_continue() {
exit 1
fi
validate_issue_ref "$issue_ref"
local session_file=$(get_session_for_issue "$issue_ref")
local session_file=$(get_session_for_issue "$session_name")
if [ -z "$session_file" ] || [ "$session_file" = "null" ]; then
echo "Error: No session found for '$issue_ref'" >&2
echo "Use 'kugetsu start $issue_ref <message>' to create one" >&2
echo "Error: No session found for '$session_name'" >&2
echo "Use 'kugetsu start <issue-ref> <message>' to create one" >&2
exit 1
fi
local session_path="$SESSIONS_DIR/$session_file"
if [ ! -f "$session_path" ]; then
echo "Error: Session file missing: $session_path" >&2
echo "Run 'kugetsu start $issue_ref <message>' to recreate" >&2
echo "Run 'kugetsu start <issue-ref> <message>' to recreate" >&2
exit 1
fi
@@ -522,7 +721,7 @@ cmd_continue() {
echo "Attempting to continue anyway..." >&2
fi
echo "Continuing session for '$issue_ref'..."
echo "Continuing session for '$session_name'..."
if [ -n "$worktree_path" ] && [ -d "$worktree_path" ]; then
echo "Using worktree: $worktree_path"
if [ "$DEBUG_MODE" = true ]; then
@@ -770,6 +969,15 @@ main() {
continue)
cmd_continue "$@"
;;
delegate)
cmd_delegate "$@"
;;
status)
cmd_status
;;
doctor)
cmd_doctor "$@"
;;
list)
cmd_list "$@"
;;

View File

@@ -48,10 +48,8 @@ echo "=== Phase 3a Chat Agent Setup (Optional) ==="
echo "To also install the Chat Agent skills for Phase 3a:"
echo ""
echo " 1. Link skills to Hermes:"
echo " mkdir -p ~/.hermes/skills/kugetsu-chat ~/.hermes/skills/kugetsu-pm ~/.hermes/skills/kugetsu-helpers"
echo " mkdir -p ~/.hermes/skills/kugetsu-chat"
echo " ln -sf /path/to/kugetsu/skills/kugetsu-chat ~/.hermes/skills/"
echo " ln -sf /path/to/kugetsu/skills/kugetsu-pm ~/.hermes/skills/"
echo " ln -sf /path/to/kugetsu/skills/kugetsu-helpers ~/.hermes/skills/"
echo ""
echo " 2. Install Chat Agent SOUL:"
echo " cp /path/to/kugetsu/skills/kugetsu-chat/SOUL.md ~/.hermes/SOUL-chat.md"
@@ -59,4 +57,7 @@ echo ""
echo " 3. Initialize kugetsu (requires TTY):"
echo " kugetsu init"
echo ""
echo " 4. Verify setup:"
echo " kugetsu status"
echo ""
echo "See docs/phase3a-setup.md for full installation guide."