| name | project-session-manager |
| description | Manage isolated dev environments with git worktrees and tmux sessions |
| aliases | ["psm"] |
| version | 0.1.0 |
| source | fork |
| checksum | 4681cc8efacfc2f52a9f5fa9c38647b5884696abe35d6efe70b8159480a69582 |
| updated_at | "2026-02-11T01:29:29.000Z" |
| layer | domain |
Project Session Manager (PSM) Skill
Native Subagent Protocol (Codex)
Codex supports native subagents. Delegate with spawn_agent, coordinate with send_input, collect via wait_agent, and clean up with close_agent.
Execution preference:
- Use native subagents first for independent workstreams (parallel when possible).
- Merge results in main thread and run final verification.
- Fallback only when delegation is blocked: use the
[ANALYST]/[ARCHITECT]/[EXECUTOR]/[REVIEWER] structure in a single response.
Minimal orchestration pattern:
spawn_agent -> send_input (optional) -> wait_agent -> close_agent
Codex invocation: use $project-session-manager ... or project-session-manager: ...
Automate isolated development environments using git worktrees and tmux sessions with Codex. Enables parallel work across multiple tasks, projects, and repositories.
Commands
| Command | Description | Example |
|---|
review <ref> | PR review session | $psm review omc#123 |
fix <ref> | Issue fix session | $psm fix omc#42 |
feature <proj> <name> | Feature development | $psm feature omc add-webhooks |
list [project] | List active sessions | $psm list |
attach <session> | Attach to session | $psm attach omc:pr-123 |
kill <session> | Kill session | $psm kill omc:pr-123 |
cleanup | Clean merged/closed | $psm cleanup |
status | Current session info | $psm status |
Project References
Supported formats:
- Alias:
omc#123 (requires ~/.psm/projects.json)
- Full:
owner/repo#123
- URL:
https://github.com/owner/repo/pull/123
- Current:
#123 (uses current directory's repo)
Configuration
Project Aliases (~/.psm/projects.json)
{
"aliases": {
"omc": {
"repo": "Yeachan-Heo/oh-my-codex",
"local": "~/Workspace/oh-my-codex",
"default_base": "main"
}
},
"defaults": {
"worktree_root": "~/.psm/worktrees",
"cleanup_after_days": 14
}
}
Directory Structure
~/.psm/
├── projects.json # Project aliases
├── sessions.json # Active session registry
└── worktrees/ # Worktree storage
└── <project>/
└── <type>-<id>/
Session Naming
| Type | Tmux Session | Worktree Dir |
|---|
| PR Review | psm:omc:pr-123 | ~/.psm/worktrees/omc/pr-123 |
| Issue Fix | psm:omc:issue-42 | ~/.psm/worktrees/omc/issue-42 |
| Feature | psm:omc:feat-auth | ~/.psm/worktrees/omc/feat-auth |
Implementation Protocol
When the user invokes a PSM command, follow this protocol:
Parse Arguments
Parse {{ARGUMENTS}} to determine:
- Subcommand: review, fix, feature, list, attach, kill, cleanup, status
- Reference: project#number, URL, or session ID
- Options: --branch, --base, --no-codex, --no-tmux, etc.
Subcommand: review <ref>
Purpose: Create PR review session
Steps:
-
Resolve reference:
cat ~/.psm/projects.json 2>/dev/null || echo '{"aliases":{}}'
-
Fetch PR info:
gh pr view <pr_number> --repo <repo> --json number,title,author,headRefName,baseRefName,body,files,url
-
Ensure local repo exists:
if [[ ! -d "$local_path" ]]; then
git clone "https://github.com/$repo.git" "$local_path"
fi
-
Create worktree:
worktree_path="$HOME/.psm/worktrees/$project_alias/pr-$pr_number"
cd "$local_path"
git fetch origin "pull/$pr_number/head:pr-$pr_number-review"
git worktree add "$worktree_path" "pr-$pr_number-review"
-
Create session metadata:
cat > "$worktree_path/.psm-session.json" << EOF
{
"id": "$project_alias:pr-$pr_number",
"type": "review",
"project": "$project_alias",
"ref": "pr-$pr_number",
"branch": "<head_branch>",
"base": "<base_branch>",
"created_at": "$(date -Iseconds)",
"tmux_session": "psm:$project_alias:pr-$pr_number",
"worktree_path": "$worktree_path",
"source_repo": "$local_path",
"github": {
"pr_number": $pr_number,
"pr_title": "<title>",
"pr_author": "<author>",
"pr_url": "<url>"
},
"state": "active"
}
EOF
-
Update sessions registry:
-
Create tmux session:
tmux new-session -d -s "psm:$project_alias:pr-$pr_number" -c "$worktree_path"
-
Launch Codex (unless --no-codex):
tmux send-keys -t "psm:$project_alias:pr-$pr_number" "codex" Enter
-
Output session info:
Session ready!
ID: omc:pr-123
Worktree: ~/.psm/worktrees/omc/pr-123
Tmux: psm:omc:pr-123
To attach: tmux attach -t psm:omc:pr-123
Subcommand: fix <ref>
Purpose: Create issue fix session
Steps:
-
Resolve reference (same as review)
-
Fetch issue info:
gh issue view <issue_number> --repo <repo> --json number,title,body,labels,url
-
Create feature branch:
cd "$local_path"
git fetch origin main
branch_name="fix/$issue_number-$(echo "$title" | tr ' ' '-' | tr '[:upper:]' '[:lower:]' | head -c 30)"
git checkout -b "$branch_name" origin/main
-
Create worktree:
worktree_path="$HOME/.psm/worktrees/$project_alias/issue-$issue_number"
git worktree add "$worktree_path" "$branch_name"
-
Create session metadata (similar to review, type="fix")
-
Update registry, create tmux, launch codex (same as review)
Subcommand: feature <project> <name>
Purpose: Start feature development
Steps:
-
Resolve project (from alias or path)
-
Create feature branch:
cd "$local_path"
git fetch origin main
branch_name="feature/$feature_name"
git checkout -b "$branch_name" origin/main
-
Create worktree:
worktree_path="$HOME/.psm/worktrees/$project_alias/feat-$feature_name"
git worktree add "$worktree_path" "$branch_name"
-
Create session, tmux, launch codex (same pattern)
Subcommand: list [project]
Purpose: List active sessions
Steps:
-
Read sessions registry:
cat ~/.psm/sessions.json 2>/dev/null || echo '{"sessions":{}}'
-
Check tmux sessions:
tmux list-sessions -F "#{session_name}" 2>/dev/null | grep "^psm:"
-
Check worktrees:
ls -la ~/.psm/worktrees/*/ 2>/dev/null
-
Format output:
Active PSM Sessions:
ID | Type | Status | Worktree
-------------------|---------|----------|---------------------------
omc:pr-123 | review | active | ~/.psm/worktrees/omc/pr-123
omc:issue-42 | fix | detached | ~/.psm/worktrees/omc/issue-42
Subcommand: attach <session>
Purpose: Attach to existing session
Steps:
-
Parse session ID: project:type-number
-
Verify session exists:
tmux has-session -t "psm:$session_id" 2>/dev/null
-
Attach:
tmux attach -t "psm:$session_id"
Subcommand: kill <session>
Purpose: Kill session and cleanup
Steps:
-
Kill tmux session:
tmux kill-session -t "psm:$session_id" 2>/dev/null
-
Remove worktree:
worktree_path=$(jq -r ".sessions[\"$session_id\"].worktree" ~/.psm/sessions.json)
source_repo=$(jq -r ".sessions[\"$session_id\"].source_repo" ~/.psm/sessions.json)
cd "$source_repo"
git worktree remove "$worktree_path" --force
-
Update registry:
Subcommand: cleanup
Purpose: Clean up merged PRs and closed issues
Steps:
-
Read all sessions
-
For each PR session, check if merged:
gh pr view <pr_number> --repo <repo> --json merged,state
-
For each issue session, check if closed:
gh issue view <issue_number> --repo <repo> --json closed,state
-
Clean up merged/closed sessions:
- Kill tmux session
- Remove worktree
- Update registry
-
Report:
Cleanup complete:
Removed: omc:pr-123 (merged)
Removed: omc:issue-42 (closed)
Kept: omc:feat-auth (active)
Subcommand: status
Purpose: Show current session info
Steps:
-
Detect current session from tmux or cwd:
tmux display-message -p "#{session_name}" 2>/dev/null
-
Read session metadata:
cat .psm-session.json 2>/dev/null
-
Show status:
Current Session: omc:pr-123
Type: review
PR: #123 - Add webhook support
Branch: feature/webhooks
Created: 2 hours ago
Error Handling
| Error | Resolution |
|---|
| Worktree exists | Offer: attach, recreate, or abort |
| PR not found | Verify URL/number, check permissions |
| No tmux | Warn and skip session creation |
| No gh CLI | Error with install instructions |
Requirements
git with worktree support (v2.5+)
gh CLI (authenticated)
tmux
jq for JSON parsing
Initialization
On first run, create default config:
mkdir -p ~/.psm/worktrees ~/.psm/logs
if [[ ! -f ~/.psm/projects.json ]]; then
cat > ~/.psm/projects.json << 'EOF'
{
"aliases": {
"omc": {
"repo": "Yeachan-Heo/oh-my-codex",
"local": "~/Workspace/oh-my-codex",
"default_base": "main"
}
},
"defaults": {
"worktree_root": "~/.psm/worktrees",
"cleanup_after_days": 14,
"auto_cleanup_merged": true
}
}
EOF
fi
if [[ ! -f ~/.psm/sessions.json ]]; then
echo '{"version":1,"sessions":{},"stats":{"total_created":0,"total_cleaned":0}}' > ~/.psm/sessions.json
fi