---
name: project-session-manager
description: 面向 issue、PR 和功能开发的 worktree 优先开发环境管理器，可选配 tmux 会话
aliases: [psm]
level: 2
---

# Project Session Manager (PSM) Skill

`psm` 是此规范技能入口点的兼容别名。

> **快速开始（worktree 优先）：** 当你想先创建隔离的 issue/PR/feature worktree，再决定是否添加 tmux/会话编排时，请从 `omc teleport` 开始：
> ```bash
> omc teleport #123          # Create worktree for issue/PR
> omc teleport my-feature    # Create worktree for feature
> omc teleport list          # List worktrees
> ```
> 详细信息请参见下方的 [Teleport Command](#teleport-command)。

使用 git worktrees 和 tmux sessions 搭配 Claude Code 自动化创建隔离的开发环境。支持在多个任务、项目和仓库之间并行工作。

规范 slash 命令：`/oh-my-claudecode:project-session-manager`（别名：`/oh-my-claudecode:psm`）。

## Commands

| Command | Description | Example |
|---------|-------------|---------|
| `review <ref>` | PR 评审会话 | `/psm review omc#123` |
| `fix <ref>` | Issue 修复会话 | `/psm fix omc#42` |
| `feature <proj> <name>` | 功能开发 | `/psm feature omc add-webhooks` |
| `list [project]` | 列出活动会话 | `/psm list` |
| `attach <session>` | 附加到会话 | `/psm attach omc:pr-123` |
| `kill <session>` | 终止会话 | `/psm kill omc:pr-123` |
| `cleanup` | 清理已合并/已关闭项 | `/psm cleanup` |
| `status` | 当前会话信息 | `/psm status` |

## Project References

支持的格式：
- **Alias**：`omc#123`（需要 `~/.psm/projects.json`）
- **Full**：`owner/repo#123`
- **URL**：`https://github.com/owner/repo/pull/123`
- **Current**：`#123`（使用当前目录对应的仓库）

## Configuration

### Project Aliases (`~/.psm/projects.json`)

```json
{
  "aliases": {
    "omc": {
      "repo": "Yeachan-Heo/oh-my-claudecode",
      "local": "~/Workspace/oh-my-claudecode",
      "default_base": "main"
    }
  },
  "defaults": {
    "worktree_root": "~/.psm/worktrees",
    "cleanup_after_days": 14
  }
}
```

## Providers

PSM 支持多个 issue 跟踪提供方：

| Provider | CLI Required | Reference Formats | Commands |
|----------|--------------|-------------------|----------|
| GitHub（默认） | `gh` | `owner/repo#123`、`alias#123`、GitHub URLs | review, fix, feature |
| Jira | `jira` | `PROJ-123`（如果配置了 PROJ）、`alias#123` | fix, feature |

### Jira Configuration

要使用 Jira，请添加一个包含 `jira_project` 和 `provider: "jira"` 的别名：

```json
{
  "aliases": {
    "mywork": {
      "jira_project": "MYPROJ",
      "repo": "mycompany/my-project",
      "local": "~/Workspace/my-project",
      "default_base": "develop",
      "provider": "jira"
    }
  }
}
```

**重要：** `repo` 字段仍然是克隆 git 仓库所必需的。Jira 用于跟踪 issue，但你的实际工作仍发生在 git 仓库中。

对于非 GitHub 仓库，请改用 `clone_url`：
```json
{
  "aliases": {
    "private": {
      "jira_project": "PRIV",
      "clone_url": "git@gitlab.internal:team/repo.git",
      "local": "~/Workspace/repo",
      "provider": "jira"
    }
  }
}
```

### Jira Reference Detection

只有当 `PROJ` 在你的别名中被明确配置为 `jira_project` 时，PSM 才会把 `PROJ-123` 格式识别为 Jira。这可以避免把像 `FIX-123` 这样的分支名误判为 Jira issue。

### Jira Examples

```bash
# Fix a Jira issue (MYPROJ must be configured)
psm fix MYPROJ-123

# Fix using alias (recommended)
psm fix mywork#123

# Feature development (works same as GitHub)
psm feature mywork add-webhooks

# Note: 'psm review' is not supported for Jira (no PR concept)
# Use 'psm fix' for Jira issues
```

### Jira CLI Setup

安装 Jira CLI：
```bash
# macOS
brew install ankitpokhrel/jira-cli/jira-cli

# Linux
# See: https://github.com/ankitpokhrel/jira-cli#installation

# Configure (interactive)
jira init
```

Jira CLI 会独立于 PSM 单独处理认证。

## 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

当用户调用 PSM 命令时，请遵循以下协议：

### Parse Arguments

解析 `{{ARGUMENTS}}` 以确定：
1. **Subcommand**：review、fix、feature、list、attach、kill、cleanup、status
2. **Reference**：project#number、URL 或 session ID
3. **Options**：--branch、--base、--no-claude、--no-tmux 等

### Subcommand: `review <ref>`

**Purpose**：创建 PR 评审会话

**Steps**：

1. **Resolve reference**：
   ```bash
   # Read project aliases
   cat ~/.psm/projects.json 2>/dev/null || echo '{"aliases":{}}'

   # Parse ref format: alias#num, owner/repo#num, or URL
   # Extract: project_alias, repo (owner/repo), pr_number, local_path
   ```

2. **Fetch PR info**：
   ```bash
   gh pr view <pr_number> --repo <repo> --json number,title,author,headRefName,baseRefName,body,files,url
   ```

3. **Ensure local repo exists**：
   ```bash
   # If local path doesn't exist, clone
   if [[ ! -d "$local_path" ]]; then
     git clone "https://github.com/$repo.git" "$local_path"
   fi
   ```

4. **Create worktree**：
   ```bash
   worktree_path="$HOME/.psm/worktrees/$project_alias/pr-$pr_number"

   # Fetch PR branch
   cd "$local_path"
   git fetch origin "pull/$pr_number/head:pr-$pr_number-review"

   # Create worktree
   git worktree add "$worktree_path" "pr-$pr_number-review"
   ```

5. **Create session metadata**：
   ```bash
   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
   ```

6. **Update sessions registry**：
   ```bash
   # Add to ~/.psm/sessions.json
   ```

7. **Create tmux session**：
   ```bash
   tmux new-session -d -s "psm:$project_alias:pr-$pr_number" -c "$worktree_path"
   ```

8. **Launch Claude Code**（除非使用了 --no-claude）：
   ```bash
   tmux send-keys -t "psm:$project_alias:pr-$pr_number" "claude" Enter
   ```

9. **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**：创建 issue 修复会话

**Steps**：

1. **Resolve reference**（与 review 相同）

2. **Fetch issue info**：
   ```bash
   gh issue view <issue_number> --repo <repo> --json number,title,body,labels,url
   ```

3. **Create feature branch**：
   ```bash
   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
   ```

4. **Create worktree**：
   ```bash
   worktree_path="$HOME/.psm/worktrees/$project_alias/issue-$issue_number"
   git worktree add "$worktree_path" "$branch_name"
   ```

5. **Create session metadata**（与 review 类似，type="fix"）

6. **Update registry, create tmux, launch claude**（与 review 相同）

### Subcommand: `feature <project> <name>`

**Purpose**：开始功能开发

**Steps**：

1. **Resolve project**（从别名或路径）

2. **Create feature branch**：
   ```bash
   cd "$local_path"
   git fetch origin main
   branch_name="feature/$feature_name"
   git checkout -b "$branch_name" origin/main
   ```

3. **Create worktree**：
   ```bash
   worktree_path="$HOME/.psm/worktrees/$project_alias/feat-$feature_name"
   git worktree add "$worktree_path" "$branch_name"
   ```

4. **Create session, tmux, launch claude**（相同模式）

### Subcommand: `list [project]`

**Purpose**：列出活动会话

**Steps**：

1. **Read sessions registry**：
   ```bash
   cat ~/.psm/sessions.json 2>/dev/null || echo '{"sessions":{}}'
   ```

2. **Check tmux sessions**：
   ```bash
   tmux list-sessions -F "#{session_name}" 2>/dev/null | grep "^psm:"
   ```

3. **Check worktrees**：
   ```bash
   ls -la ~/.psm/worktrees/*/ 2>/dev/null
   ```

4. **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**：附加到现有会话

**Steps**：

1. **Parse session ID**：`project:type-number`

2. **Verify session exists**：
   ```bash
   tmux has-session -t "psm:$session_id" 2>/dev/null
   ```

3. **Attach**：
   ```bash
   tmux attach -t "psm:$session_id"
   ```

### Subcommand: `kill <session>`

**Purpose**：终止会话并清理

**Steps**：

1. **Kill tmux session**：
   ```bash
   tmux kill-session -t "psm:$session_id" 2>/dev/null
   ```

2. **Remove worktree**：
   ```bash
   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
   ```

3. **Update registry**：
   ```bash
   # Remove from sessions.json
   ```

### Subcommand: `cleanup`

**Purpose**：清理已合并的 PR 和已关闭的 issue

**Steps**：

1. **Read all sessions**

2. **For each PR session, check if merged**：
   ```bash
   gh pr view <pr_number> --repo <repo> --json merged,state
   ```

3. **For each issue session, check if closed**：
   ```bash
   gh issue view <issue_number> --repo <repo> --json closed,state
   ```

4. **Clean up merged/closed sessions**：
   - 终止 tmux session
   - 移除 worktree
   - 更新 registry

5. **Report**：
   ```
   Cleanup complete:
     Removed: omc:pr-123 (merged)
     Removed: omc:issue-42 (closed)
     Kept: omc:feat-auth (active)
   ```

### Subcommand: `status`

**Purpose**：显示当前会话信息

**Steps**：

1. **Detect current session**：从 tmux 或 cwd：
   ```bash
   tmux display-message -p "#{session_name}" 2>/dev/null
   # or check if cwd is inside a worktree
   ```

2. **Read session metadata**：
   ```bash
   cat .psm-session.json 2>/dev/null
   ```

3. **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 | 提供选项：attach、recreate 或 abort |
| PR not found | 验证 URL/编号，检查权限 |
| No tmux | 警告并跳过会话创建 |
| No gh CLI | 返回错误并提供安装说明 |

## Teleport Command

`omc teleport` 命令提供了一个比完整 PSM 会话更轻量的替代方案。它只创建 git worktrees，而不管理 tmux 会话，适合快速、隔离的开发工作。

### Usage

```bash
# Create worktree for an issue or PR
omc teleport #123
omc teleport owner/repo#123
omc teleport https://github.com/owner/repo/issues/42

# Create worktree for a feature
omc teleport my-feature

# List existing worktrees
omc teleport list

# Remove a worktree
omc teleport remove issue/my-repo-123
omc teleport remove --force feat/my-repo-my-feature
```

### Options

| Flag | Description | Default |
|------|-------------|---------|
| `--worktree` | 创建 worktree（默认值，为兼容性保留） | `true` |
| `--path <path>` | 自定义 worktree 根目录 | `~/Workspace/omc-worktrees/` |
| `--base <branch>` | 用于创建的基础分支 | `main` |
| `--json` | 以 JSON 输出 | `false` |

### Worktree Layout

```
~/Workspace/omc-worktrees/
├── issue/
│   └── my-repo-123/        # Issue worktrees
├── pr/
│   └── my-repo-456/        # PR review worktrees
└── feat/
    └── my-repo-my-feature/ # Feature worktrees
```

### PSM vs Teleport

| Feature | PSM | Teleport |
|---------|-----|----------|
| Git worktree | Yes | Yes |
| Tmux session | Yes | No |
| Claude Code launch | Yes | No |
| Session registry | Yes | No |
| Auto-cleanup | Yes | No |
| Project aliases | Yes | No (uses current repo) |

在需要完整托管会话时使用 **PSM**。在只需快速创建 worktree 时使用 **teleport**。

---

## Requirements

必需：
- `git` - 版本控制（支持 worktree，版本需为 v2.5+）
- `jq` - JSON 解析
- `tmux` - 会话管理（可选，但推荐）

可选（按 provider 区分）：
- `gh` - GitHub CLI（用于 GitHub 工作流）
- `jira` - Jira CLI（用于 Jira 工作流）

## Initialization

首次运行时，创建默认配置：

```bash
mkdir -p ~/.psm/worktrees ~/.psm/logs

# Create default projects.json if not exists
if [[ ! -f ~/.psm/projects.json ]]; then
  cat > ~/.psm/projects.json << 'EOF'
{
  "aliases": {
    "omc": {
      "repo": "Yeachan-Heo/oh-my-claudecode",
      "local": "~/Workspace/oh-my-claudecode",
      "default_base": "main"
    }
  },
  "defaults": {
    "worktree_root": "~/.psm/worktrees",
    "cleanup_after_days": 14,
    "auto_cleanup_merged": true
  }
}
EOF
fi

# Create sessions.json if not exists
if [[ ! -f ~/.psm/sessions.json ]]; then
  echo '{"version":1,"sessions":{},"stats":{"total_created":0,"total_cleaned":0}}' > ~/.psm/sessions.json
fi
```
