关于 paseokit
paseokit 是用于协调 Git worktree 与 Paseo 工作区注册表的技能。它将登记与清理分开,清理前预览变更,并把 worktree 的创建和移除交由 gitkit 处理。
主要功能
- 01查看工作区注册表差异
- 02通过 sync 登记缺失 worktree
- 03清理重复及已完成条目
- 04调整 Paseo 的 worktree 根目录
- 05预览并确认清理操作
适用场景
- 01将已有 worktree 登记到 Paseo
- 02查找缺失或重复的工作区记录
- 03合并 PR 后移除已完成的 worktree
- 04检查 Paseo 应将新 worktree 放在哪里
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mimukit/ skills --skill paseokit安装后在 Claude Code 中输入/paseokit确认已加载。
附带文件modes/align.mdmodes/clean.md
详细介绍
paseokit
Paseo 会为每个检出显示一个工作区,可以是主仓库,也可以是其下的一个 git worktree,并在每个工作区中挂接 Agent。Worktree 本身由原生 git worktree 创建:可以遵循 gitkit 的约定,使用 issuekit 的 start,也可以由你亲自操作。
Paseo 不会自行注册任何内容。 git worktree add 创建的 worktree 在经过某种方式注册之前,对 Paseo 不可见。没有可启用的发现设置,因此实际工作不会自行出现在侧边栏中。
不过,Paseo 确实会自行修剪一项内容,具体如版本衔接处的目录修剪所述:它会归档目录已不存在的所有活动行。除此之外,它不会归档任何内容:它从不合并重复行,从不判断工作是否已合并,也从不触碰目录仍存在的行。因此,剩余的不同步情况包括从未显示的工作、重复项,以及仍留在磁盘上的已完成 worktree。
paseokit 只负责这项对账,并按方向拆分:sync 添加缺失项,clean 移除已完成项——包括重复行,以及工作已合并的 worktree。每种操作都仅针对你运行它的项目,除非你要求处理整台机器;无论哪种操作,运行两次后第二次都不会造成任何变化。
这种按需设计是刻意为之。只有运行 sync 时,worktree 才会出现在 Paseo 中,而不是在创建时出现。这是经过权衡的选择:不使用 git hooks、调度器或后台进程,也不会向任何仓库写入内容。
paseokit 不会越过的界限
Git 管理 worktree;Paseo 管理行。 paseokit 从不运行 paseo workspace create --isolation worktree 来开展实际工作,从不虚构路径,也从不让 Paseo 创建分支。创建和移除 worktree 都使用遵循 gitkit 约定的原生 git worktree,因此没有安装 Paseo 的机器也会运行完全相同的命令。
paseokit 在更高一层操作,只处理 Paseo 独自掌握的信息:注册表行,也就是此路径在此项目下存在一个工作区,且具有这个标题。
有两点值得明确说明:
paseo workspace archive不仅操作注册表。 它会归档工作区中的所有 Agent,结束其中的所有终端,并且在 Paseo 认定该目录归自己所有、且没有其他活动行指向它时,删除工作区对应的 worktree 目录。只有行可以恢复;目录不行。排入任何归档操作之前,请先阅读归档调用会删除目录。- 移除 worktree 仍然是 gitkit 的职责。 paseokit 通过 gitkit 执行拆除,绝不会用归档代替它,因为会删除内容的归档,就是一次从未预览过的删除。
clean是唯一会触及磁盘的模式。 它判断哪些 worktree 已完成,并执行拆除;但在安装了 gitkit 时,它不会自行运行git worktree remove,也绝不虚构路径或分支规则。判断由 paseokit 做出;移除仍由 gitkit 执行。
paseokit 绝不会触碰跟踪系统。 它会读取 issue 和 pull request 来生成标题并判断结果;但绝不会关闭 issue、移动标签或编辑 pull request。如果 pull request 已合并但对应的 issue 仍未关闭,这属于跟踪系统不同步,paseokit 会指出这一点,并转交给 issuekit 的 close。
触发时机
list。“paseo 认为我的工作树有哪些?”“为什么侧边栏里没有我的工作树?”“显示一下差异。”只读。sync。“将我的工作树同步到 paseo。”“注册我的工作树。”默认仅作用于当前项目;“全部同步”“同步所有内容”或“我的所有项目”会将范围扩大到整台机器——参见范围。clean。“清理 PR 已合并的工作树。”“删除已合并的工作树及其会话。”“清理侧边栏里的无效条目。”“我的机器上全是已经合并的工作。”这是唯一会归档条目或从磁盘删除内容的模式;它会先列出所有计划归档和删除的内容,然后将归档作为一组确认,并对每项删除分别确认。align。“paseo 应该把新工作树放在哪里?”“让 paseo 使用我的工作树根目录。”
**如果无法确定模式,先从 list 开始。**它是只读的,并会指出 sync 会处理哪些条目,所以作为第一步总不会错。
sync 与 clean。sync 只会添加内容:它会注册、重命名标题并恢复条目,但绝不会归档条目、合并重复项或触碰磁盘。所有移除操作,从归档无效条目到删除已合并的工作树,都属于 clean。clean 会在一个列表中预览这两类操作,并在触碰任一类内容前征求确认;对于磁盘操作,它还会先证明拉取请求已合并,工作树才会出现在列表中,并遵循 gitkit 的移除规则:每个工作树都要单独确认。
**不属于此技能:**创建工作树(gitkit)、关闭 issue 并在合并后拆除内容(issuekit close),或驱动 Agent,因为 paseo run、attach、send、logs 和计划功能都直接属于 paseo CLI。paseokit 负责注册表维护,而不是 Agent 操作。
预检(所有模式)
paseo status # CLI installed? daemon running and reachable?
- 未安装
paseo→ 这台机器没有 Paseo,因此无需协调。请如实说明这一点,然后停止。不要改用其他方式:没有 Paseo,工作树也已处于正常状态,工作流中的其他内容也不依赖此技能。 - 守护进程未运行或无法访问 → 指出
paseo start并停止。未经请求,不要在他人的机器上启动守护进程。 - 缺少
gh或未通过身份验证 → 标题会退化为分支名称,跟踪器列会显示“未知”。list、sync和align的其他功能不受影响。clean的磁盘操作是例外,会停止执行,因为它的前提是已证明合并,而只有跟踪器能证明这一点;不过注册表清理仍会在单独预览并确认后运行。 paseo标志或子命令被拒绝 → CLI 更新很快。在断定某项操作不受支持之前,先检查paseo <command> --help,并对照下面的两个版本号,再判断是否是 CLI 的问题。目标是实现约定的结果,即注册条目、归档条目、设置标题;具体标志的写法并不重要。
所有依赖版本的事实都列在版本差异中。在执行写入操作前,请根据更新版本重新核对该列表。
分别读取两个版本号。paseo status 会将 CLI 和 Daemon Version 分别列出,它们可能不一致:CLI 会在下次安装时升级,而守护进程会继续运行启动时所用的代码,直到执行 paseo restart。CLI 会显示自身版本支持的所有标志,因此某个标志可能在本地解析成功,却仍被守护进程拒绝。当两个版本号不同时,应优先将写入操作被拒绝视为版本不匹配,并说明这一点。**不要运行 paseo restart 来消除版本差异。**重启会终止所有正在运行的 Agent,包括正在读取本文的 Agent。
版本界限
已针对 Paseo CLI 0.8.0 和守护进程 0.8.0 验证。本技能中所有依赖 Paseo 版本的事实都列在此处,其余部分按名称引用这些条目,不注明自身版本。守护进程报告了更新版本时,请重新检查每个条目,再信任任何写入操作,并在此处统一更新。
- 目录清理。 守护进程启动时以及此后每五分钟会执行一次协调。如果某个活跃条目的目录已不存在,就将其归档,原因设为
directory_missing,除此之外不做其他操作。此功能于 0.7 引入。 - 所有权标记。
isPaseoOwnedWorktree使用与归档删除操作相同的<hash>/<slug>路径测试,并且每次协调都会刷新该标记。0.7 之前采用较宽松的检查来设置此标记,因此它可能与删除操作的判断不一致。 project组。create、ls、rename和delete均已实现。对于其他动词,安全探测方式是使用守护进程会接受并执行、但不会匹配到任何内容的命令,例如使用一个不存在的格式正确的 id。- 无法取消归档。
workspace子命令只有create、ls、rename和archive,没有其他子命令。 daemon.autoArchiveAfterMerge的限制。 该功能仅在拉取请求已合并、工作区干净、没有任何提交领先于 origin,且工作树由 Paseo 创建时才会执行。这些限制于 0.7 引入。
Paseo 对工作区的了解
有两个数据面,两者的差异至关重要。
CLI 列表是精简投影。 paseo workspace ls --json 只返回 workspaceId、project(显示名称,而非 id)、name、isolation 和 cwd。它只列出活跃工作区。这些信息足以回答一个问题:是否有任何活跃条目指向此路径;除此之外别无用途。
paseo project ls --json 会解析项目 id。 它会返回每个活跃项目的 projectId、name、kind 和 path,因此现在可通过 CLI 获取 --project 要求的 prj_… id。按 path 匹配。优先使用此命令;只有在命令不存在或守护进程拒绝执行时,才回退到状态文件。
状态文件包含两个列表都未公开的信息。 这些文件位于 ~/.paseo/projects/:
| 文件 | 独有信息 | 用途 |
|---|---|---|
workspaces.json | branch、title、kind、projectId、createdAt、archivedAt、isPaseoOwnedWorktree、worktreeRoot、mainRepoRoot | 墓碑记录、重复项排序、重命名安全检查、删除预估 |
projects.json | 每个项目的 projectKey 和 archivedAt | 检测孤立项目,以及作为 project ls 的回退方案 |
主检出中的 kind 为 local_checkout,工作树中的 kind 为 worktree。
这是文档记录的数据界限,并非稳定 API。 workspace ls 仍然不包含 branch、title、createdAt 和任何已归档条目,因此读取 workspaces.json 仍不可避免,并非捷径。将这两个文件都视为只读:paseokit 会解析它们,并通过 CLI 执行写入,绝不直接写入这些文件。
如果任一文件缺失、无法读取或结构异常,所有写入模式都必须降级为只读,并说明具体是哪个文件以及原因。绝不猜测 id。
工作区只包含标题和固定标记,不包含其他信息;没有关联的问题,也没有状态字段。因此,这里没有与 link 式信息增强对应的机制;标题就是全部信息。
archive 调用会删除目录
paseo workspace archive <workspace-id> 会执行三个步骤,只有第一步是修改注册表:
- 它会归档工作区拥有的所有 Agent,无论是运行中的还是已存储的,并终止其中的所有终端。它不会征求同意,也不会因为有 Agent 正在运行而拒绝执行。
- 它会归档工作区记录。这一步可以撤销。
- 接着,如果没有其他活动行指向该目录,且该目录通过下方的所有权测试,它就会尝试删除后端目录。删除操作会运行
git worktree remove --force,然后移除该目录。Git 不会还原其中任何内容。
删除操作会进行路径测试,路径结构就是全部测试条件。 守护进程只接受 <worktrees.root>/<hash>/<slug> 形式的目录,其中 <hash> 是主检出绝对路径的短 base-36 摘要。gitkit 的约定是 $WORKTREE_ROOT/<repo>/<branch>,其中保存的是仓库名称,而守护进程要求的是哈希,因此 gitkit 工作树无法通过测试,删除操作会抛出 Refusing to delete non-Paseo worktree。只有 Paseo 自行创建的工作树才能通过。 守护进程会捕获该异常,将其记录为警告,并报告归档成功,因此在 CLI 中看不到删除被拒绝的提示。
根据版本衔接部分的所有权标志,isPaseoOwnedWorktree 可以预测是否会删除:workspaces.json 中为 true 表示会删除磁盘目录,为 false 表示只归档注册表。不过,在排队归档前仍要确认路径结构,因为存储的值是否准确取决于最近一次检查:父目录名称是仓库名称的目录属于 Git 工作树;父目录名称是不透明哈希的目录则属于 Paseo。
以下三条规则都必须遵守:
- 只要工作树位于哈希目录下,就将归档视为磁盘删除。 这是守护进程唯一会删除的结构。预览时应将其视为删除,而不是注册表修改。
- 工作树存在未提交更改也无法保护它。 守护进程会向
git worktree remove传入--force,因此,Paseo 创建的工作树中未提交的工作会随目录一起消失。这就是为什么clean会自行确认工作树干净,而不是指望该调用拒绝执行。 - 运行中的 Agent 不会阻止调用。 归档操作会停止并归档该 Agent,还会终止工作区中的所有终端。因此,
busy检查是 paseokit 自身的防护措施,并非 CLI 提供的安全网。
工作区拆除命令会在删除前运行,并以目录所在路径为目标。对于配置了拆除脚本的工作区,每次归档 Paseo 所有的工作树时都会运行该脚本。如果拆除命令失败,目录删除会被取消,而记录会保持归档状态,此时工作区与其目录就会不一致。
注册表还有一个问题
workspace create 不是幂等的。 对同一路径调用两次完全相同的命令,会悄无声息地生成两条 cwd 相同的记录。因此,注册前的每项存在性检查都至关重要,而非仅仅是优化;检查时还必须考虑已归档的记录,否则下方的墓碑规则会悄无声息地失效。
模式:list
只读。不做任何更改,不提出任何问题;状态不明确时,应首先使用此模式。
合并三个来源,并按绝对路径进行匹配,这是 git 和 Paseo 共同记录的唯一键:
paseo project ls --json # live projects, each with a projectId and a path
git -C "$REPO" worktree list --porcelain # per live project
paseo workspace ls --json # active rows
paseo ls -g --json # agents across every directory, each with a cwd and a status
在判定任何结果之前,先应用两个筛选条件:
- HEAD 不可解析为符号引用时,不显示该行。 porcelain 记录包含
branch refs/heads/<name>或detached;detached记录永远不会注册。这与在工作树中运行git symbolic-ref -q HEAD得到的结果相同,也正是防止 debugkit 的 bisect 临时目录出现在侧边栏中的机制。 - Agent 的
cwd值会以波浪号缩写形式返回(~/projects/skills)。请先展开路径再进行比较,否则所有busy检查都会静默地返回 false。
然后为每一行给出判定结果:
| 判定结果 | 含义 | 修复方式 |
|---|---|---|
busy | 非空闲 Agent 的 cwd 位于此工作区内 | 保留 |
registered | 工作树存在,且恰好有一行活动记录指向它 | 无需处理 |
unregistered | 工作树存在,但没有任何记录指向它 | sync |
orphaned | 有一行活动记录指向一个已不存在的路径 | 等待;守护进程会在五分钟内将其归档 |
duplicate | 两行或更多活动记录共用一个 cwd | clean |
tombstoned | 工作树存在,但其唯一记录已归档 | sync,需确认 |
unknown repo | $WORKTREE_ROOT 下的工作树所属仓库是 Paseo 从未见过的 | sync,需确认 |
stray project | 某项目的 rootPath 是工作树,而非主检出目录 | 报告此情况;确认后,运行 paseo project delete 将其移除 |
reapable | 拉取请求已合并、议题已关闭、工作树干净 | clean |
只要存在 busy 行,就将其排在最前面。 对这些行采取操作会中断正在进行的工作。
orphaned 行是时序造成的临时状态,详见目录清理。守护进程会在自己的处理周期中将其归档,因此请报告此状态并说明何时会消失。只有用户要求立即清除时,才将其排入归档队列。
stray project 有明确的特征:它的 projectKey 与某个真实项目的 projectKey 相同,而它的 rootPath 位于 $WORKTREE_ROOT 下。这是未使用 --project 进行注册所产生的结果;由于其下方的记录可能已归档,因此它不会显示在 workspace ls 中。
交接
在本技能中撰写的所有交接内容都使用程序性语体:每句话只给出一条指令,使用主动语态和现在时,不使用比喻。
变更内容。 没有变更。明确说明这一点。
所在位置。 给出一个表格,列出各判定结果的数量。
下一步。 任何行的判定结果为 unregistered 或 tombstoned 时,优先选择 sync。任何行的判定结果为 duplicate 或 reapable 时,优先选择 clean。两种情况同时出现时,先选择 clean,这样 sync 就会将记录注册到一个已清除失效记录的注册表中。如果所有行的判定结果都是 registered,请明确说明侧边栏已与磁盘内容一致。
模式:sync
此模式用于添加,并且从设计上可安全地重复运行。它会注册、重命名和恢复记录;绝不会归档任何记录,也绝不会触碰目录或分支。任何形式的移除,包括归档失效记录,都应交由 clean 处理。
范围
sync 有两种范围,请求中的措辞决定使用哪一种:
- 默认使用项目范围。 使用
git rev-parse --path-format=absolute --git-common-dir从当前目录解析主检出,然后仅对该项目执行操作:磁盘上的工作树,以及workspaces.json中projectId与其匹配的注册表行。其他所有项目的行和工作树都保持不变,也不报告。 sync all是整台机器范围。 用户会通过“sync all”“sync everything”或“all my projects”提出此请求。它涵盖paseo project ls --json返回的所有项目;由于下面的未知仓库遍历本质上是对整台机器进行扫描,因此只有此范围会执行该遍历。
如果当前目录不在 Git 仓库中,项目范围就没有对应对象。 请说明这一点,并指出 sync all 可用于扫描整台机器。不要擅自扩大用户未要求的范围。
先运行 list 的联接操作,并按所选范围筛选,因为 sync 只会对这些判定结果执行操作。
直接执行,无需确认
以下所有操作都已证明不会造成破坏,因此无需询问确认。
注册每个 unregistered 工作树:
paseo workspace create --isolation local --path "$WT" \
--project "$PROJECT_ID" --title "$TITLE" --json
即使目标是工作树,--isolation local 仍是正确的设置:它会指示 Paseo 接管 $WT 处的检出,而不是新建一个。Paseo 会自行检查 Git,并记录 kind: "worktree"、分支和 mainRepoRoot。
必须指定 --project。 如果不指定,Paseo 会在工作树路径下创建一个重复的项目,也就是上文提到的 stray project。通过运行 paseo project ls --json 并匹配主检出的 path 来解析 $PROJECT_ID;如果找不到,则在 projects.json 中查找 rootPath 匹配且 archivedAt 为 null 的项目。如果无法解析 id,则跳过注册并报告原因。 切勿为了绕过缺失的 id 而在未指定 --project 的情况下注册。
报告每个 duplicate 集合,并将其交由 clean 处理。将每个 orphaned 行报告为可自我修复。sync 会同时指出这两类情况,以便清楚显示偏差;它不会归档任何内容。
重命名标题由 Paseo 自动生成而非由人工设置的行:
paseo workspace rename "$WORKSPACE_ID" "$TITLE"
标题格式为 #<n> · <issue title>;从 issue-<n>-<slug> 分支中解析 <n>,并通过 gh issue view "$N" --json title 读取标题。如果 gh 无法使用,或分支名称不含 issue 编号,则退回使用分支名称。
仅当行的 title 为 null 或与分支名称完全一致时,才重命名该行。 其他任何标题都视为由人工设置,应保持不变,并报告为不一致,而不是覆盖。
跳过所有 busy 项,并在报告中注明 Agent 的短 ID。切勿重命名含有运行中 Agent 的工作区。
各项都需单独确认一次
这两项都会超出用户请求的范围,因此都要停下来询问。
未知仓库(仅限 sync all,参见范围)。遍历 $WORKTREE_ROOT/*,通过 git -C "$CANDIDATE" rev-parse --git-common-dir 将每个候选项解析到其主检出,并收集 Paseo 从未见过的仓库。列出这些仓库,然后在一次确认后先创建项目:
paseo project create "$REPO" --json
该调用会直接返回新的 prj_… ID。使用该 ID 注册仓库的主检出,然后注册其工作树;每项都通过 workspace create --isolation local --project "$PROJECT_ID" 完成。
Paseo 自己的工作树无需特殊处理。它们已经有对应记录,其 --git-common-dir 会解析到 Paseo 已知的仓库,因此不会进入未知仓库类别,也无需猜测哈希目录模式。
墓碑记录。 归档记录会阻止重新注册:有人刻意归档了该工作区,若在下一次运行时重新添加,就会撤销他们刚完成的整理。列出这些墓碑工作树,在一次确认后恢复它们;否则保持原样。
没有 paseo workspace unarchive,参见版本分界。“恢复”墓碑记录意味着为同一路径创建一条新记录,因此归档记录仍保留在 workspaces.json 中,恢复后的工作区会获得新的 wks_… ID。执行时要说明这一点;不要声称记录已复活。
移交
发生了什么变化。 说明你执行的范围:当前项目或整台机器。分别报告注册、恢复和重命名的数量。逐项说明跳过的内容及原因。将 busy 跳过项放在最前面,因为它们涉及正在进行的工作。
变更落在哪里。 只涉及 Paseo 的注册表,且仅涉及新增或重命名的记录。明确说明没有归档任何记录,也没有更改任何目录、分支或 git 注册,并说明侧边栏会在几秒内反映这些新记录。
后续操作。 按以下优先级处理:
- 存在任何
busy项 → 指明路径和 Agent。告知用户等该 Agent 完成后再次运行sync。 - 存在任何
stray project→ 指明项目,并说明修复方式是paseo project delete "$PROJECT_ID"。此处不要运行该命令。 该命令会删除项目及其下的每个工作区,因此应通过clean的预览和确认来执行,而不是放在sync可直接执行的环节中。 - 存在任何
duplicate或reapable项 → 引导至clean,由其在一次操作中合并重复记录,并通过 gitkit 拆除合并后的工作树。 - 追踪器状态不一致 → 引导使用 issuekit 执行
close <n>,否则使用gh issue close <n>。 - 没有剩余问题 → 说明注册表与磁盘一致,然后停止。这不值得反复执行。
模式
clean 和 align 的模式正文分别存放在 modes/ 下的一个文件中。根据触发条件选择模式,读取对应文件并遵循其中的说明。本文件中的内容适用于所有模式,不会在模式文件中重复说明。list 和 sync 保留在此处,因为 list 中的联结方式和判定结果构成了 sync 与 clean 操作时使用的术语体系。
- 模式
clean→ 阅读 modes/clean.md,然后遵循其中的说明。 - 模式
align→ 阅读 modes/align.md,然后遵循其中的说明。
备注
- paseokit 仅在本机运行,且始终是可选的。 如果机器上没有 Paseo,就什么也不做;工作流中的其他任何部分都不得依赖它。gitkit、issuekit 等绝不会调用它,否则在没有该工具的机器上都会出错。它是你可以运行的泵,而不是链条中的一环。
orcakit是同级工具,不是前置工具。 它会将相同的工作树同步到 Orca;Orca 的模型恰恰相反:Orca 会自行发现工作树,并且对它们一无所知,因此 orcakit 负责补充信息和清理,而 paseokit 负责注册和回收。两者都仅在本机运行,且都是可选的,彼此绝不会调用对方。- 工作树信息由 gitkit 管理。 路径约定
$WORKTREE_ROOT/<repo>/<branch>和issue-<n>-<slug>分支语法仅在此处作为没有 gitkit 的机器上的声明式可移植性回退方案出现。分支命名、基础引用解析和拆除规则都由 gitkit 管理;本文件中任何其他关于 gitkit 的信息副本都是错误。 - 跟踪器信息由 issuekit 管理。 paseokit 会读取 issue 和拉取请求的状态来生成标题和判断结果,但不会写入任何内容。
- 安全的操作直接执行;扩大范围和破坏性操作则需要询问。
list绝不询问。sync会不经提示地执行新增操作,只会在两种注册用户未指定内容的操作前停止。clean会在执行任何操作前列出所有计划归档和删除的内容。它会针对归档询问一次,因为用户应该看到哪些内容会从侧边栏中消失;并且会针对每次删除分别询问,因为 gitkit 的移除规则会将每个工作树视为独立决定,而被移除的工作树是这里唯一无法通过 git 恢复的东西。 - 不要因为某个
paseo命令的名字听起来安全,就认为它安全。archive会删除目录,而project delete会连同项目下的所有工作区一起删除。查看paseo <command> --help,了解命令会影响哪些内容;并且应将单行说明视为概要,而非保证。 - 绝不要写入
~/.paseo/projects/*.json。 paseokit 会读取这些文件中未通过列表展示的字段,并且只会通过paseo写入。手动编辑状态文件后,必须重启守护进程才能生效,而重启会终止所有正在运行的 Agent。 - 无法使用 shell? 那就无法访问
paseoCLI、git或gh。根据用户提供的信息进行判断,并以代码块形式打印确切的命令供用户运行;绝不要声称已注册或归档你无法实际执行的工作区。