Add PA Agent Mode implementation plan
9-task plan covering: - Directory structure and JSON state files - pa-mode launch script with tmux management - pa-summarize hook script - Hyprland keybind update - PA agent memory loading instructions - End-to-end testing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
470
docs/plans/2024-12-29-pa-agent-mode-implementation.md
Normal file
470
docs/plans/2024-12-29-pa-agent-mode-implementation.md
Normal file
@@ -0,0 +1,470 @@
|
||||
# PA Agent Mode Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Create a persistent Claude Code environment with tmux, full autonomy, and long-term memory.
|
||||
|
||||
**Architecture:** Shell scripts manage tmux session lifecycle. Memory stored as JSON files. Hyprland keybind launches via existing `omarchy-launch-tui` pattern. PA agent instructions updated to load memory on startup.
|
||||
|
||||
**Tech Stack:** Bash, tmux, JSON, Hyprland config
|
||||
|
||||
---
|
||||
|
||||
## Task 1: Create Directory Structure
|
||||
|
||||
**Files:**
|
||||
- Create: `~/.claude/state/personal-assistant/history/`
|
||||
- Create: `~/.claude/state/personal-assistant/memory/`
|
||||
|
||||
**Step 1: Create directories**
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.claude/state/personal-assistant/history
|
||||
mkdir -p ~/.claude/state/personal-assistant/memory
|
||||
```
|
||||
|
||||
Run: `mkdir -p ~/.claude/state/personal-assistant/history ~/.claude/state/personal-assistant/memory`
|
||||
|
||||
**Step 2: Verify directories exist**
|
||||
|
||||
Run: `ls -la ~/.claude/state/personal-assistant/`
|
||||
Expected: `history` and `memory` directories listed
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
# No git commit - these are runtime directories, not tracked
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Create History Index File
|
||||
|
||||
**Files:**
|
||||
- Create: `~/.claude/state/personal-assistant/history/index.json`
|
||||
|
||||
**Step 1: Create index.json with empty sessions array**
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"sessions": []
|
||||
}
|
||||
```
|
||||
|
||||
Write to: `~/.claude/state/personal-assistant/history/index.json`
|
||||
|
||||
**Step 2: Verify file is valid JSON**
|
||||
|
||||
Run: `cat ~/.claude/state/personal-assistant/history/index.json | jq .`
|
||||
Expected: Pretty-printed JSON with empty sessions array
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Create Memory Category Files
|
||||
|
||||
**Files:**
|
||||
- Create: `~/.claude/state/personal-assistant/memory/decisions.json`
|
||||
- Create: `~/.claude/state/personal-assistant/memory/preferences.json`
|
||||
- Create: `~/.claude/state/personal-assistant/memory/projects.json`
|
||||
- Create: `~/.claude/state/personal-assistant/memory/facts.json`
|
||||
- Create: `~/.claude/state/personal-assistant/memory/meta.json`
|
||||
|
||||
**Step 1: Create decisions.json**
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"description": "Decisions made with rationale",
|
||||
"items": []
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: Create preferences.json**
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"description": "User preferences learned over time",
|
||||
"items": []
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: Create projects.json**
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"description": "Active and recent project context",
|
||||
"items": []
|
||||
}
|
||||
```
|
||||
|
||||
**Step 4: Create facts.json**
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"description": "Factual knowledge about the environment",
|
||||
"items": []
|
||||
}
|
||||
```
|
||||
|
||||
**Step 5: Create meta.json**
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"last_summarized": null,
|
||||
"total_sessions": 0,
|
||||
"total_items": {
|
||||
"decisions": 0,
|
||||
"preferences": 0,
|
||||
"projects": 0,
|
||||
"facts": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Step 6: Verify all files are valid JSON**
|
||||
|
||||
Run: `for f in ~/.claude/state/personal-assistant/memory/*.json; do echo "=== $f ===" && jq . "$f"; done`
|
||||
Expected: All 5 files display as valid JSON
|
||||
|
||||
---
|
||||
|
||||
## Task 4: Create pa-mode Launch Script
|
||||
|
||||
**Files:**
|
||||
- Create: `~/.claude/automation/pa-mode`
|
||||
|
||||
**Step 1: Write the pa-mode script**
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# PA Agent Mode - Launch/attach to persistent PA tmux session
|
||||
set -euo pipefail
|
||||
|
||||
SESSION_NAME="pa"
|
||||
HISTORY_DIR="$HOME/.claude/state/personal-assistant/history"
|
||||
INDEX_FILE="$HISTORY_DIR/index.json"
|
||||
|
||||
usage() {
|
||||
echo "Usage: pa-mode [command]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " (none) Attach to existing session or create new one"
|
||||
echo " new Force new session (detaches existing if any)"
|
||||
echo " kill Terminate the PA session"
|
||||
echo " status Show session status"
|
||||
echo ""
|
||||
}
|
||||
|
||||
get_session_id() {
|
||||
date +"%Y-%m-%d_%H-%M-%S"
|
||||
}
|
||||
|
||||
create_session() {
|
||||
local session_id
|
||||
session_id=$(get_session_id)
|
||||
local history_file="$HISTORY_DIR/${session_id}.jsonl"
|
||||
|
||||
# Record session start in index
|
||||
local tmp_file
|
||||
tmp_file=$(mktemp)
|
||||
jq --arg id "$session_id" --arg started "$(date -Iseconds)" \
|
||||
'.sessions += [{"id": $id, "started": $started, "ended": null, "summarized": false, "topics": []}]' \
|
||||
"$INDEX_FILE" > "$tmp_file" && mv "$tmp_file" "$INDEX_FILE"
|
||||
|
||||
# Create tmux session with claude in PA mode
|
||||
# Using HISTFILE-like approach: set env var for history location
|
||||
tmux new-session -d -s "$SESSION_NAME" -c "$HOME" \
|
||||
"PA_SESSION_ID='$session_id' PA_HISTORY_FILE='$history_file' claude --dangerously-skip-permissions --agent personal-assistant"
|
||||
|
||||
echo "Created new PA session: $session_id"
|
||||
}
|
||||
|
||||
attach_session() {
|
||||
if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
||||
tmux attach-session -t "$SESSION_NAME"
|
||||
else
|
||||
create_session
|
||||
tmux attach-session -t "$SESSION_NAME"
|
||||
fi
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
"")
|
||||
attach_session
|
||||
;;
|
||||
new)
|
||||
if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
||||
echo "Killing existing session..."
|
||||
tmux kill-session -t "$SESSION_NAME"
|
||||
fi
|
||||
create_session
|
||||
tmux attach-session -t "$SESSION_NAME"
|
||||
;;
|
||||
kill)
|
||||
if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
||||
tmux kill-session -t "$SESSION_NAME"
|
||||
echo "PA session terminated"
|
||||
else
|
||||
echo "No PA session running"
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
||||
echo "PA session is running"
|
||||
tmux list-sessions -F "#{session_name}: #{session_created} (#{session_attached} attached)" | grep "^$SESSION_NAME:"
|
||||
else
|
||||
echo "PA session is not running"
|
||||
fi
|
||||
;;
|
||||
-h|--help|help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
**Step 2: Make script executable**
|
||||
|
||||
Run: `chmod +x ~/.claude/automation/pa-mode`
|
||||
|
||||
**Step 3: Verify script syntax**
|
||||
|
||||
Run: `bash -n ~/.claude/automation/pa-mode && echo "Syntax OK"`
|
||||
Expected: "Syntax OK"
|
||||
|
||||
**Step 4: Test help output**
|
||||
|
||||
Run: `~/.claude/automation/pa-mode --help`
|
||||
Expected: Usage information displayed
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
cd ~/.claude && git add automation/pa-mode && git commit -m "feat: add pa-mode launch script"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: Create pa-summarize Hook Script
|
||||
|
||||
**Files:**
|
||||
- Create: `~/.claude/automation/pa-summarize`
|
||||
|
||||
**Step 1: Write the pa-summarize script**
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# PA Summarize - Extract session summary before shutdown
|
||||
set -euo pipefail
|
||||
|
||||
MEMORY_DIR="$HOME/.claude/state/personal-assistant/memory"
|
||||
INDEX_FILE="$HOME/.claude/state/personal-assistant/history/index.json"
|
||||
|
||||
# This script is called by tmux hook or manually
|
||||
# It sends a summarization request to the running claude session
|
||||
|
||||
SESSION_NAME="pa"
|
||||
|
||||
if ! tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
||||
echo "No PA session running"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Send summarization prompt to the tmux pane
|
||||
# The PA agent will handle extracting and saving to memory files
|
||||
tmux send-keys -t "$SESSION_NAME" \
|
||||
"Please summarize this session for long-term memory. Extract key decisions, preferences learned, project context, and facts into the appropriate memory files in ~/.claude/state/personal-assistant/memory/. Then mark this session as summarized in the history index." \
|
||||
Enter
|
||||
|
||||
echo "Summarization request sent to PA session"
|
||||
```
|
||||
|
||||
**Step 2: Make script executable**
|
||||
|
||||
Run: `chmod +x ~/.claude/automation/pa-summarize`
|
||||
|
||||
**Step 3: Verify script syntax**
|
||||
|
||||
Run: `bash -n ~/.claude/automation/pa-summarize && echo "Syntax OK"`
|
||||
Expected: "Syntax OK"
|
||||
|
||||
**Step 4: Commit**
|
||||
|
||||
```bash
|
||||
cd ~/.claude && git add automation/pa-summarize && git commit -m "feat: add pa-summarize hook script"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 6: Update Hyprland Keybind
|
||||
|
||||
**Files:**
|
||||
- Modify: `~/.config/hypr/bindings.conf`
|
||||
|
||||
**Step 1: Update the SUPER SHIFT C binding**
|
||||
|
||||
Find line:
|
||||
```conf
|
||||
bindd = SUPER SHIFT, C, Claude Code, exec, omarchy-launch-tui tmux new-session -A -s claude-code claude
|
||||
```
|
||||
|
||||
Replace with:
|
||||
```conf
|
||||
bindd = SUPER SHIFT, C, PA Agent Mode, exec, omarchy-launch-tui /home/will/.claude/automation/pa-mode
|
||||
```
|
||||
|
||||
**Step 2: Reload Hyprland config**
|
||||
|
||||
Run: `hyprctl reload`
|
||||
Expected: No errors
|
||||
|
||||
**Step 3: Verify binding registered**
|
||||
|
||||
Run: `hyprctl binds | grep -i "PA Agent"`
|
||||
Expected: Shows the PA Agent Mode binding
|
||||
|
||||
---
|
||||
|
||||
## Task 7: Update PA Agent Instructions
|
||||
|
||||
**Files:**
|
||||
- Modify: `~/.claude/agents/personal-assistant.md`
|
||||
|
||||
**Step 1: Add memory loading to initialization section**
|
||||
|
||||
Find the initialization section after line 14 and add memory files to the list. Update the code block:
|
||||
|
||||
```markdown
|
||||
**Read these state files before executing tasks:**
|
||||
|
||||
```
|
||||
~/.claude/state/system-instructions.json # Process definitions
|
||||
~/.claude/state/future-considerations.json # Deferred features
|
||||
~/.claude/state/model-policy.json # Model selection rules
|
||||
~/.claude/state/autonomy-levels.json # Autonomy definitions
|
||||
~/.claude/state/personal-assistant-preferences.json # PA persistent config
|
||||
~/.claude/state/personal-assistant/session-context.json # Session context override
|
||||
~/.claude/state/personal-assistant/general-instructions.json # User memory
|
||||
~/.claude/state/personal-assistant/memory/decisions.json # Decisions with rationale
|
||||
~/.claude/state/personal-assistant/memory/preferences.json # Learned preferences
|
||||
~/.claude/state/personal-assistant/memory/projects.json # Project context
|
||||
~/.claude/state/personal-assistant/memory/facts.json # Environment facts
|
||||
```
|
||||
```
|
||||
|
||||
**Step 2: Add PA Agent Mode section before Notes**
|
||||
|
||||
Insert before the "## Notes" section (around line 235):
|
||||
|
||||
```markdown
|
||||
## PA Agent Mode
|
||||
|
||||
When running in PA Agent Mode (tmux session "pa" with `--dangerously-skip-permissions`):
|
||||
|
||||
### Memory System
|
||||
|
||||
**On startup:**
|
||||
1. Read all memory files from `~/.claude/state/personal-assistant/memory/`
|
||||
2. Check `history/index.json` for unsummarized sessions
|
||||
3. If unsummarized sessions exist, offer: "Last session wasn't summarized. Review it now?"
|
||||
|
||||
**During session:**
|
||||
- Respond to `/pa --summarize` or "summarize this session" by extracting:
|
||||
- Decisions → `memory/decisions.json`
|
||||
- Preferences learned → `memory/preferences.json`
|
||||
- Project context → `memory/projects.json`
|
||||
- Facts → `memory/facts.json`
|
||||
- Update `memory/meta.json` timestamps
|
||||
- Mark session as summarized in `history/index.json`
|
||||
|
||||
**Memory item format:**
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"date": "YYYY-MM-DD",
|
||||
"content": "description of item",
|
||||
"context": "optional additional context",
|
||||
"session": "session-id"
|
||||
}
|
||||
```
|
||||
|
||||
### History Search
|
||||
|
||||
When asked about past conversations:
|
||||
1. Search `history/index.json` for relevant session IDs by topic
|
||||
2. Read the corresponding `.jsonl` files
|
||||
3. Provide relevant context from historical sessions
|
||||
```
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
cd ~/.claude && git add agents/personal-assistant.md && git commit -m "feat: add PA Agent Mode memory instructions"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 8: End-to-End Test
|
||||
|
||||
**Step 1: Verify pa-mode creates session**
|
||||
|
||||
Run: `~/.claude/automation/pa-mode status`
|
||||
Expected: "PA session is not running"
|
||||
|
||||
Run: `~/.claude/automation/pa-mode new &` then `sleep 2 && tmux has-session -t pa && echo "Session created"`
|
||||
Expected: "Session created"
|
||||
|
||||
**Step 2: Verify index was updated**
|
||||
|
||||
Run: `cat ~/.claude/state/personal-assistant/history/index.json | jq '.sessions | length'`
|
||||
Expected: `1`
|
||||
|
||||
**Step 3: Kill test session**
|
||||
|
||||
Run: `~/.claude/automation/pa-mode kill`
|
||||
Expected: "PA session terminated"
|
||||
|
||||
**Step 4: Test keybind (manual)**
|
||||
|
||||
Press Super+Shift+C
|
||||
Expected: Alacritty opens with PA session attached
|
||||
|
||||
---
|
||||
|
||||
## Task 9: Final Commit
|
||||
|
||||
**Step 1: Check git status**
|
||||
|
||||
Run: `cd ~/.claude && git status`
|
||||
Expected: All changes committed, working tree clean
|
||||
|
||||
**Step 2: Tag release**
|
||||
|
||||
```bash
|
||||
cd ~/.claude && git tag -a v1.0.0-pa-mode -m "PA Agent Mode implementation"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Task | Description | Files |
|
||||
|------|-------------|-------|
|
||||
| 1 | Create directories | history/, memory/ |
|
||||
| 2 | Create history index | history/index.json |
|
||||
| 3 | Create memory files | memory/*.json (5 files) |
|
||||
| 4 | Create pa-mode script | automation/pa-mode |
|
||||
| 5 | Create pa-summarize script | automation/pa-summarize |
|
||||
| 6 | Update Hyprland keybind | ~/.config/hypr/bindings.conf |
|
||||
| 7 | Update PA agent instructions | agents/personal-assistant.md |
|
||||
| 8 | End-to-end test | (verification) |
|
||||
| 9 | Final commit + tag | (git) |
|
||||
Reference in New Issue
Block a user