mcpField
S
swain-session

swain-session

github.com/cristoslcAgent 工作流2108 次安装25 周前更新
代码仓库

关于 swain-session

swain-session 是面向 Agent 工作环境的会话管理 Skill,通过 AGENTS.md 自动调用,管理会话身份、偏好和上下文延续。它涵盖会话启动、恢复、决策记录与关闭,并提供预检和状态脚本。

主要功能

  1. 01会话启动时恢复上下文
  2. 02读取并应用用户偏好
  3. 03记录会话决策与进度
  4. 04管理会话关闭和恢复
  5. 05提供预检及问候脚本

适用场景

  1. 01开始工作时恢复上次会话
  2. 02跨会话保留上下文书签
  3. 03结束会话并生成进度记录

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cristoslc/swain --skill swain-session

安装后在 Claude Code 中输入/swain-session确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
agent-summary-template.md
bookmark-protocol.md
session-check-preamble.md
status-format.md
scripts/
swain-bookmark.sh
swain-focus.sh
swain-preflight-timing.sh
swain-progress-log.sh
swain-session-archive.sh
swain-session-bootstrap.sh
swain-session-check.sh
swain-session-digest.sh
swain-session-greeting.sh
swain-session-preflight.sh
swain-session-state.sh
swain-startup-timing.sh
swain-status.sh
swain-tab-name.sh
swain-worktree-name.sh
test-session-greeting.sh
tests/
test-bootstrap.sh
test-progress-log.sh
test-session-close-integration.sh
test-session-digest.sh
test-tab-name.sh

详细介绍

会话

管理 Agent 会话之间的会话身份、偏好设置和上下文连续性。此技能与 Agent 无关——它依赖 AGENTS.md 自动调用。

自动运行行为

此技能会在会话开始时自动调用(参见 AGENTS.md)。自动调用时:

  1. 恢复标签页名称 — 运行标签页命名脚本
  2. 加载偏好设置 — 读取 session.json 并应用已存储的偏好设置
  3. 显示上下文书签 — 如果上一个会话留下了上下文备注,则显示该备注

手动调用时,用户可以更改偏好设置或为上下文添加书签。

会话目的文本

当操作者使用自由文本启动时(例如,swain new bug about timestamps),启动器会导出 SWAIN_PURPOSE,并且对于接受初始提示词的运行时,还会以内联方式传入 /swain-session Session purpose: new bug about timestamps。

启动器负责选择保存该书签的工作副本:

  • 如果操作者从主工作副本启动,启动器会先打开一个新的工作树,然后才传入会话目的。
  • 如果操作者从已有书签的关联工作树中启动,启动器应引导其恢复/完成该工作树,或在重新使用目的文本之前打开另一个工作树。

问候脚本(swain-session-greeting.sh)会读取 $SWAIN_PURPOSE,并以确定性方式写入书签(SPEC-297)。问候 JSON 会在 purpose 字段中提供捕获的文本。

当问候 JSON 的 purpose 字段不为 null 时:

  • 向操作者显示:**Session purpose:** <text>。

不要重新解析初始提示词,也不要自行调用 swain-bookmark.sh——问候脚本已完成这两项操作。内联提示词文本仅用于显示上下文;环境变量才是事实来源。

预检

执行任何步骤之前,先运行预检脚本,一次性收集所有会话状态。此脚本取代旧的子进程调用链(greeting → bootstrap → tab-name),是只读脚本。

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
PREFLIGHT_SCRIPT="$(find "$REPO_ROOT" -path '*/swain-session/scripts/swain-session-preflight.sh' -print -quit 2>/dev/null)"
PREFLIGHT_JSON=$( bash "$PREFLIGHT_SCRIPT" --repo-root "$REPO_ROOT" 2>/dev/null )
echo "$PREFLIGHT_JSON"

将 PREFLIGHT_JSON 保存下来,以供以下所有步骤使用。每项决策都要引用此 JSON 中的字段——除非要执行变更,否则不要运行其他检查命令。

步骤 1 — 快速问候(SPEC-194)

运行问候脚本。它会在内部调用预检,并执行轻量级变更(设置标签页名称、清理锁、创建 .agents 目录)。它不会调用 specgraph、GitHub API 或完整状态仪表板。

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-session-greeting.sh" --json

问候脚本会输出结构化 JSON:

{
  "greeting": true,
  "branch": "trunk",
  "dirty": false,
  "isolated": false,
  "bookmark": "Left off implementing the bootstrap script",
  "focus": "VISION-001",
  "tab": "project @ branch",
  "warnings": []
}

预检 JSON 还会在 prev_session 下包含上一个会话的状态,因此无需单独调用 swain-session-state.sh resume:

{
  "prev_session": {
    "exists": true,
    "status": "closed",
    "session_id": "session-20260404-215204-9576",
    "focus_lane": "INITIATIVE-002",
    "phase": "closed",
    "start_time": "2026-04-05T01:52:04Z",
    "end_time": "2026-04-06T04:10:09Z",
    "decisions_made": 0,
    "walkaway": "Reviewed and fixed SPIKE-058"
  }
}

收到问候 JSON 后:

  1. 向操作者展示问候信息——分支、脏状态、书签(如有)、关注泳道(如有)和警告。

  2. 如果 prev_session.exists 为 true,展示上一个会话的上下文(来自预检 JSON),让操作者决定是继续还是重新开始。

  3. 如果 isolated 为 false,且操作者尚未开始工作,此时不要创建工作树——工作树由 bin/swain 预启动流程创建(SPEC-245)。如果需要工作树名称以供参考,则生成该名称:

    bash "$REPO_ROOT/.agents/bin/swain-worktree-name.sh" "context"
    

    然后使用 --path 重新运行问候脚本,以刷新标签页名称和上下文:

    bash "$REPO_ROOT/.agents/bin/swain-session-greeting.sh" --path "$(pwd)" --json
    
  4. 如果 bookmark 不为 null,则显示该书签:

    恢复会话 — 上次:{bookmark}

  5. 现在会话已准备好开始工作。完整状态仪表板可按需使用(参见状态仪表板(SPEC-122))。

如果未设置 $TMUX(JSON 中没有 tab 即表示检测到此情况),请检查是否已安装 tmux:

  • 未安装 tmux: 提供安装选项(brew install tmux)。
  • 已安装 tmux 但不在会话中: 显示:[note] 不在 tmux 会话中 — 会话标签页和窗格功能不可用

操作者可以随时说“exit worktree”或“back to main”——这会结束会话。运行时退出后,bin/swain 会处理工作树清理(SPEC-245)。

工作树/分支变更(与 Agent 无关)

当 Agent 进入工作树或切换分支时,使用 --path 重新运行引导脚本以更新标签名称:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-session-bootstrap.sh" --path "$NEW_WORKDIR" --skip-worktree --auto

这与 Agent 无关——适用于 Claude Code、opencode、gemini cli、codex、copilot,或任何会读取 AGENTS.md 并能运行 bash 命令的 Agent。

Session.json 架构
{
  "lastBranch": "trunk",
  "lastContext": "Working on swain-session skill",
  "preferences": {
    "verbosity": "concise"
  },
  "bookmark": {
    "note": "Left off implementing the bootstrap script",
    "files": ["SKILL.md"],
    "timestamp": "2026-03-10T14:32:00Z"
  }
}

迁移: 如果 .agents/session.json 不存在,但旧的全局位置(~/.claude/projects/<project-path-slug>/memory/session.json)存在,引导脚本会自动复制它。

README 核对检查点(SPEC-209)

在问候之后、开始工作之前,将 README.md 与制品树进行比较。此检查在每个会话中只运行一次,在选择焦点泳道时进行。

触发条件

设置焦点泳道时(从上一会话恢复或新选择),且 README.md 存在:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
[ -f "$REPO_ROOT/README.md" ] && echo "has_readme" || echo "no_readme"

如果不存在 README,则静默跳过核对——swain-doctor 会标记 README 缺失。

流程
  1. 阅读 README.md 并提取其中的陈述——任何关于项目用途、目标用户、运作方式、支持内容或行为表现的说明。将整个 README 作为普通文本阅读;无需标记或章节约定。
  2. 将这些陈述与当前的 Active Visions、Designs、Journeys 和 Persona 制品进行比较。查找:
    • 过时的承诺——README 声称有某项功能或行为,但制品明确指出该项已弃用或被取代。
    • 内容缺失——某项制品描述了 README 未提及的能力。
    • 相互矛盾——README 与制品对行为、受众或范围的说法不一致。
  3. 对每处不匹配,向操作人员提出具体问题:

    “README 写着‘{claim}’,但 {artifact-id} {describes the conflict}。哪一个才是正确的?”

核对方向

双向核对。出现偏差并不意味着制品一定正确:

  • 新的 Vision 可能意味着需要更新 README。
  • README 可能是正确的,而 Vision 需要调整。
  • 某项承诺可能是有意弃用的,需要从两者中移除。
延后跟踪

操作人员可以延后处理任何不匹配项。延后项会记录在 .agents/session.json 的 readme_deferrals 键下:

{
  "readme_deferrals": [
    {
      "claim": "real-time sync",
      "conflict_artifact": "VISION-003",
      "deferred_at": "2026-03-31T14:00:00Z"
    }
  ]
}

延后项会在下一次会话开始时再次提出。操作人员处理延后项(更新 README 或制品)后,请将其从列表中移除。

静默通过

如果未发现偏差,核对检查将静默通过——不向操作人员输出任何内容。

会话生命周期(SPEC-119)

swain-session 负责管理有明确边界的会话生命周期:开始 → 工作 → 关闭 → 恢复。会话状态通过 swain-session-state.sh 脚本记录在 .agents/session-state.json 中。

会话开始

引导完成且工作树就绪后,初始化会话生命周期:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-session-state.sh" init --focus "<FOCUS-ID>" --session-roadmap "$(pwd)/SESSION-ROADMAP.md" --repo-root "$REPO_ROOT"

此操作会:

  1. 创建 .agents/session-state.json,其中包含焦点泳道、决策预算(默认为 5)和开始时间
  2. 通过 chart.sh session --focus <ID> 生成 SESSION-ROADMAP.md

焦点泳道默认为上一会话的泳道(来自引导 JSON 中的 session.focus)。请与操作人员确认,或接受其指定的其他泳道。

自定义决策预算:--budget 7

工作期间——记录决策

当操作人员或 Agent 作出决策时(批准规格、选择方案、确定方向),请记录:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-session-state.sh" record-decision --note "Approved SPEC-119 implementation approach"
会话关闭

当操作人员说“完成”“收尾”“关闭会话”,或达到决策预算时,执行以下关闭流程。重要: swain-retro 必须在会话仍处于活动状态时运行,以便读取会话状态。运行回顾之前不要关闭会话。

步骤 1——生成会话摘要和进度日志
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-session-digest.sh" --session-id "$(jq -r .session_id "$REPO_ROOT/.agents/session-state.json")" --output "$REPO_ROOT/.agents/session-log.jsonl"
bash "$REPO_ROOT/.agents/bin/swain-progress-log.sh" --digest "$REPO_ROOT/.agents/session-log.jsonl"

此操作会追加一条 JSONL 摘要记录,并更新每个受影响的 EPIC/Initiative 的 progress.md 和 ## Progress 部分。

步骤 2 — 运行 retro(会话仍处于活动状态)
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
SWAIN_RETRO_SKILL="$REPO_ROOT/.claude/skills/swain-retro/SKILL.md"
Skill("$SWAIN_RETRO_SKILL", "Session close — session is closing. Run /swain-retro to capture session learnings before the session state is cleared.")

重要: Retro 会在 session.json 和 session-state.json 仍有内容时读取它们。此步骤之前不要调用 session-state.sh close。

步骤 3 — 关闭会话
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-session-state.sh" close --walkaway "Completed SPEC-119 tests and state management" --session-roadmap "$(pwd)/SESSION-ROADMAP.md"

这会将会话阶段设为 closed,记录结束时间,并将离开信号追加到 SESSION-ROADMAP.md。

步骤 4 — 运行会话拆除
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
SWAIN_TEARDOWN_SKILL="$REPO_ROOT/.claude/skills/swain-teardown/SKILL.md"
Skill("$SWAIN_TEARDOWN_SKILL", "Session teardown — --session-chain flag passed from swain-session close handler.")

这会运行孤立工作树检查、git 脏状态检查、工单同步提示,并写入交接摘要。--session-chain 标志会告知拆除流程跳过冗余的会话活动状态检查,因为处理程序已确认会话状态。

步骤 5 — 提交 SESSION-ROADMAP.md

最后,将 SESSION-ROADMAP.md 提交到 git。

恢复会话

下次会话开始时,从预检 JSON 中读取 prev_session(参见预检)。其中包含上一个会话的关注方向、离开备注、决策数量和过时状态——无需单独调用脚本。

如果需要直接调用 session-state.sh(例如,从不包含预检 JSON 的脚本中调用):

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-session-state.sh" resume

显示上一个会话的上下文,以便操作员决定是继续还是重新开始。

会话状态架构
{
  "session_id": "session-20260328-220634-4ad1",
  "focus_lane": "INITIATIVE-019",
  "phase": "active",
  "start_time": "2026-03-28T22:06:34Z",
  "last_activity_time": "2026-03-28T22:06:34Z",
  "end_time": null,
  "decision_budget": 5,
  "decisions_made": 0,
  "decisions": [],
  "walkaway": null
}

手动调用命令

用户明确调用时,支持以下操作:

设置标签页名称

用户说类似“将标签页名称设为 X”或“重命名标签页”:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-tab-name.sh" "Custom Name"
添加上下文书签

用户说“记住我现在的位置”或“为此添加书签”:

  • 根据对话上下文推断他们正在处理的内容,或使用他们提供的备注——不要提示用户
  • 将包含备注、相关文件和时间戳的内容写入 session.json 的 bookmark 字段
  • 如果已存在书签,无需询问确认,直接静默覆盖——swain-bookmark.sh 会处理原子写入
清除书签

用户说“清除书签”或“重新开始”:

  • 从 session.json 中移除 bookmark 字段
显示会话信息

用户说“会话信息”或“我的会话是什么”:

  • 显示当前标签页名称、分支、偏好设置和书签状态
  • 如果书签备注包含工件 ID(例如 SPEC-052、EPIC-018),显示 Vision 祖先关系路径,提供战略上下文。运行 bash "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents/bin/chart.sh" scope <ID> 2>/dev/null | head -5 获取父级链。显示为:Context: Swain > Operator Situational Awareness > Vision-Rooted Chart Hierarchy
设置偏好

用户说“将偏好 X 设为 Y”:

  • 更新 session.json 中的 preferences

操作后书签(自动更新协议)

其他 swain 技能会在操作后更新会话书签。请阅读 references/bookmark-protocol.md,了解协议、调用模式和示例。

焦点通道

操作员可以设置焦点通道,将推荐范围限定在一个愿景或计划内。这是一种引导机制——它不会隐藏其他工作,而是围绕操作员当前的重点组织推荐内容。

设置焦点: 当操作员说“聚焦安全”或“我正在处理 VISION-001”时,将名称解析为工件 ID,并调用焦点脚本。

**名称到 ID 的解析:**如果操作员使用名称而非 ID(例如,说“安全”而不是“VISION-001”),使用 swain chart 搜索愿景和计划工件标题,找到最佳匹配:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/chart.sh" --ids --flat 2>/dev/null | grep -i "<name>"

如果只有一个匹配项,就使用它。如果有多个匹配项,请操作员明确选择。如果没有匹配项,告知操作员没有名称匹配的愿景或计划,并提出创建一个。

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-focus.sh" set <RESOLVED-ID>

清除焦点:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-focus.sh" clear

检查焦点:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-focus.sh"

对焦点 ID 调用 artifact-context.sh,将焦点工件显示为上下文行。如果该工具不可用,则使用纯 ID。

焦点通道存储在 .agents/session.json 的 focus_lane 键下。它会在一个会话内的状态检查之间持续保留。状态仪表板会读取该值,以筛选推荐内容,并显示非焦点愿景的外围信息。

状态仪表板(SPEC-122)

swain-session 现在负责项目状态仪表板。当操作员说“状态”“接下来做什么”“仪表板”“概览”“目前进展如何”“我该做什么”或“显示优先级”时,运行状态脚本:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
STATUS_SCRIPT="$REPO_ROOT/.agents/bin/swain-status.sh"
[ -f "$STATUS_SCRIPT" ] && bash "$STATUS_SCRIPT" --refresh || echo "status dashboard script not found"

紧凑模式(MOTD):bash "$STATUS_SCRIPT" --compact

脚本运行后,按照 references/agent-summary-template.md 提供结构化的 Agent 摘要。

缓存

状态会写入 .agents/status-cache.json,TTL 为 120 秒。使用 --refresh 绕过缓存,使用 --json 获取原始输出。

推荐

从 JSON 缓存中读取 .priority.recommendations[0]。设置焦点通道后,推荐范围将限定在该愿景或计划内。

丰富上下文的显示

向操作员展示工件(推荐内容、焦点通道、待处理决策)时,使用工件上下文工具,而不是纯 ID:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
CONTEXT=$(bash "$REPO_ROOT/.agents/bin/artifact-context.sh" <ARTIFACT-ID> 2>/dev/null)

如果该工具可用且有输出,则使用上下文行。如果该工具不可用或输出为空,则回退为 <ID> — <title>(当前行为)。

显示格式:标题 ID — 范围。进度。

模式推断
  1. 两份规范都在审核中,且有待处理的战略决策 → 询问操作员
  2. 规范等待审核 → 详细模式
  3. 已设置焦点通道,且有待处理决策 → 愿景模式
  4. 没有可执行事项 → 愿景模式(主计划镜像)
待处理决策(路线图集成)

使用 chart.sh roadmap --json 进行 Eisenhower 分类。显示“立即处理”和“安排处理”象限中需要操作员决策的前 5 项。

设置

此技能读取 swain.settings.json(项目根目录)和 ~/.config/swain/settings.json(用户覆盖项)。用户设置优先。

相关设置:

  • terminal.tabNameFormat — 标签页名称的格式字符串。支持 {project} 和 {branch} 占位符。默认值:{project} @ {branch}

错误处理

  • 如果没有 jq,警告用户并跳过 JSON 操作。没有 jq 仍可设置标签页名称。
  • 如果没有 git,则使用目录名称作为项目名称,并跳过分支检测。
  • 绝不彻底失败——会话管理是便利功能,而非门槛。

评论

支持 Markdown