make-pdf

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly --> <!-- Regenerate: bun run gen:skill-docs -->
<!-- 由SKILL.md.tmpl自动生成——请勿直接编辑 --> <!-- 重新生成:bun run gen:skill-docs -->

Preamble (run first)

前置步骤(先运行)

bash
_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true)
[ -n "$_UPD" ] && echo "$_UPD" || true
mkdir -p ~/.gstack/sessions
touch ~/.gstack/sessions/"$PPID"
_SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true
_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true")
_PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no")
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH"
_SKILL_PREFIX=$(~/.claude/skills/gstack/bin/gstack-config get skill_prefix 2>/dev/null || echo "false")
echo "PROACTIVE: $_PROACTIVE"
echo "PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED"
echo "SKILL_PREFIX: $_SKILL_PREFIX"
source <(~/.claude/skills/gstack/bin/gstack-repo-mode 2>/dev/null) || true
REPO_MODE=${REPO_MODE:-unknown}
echo "REPO_MODE: $REPO_MODE"
_LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no")
echo "LAKE_INTRO: $_LAKE_SEEN"
_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true)
_TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no")
_TEL_START=$(date +%s)
_SESSION_ID="$$-$(date +%s)"
echo "TELEMETRY: ${_TEL:-off}"
echo "TEL_PROMPTED: $_TEL_PROMPTED"
_EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default")
if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi
echo "EXPLAIN_LEVEL: $_EXPLAIN_LEVEL"
_QUESTION_TUNING=$(~/.claude/skills/gstack/bin/gstack-config get question_tuning 2>/dev/null || echo "false")
echo "QUESTION_TUNING: $_QUESTION_TUNING"
mkdir -p ~/.gstack/analytics
if [ "$_TEL" != "off" ]; then
echo '{"skill":"make-pdf","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}'  >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
fi
for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do
  if [ -f "$_PF" ]; then
    if [ "$_TEL" != "off" ] && [ -x "~/.claude/skills/gstack/bin/gstack-telemetry-log" ]; then
      ~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true
    fi
    rm -f "$_PF" 2>/dev/null || true
  fi
  break
done
eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true
_LEARN_FILE="${GSTACK_HOME:-$HOME/.gstack}/projects/${SLUG:-unknown}/learnings.jsonl"
if [ -f "$_LEARN_FILE" ]; then
  _LEARN_COUNT=$(wc -l < "$_LEARN_FILE" 2>/dev/null | tr -d ' ')
  echo "LEARNINGS: $_LEARN_COUNT entries loaded"
  if [ "$_LEARN_COUNT" -gt 5 ] 2>/dev/null; then
    ~/.claude/skills/gstack/bin/gstack-learnings-search --limit 3 2>/dev/null || true
  fi
else
  echo "LEARNINGS: 0"
fi
~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"make-pdf","event":"started","branch":"'"$_BRANCH"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null &
_HAS_ROUTING="no"
if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then
  _HAS_ROUTING="yes"
fi
_ROUTING_DECLINED=$(~/.claude/skills/gstack/bin/gstack-config get routing_declined 2>/dev/null || echo "false")
echo "HAS_ROUTING: $_HAS_ROUTING"
echo "ROUTING_DECLINED: $_ROUTING_DECLINED"
_VENDORED="no"
if [ -d ".claude/skills/gstack" ] && [ ! -L ".claude/skills/gstack" ]; then
  if [ -f ".claude/skills/gstack/VERSION" ] || [ -d ".claude/skills/gstack/.git" ]; then
    _VENDORED="yes"
  fi
fi
echo "VENDORED_GSTACK: $_VENDORED"
echo "MODEL_OVERLAY: claude"
_CHECKPOINT_MODE=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_mode 2>/dev/null || echo "explicit")
_CHECKPOINT_PUSH=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_push 2>/dev/null || echo "false")
echo "CHECKPOINT_MODE: $_CHECKPOINT_MODE"
echo "CHECKPOINT_PUSH: $_CHECKPOINT_PUSH"
[ -n "$OPENCLAW_SESSION" ] && echo "SPAWNED_SESSION: true" || true
bash
_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true)
[ -n "$_UPD" ] && echo "$_UPD" || true
mkdir -p ~/.gstack/sessions
touch ~/.gstack/sessions/"$PPID"
_SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true
_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true")
_PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no")
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH"
_SKILL_PREFIX=$(~/.claude/skills/gstack/bin/gstack-config get skill_prefix 2>/dev/null || echo "false")
echo "PROACTIVE: $_PROACTIVE"
echo "PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED"
echo "SKILL_PREFIX: $_SKILL_PREFIX"
source <(~/.claude/skills/gstack/bin/gstack-repo-mode 2>/dev/null) || true
REPO_MODE=${REPO_MODE:-unknown}
echo "REPO_MODE: $REPO_MODE"
_LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no")
echo "LAKE_INTRO: $_LAKE_SEEN"
_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true)
_TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no")
_TEL_START=$(date +%s)
_SESSION_ID="$$-$(date +%s)"
echo "TELEMETRY: ${_TEL:-off}"
echo "TEL_PROMPTED: $_TEL_PROMPTED"
_EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default")
if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi
echo "EXPLAIN_LEVEL: $_EXPLAIN_LEVEL"
_QUESTION_TUNING=$(~/.claude/skills/gstack/bin/gstack-config get question_tuning 2>/dev/null || echo "false")
echo "QUESTION_TUNING: $_QUESTION_TUNING"
mkdir -p ~/.gstack/analytics
if [ "$_TEL" != "off" ]; then
echo '{"skill":"make-pdf","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}'  >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
fi
for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do
  if [ -f "$_PF" ]; then
    if [ "$_TEL" != "off" ] && [ -x "~/.claude/skills/gstack/bin/gstack-telemetry-log" ]; then
      ~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true
    fi
    rm -f "$_PF" 2>/dev/null || true
  fi
  break
done
eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true
_LEARN_FILE="${GSTACK_HOME:-$HOME/.gstack}/projects/${SLUG:-unknown}/learnings.jsonl"
if [ -f "$_LEARN_FILE" ]; then
  _LEARN_COUNT=$(wc -l < "$_LEARN_FILE" 2>/dev/null | tr -d ' ')
  echo "LEARNINGS: $_LEARN_COUNT entries loaded"
  if [ "$_LEARN_COUNT" -gt 5 ] 2>/dev/null; then
    ~/.claude/skills/gstack/bin/gstack-learnings-search --limit 3 2>/dev/null || true
  fi
else
  echo "LEARNINGS: 0"
fi
~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"make-pdf","event":"started","branch":"'"$_BRANCH"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null &
_HAS_ROUTING="no"
if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then
  _HAS_ROUTING="yes"
fi
_ROUTING_DECLINED=$(~/.claude/skills/gstack/bin/gstack-config get routing_declined 2>/dev/null || echo "false")
echo "HAS_ROUTING: $_HAS_ROUTING"
echo "ROUTING_DECLINED: $_ROUTING_DECLINED"
_VENDORED="no"
if [ -d ".claude/skills/gstack" ] && [ ! -L ".claude/skills/gstack" ]; then
  if [ -f ".claude/skills/gstack/VERSION" ] || [ -d ".claude/skills/gstack/.git" ]; then
    _VENDORED="yes"
  fi
fi
echo "VENDORED_GSTACK: $_VENDORED"
echo "MODEL_OVERLAY: claude"
_CHECKPOINT_MODE=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_mode 2>/dev/null || echo "explicit")
_CHECKPOINT_PUSH=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_push 2>/dev/null || echo "false")
echo "CHECKPOINT_MODE: $_CHECKPOINT_MODE"
echo "CHECKPOINT_PUSH: $_CHECKPOINT_PUSH"
[ -n "$OPENCLAW_SESSION" ] && echo "SPAWNED_SESSION: true" || true

Plan Mode Safe Operations

计划模式安全操作

In plan mode, allowed because they inform the plan:
$B
,
$D
,
codex exec
/
codex review
, writes to
~/.gstack/
, writes to the plan file, and
open
for generated artifacts.
在计划模式下,以下操作被允许,因为它们为计划提供信息:
$B
$D
codex exec
/
codex review
、写入
~/.gstack/
目录、写入计划文件,以及对生成的工件执行
open
操作。

Skill Invocation During Plan Mode

计划模式下的技能调用

If the user invokes a skill in plan mode, the skill takes precedence over generic plan mode behavior. Treat the skill file as executable instructions, not reference. Follow it step by step starting from Step 0; the first AskUserQuestion is the workflow entering plan mode, not a violation of it. AskUserQuestion (any variant —
mcp__*__AskUserQuestion
or native; see "AskUserQuestion Format → Tool resolution") satisfies plan mode's end-of-turn requirement. If no variant is callable, the skill is BLOCKED — stop and report
BLOCKED — AskUserQuestion unavailable
per the AskUserQuestion Format rule. At a STOP point, stop immediately. Do not continue the workflow or call ExitPlanMode there. Commands marked "PLAN MODE EXCEPTION — ALWAYS RUN" execute. Call ExitPlanMode only after the skill workflow completes, or if the user tells you to cancel the skill or leave plan mode.
If
PROACTIVE
is
"false"
, do not auto-invoke or proactively suggest skills. If a skill seems useful, ask: "I think /skillname might help here — want me to run it?"
If
SKILL_PREFIX
is
"true"
, suggest/invoke
/gstack-*
names. Disk paths stay
~/.claude/skills/gstack/[skill-name]/SKILL.md
.
If output shows
UPGRADE_AVAILABLE <old> <new>
: read
~/.claude/skills/gstack/gstack-upgrade/SKILL.md
and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined).
If output shows
JUST_UPGRADED <from> <to>
: print "Running gstack v{to} (just updated!)". If
SPAWNED_SESSION
is true, skip feature discovery.
Feature discovery, max one prompt per session:
  • Missing
    ~/.claude/skills/gstack/.feature-prompted-continuous-checkpoint
    : AskUserQuestion for Continuous checkpoint auto-commits. If accepted, run
    ~/.claude/skills/gstack/bin/gstack-config set checkpoint_mode continuous
    . Always touch marker.
  • Missing
    ~/.claude/skills/gstack/.feature-prompted-model-overlay
    : inform "Model overlays are active. MODEL_OVERLAY shows the patch." Always touch marker.
After upgrade prompts, continue workflow.
If
WRITING_STYLE_PENDING
is
yes
: ask once about writing style:
v1 prompts are simpler: first-use jargon glosses, outcome-framed questions, shorter prose. Keep default or restore terse?
Options:
  • A) Keep the new default (recommended — good writing helps everyone)
  • B) Restore V0 prose — set
    explain_level: terse
If A: leave
explain_level
unset (defaults to
default
). If B: run
~/.claude/skills/gstack/bin/gstack-config set explain_level terse
.
Always run (regardless of choice):
bash
rm -f ~/.gstack/.writing-style-prompt-pending
touch ~/.gstack/.writing-style-prompted
Skip if
WRITING_STYLE_PENDING
is
no
.
If
LAKE_INTRO
is
no
: say "gstack follows the Boil the Lake principle — do the complete thing when AI makes marginal cost near-zero. Read more: https://garryslist.org/posts/boil-the-ocean" Offer to open:
bash
open https://garryslist.org/posts/boil-the-ocean
touch ~/.gstack/.completeness-intro-seen
Only run
open
if yes. Always run
touch
.
If
TEL_PROMPTED
is
no
AND
LAKE_INTRO
is
yes
: ask telemetry once via AskUserQuestion:
Help gstack get better. Share usage data only: skill, duration, crashes, stable device ID. No code, file paths, or repo names.
Options:
  • A) Help gstack get better! (recommended)
  • B) No thanks
If A: run
~/.claude/skills/gstack/bin/gstack-config set telemetry community
If B: ask follow-up:
Anonymous mode sends only aggregate usage, no unique ID.
Options:
  • A) Sure, anonymous is fine
  • B) No thanks, fully off
If B→A: run
~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous
If B→B: run
~/.claude/skills/gstack/bin/gstack-config set telemetry off
Always run:
bash
touch ~/.gstack/.telemetry-prompted
Skip if
TEL_PROMPTED
is
yes
.
If
PROACTIVE_PROMPTED
is
no
AND
TEL_PROMPTED
is
yes
: ask once:
Let gstack proactively suggest skills, like /qa for "does this work?" or /investigate for bugs?
Options:
  • A) Keep it on (recommended)
  • B) Turn it off — I'll type /commands myself
If A: run
~/.claude/skills/gstack/bin/gstack-config set proactive true
If B: run
~/.claude/skills/gstack/bin/gstack-config set proactive false
Always run:
bash
touch ~/.gstack/.proactive-prompted
Skip if
PROACTIVE_PROMPTED
is
yes
.
If
HAS_ROUTING
is
no
AND
ROUTING_DECLINED
is
false
AND
PROACTIVE_PROMPTED
is
yes
: Check if a CLAUDE.md file exists in the project root. If it does not exist, create it.
Use AskUserQuestion:
gstack works best when your project's CLAUDE.md includes skill routing rules.
Options:
  • A) Add routing rules to CLAUDE.md (recommended)
  • B) No thanks, I'll invoke skills manually
If A: Append this section to the end of CLAUDE.md:
markdown
undefined
如果用户在计划模式下调用技能,该技能优先于通用计划模式行为。将技能文件视为可执行指令,而非参考文档。从步骤0开始逐步执行;第一个AskUserQuestion表示工作流进入计划模式,并非违反规则。AskUserQuestion(任何变体——
mcp__*__AskUserQuestion
或原生;请参阅“AskUserQuestion格式 → 工具解析”)满足计划模式的回合结束要求。如果没有可调用的变体,则技能被BLOCKED——根据AskUserQuestion格式规则,停止并报告
BLOCKED — AskUserQuestion unavailable
。在STOP点,立即停止。不要继续工作流或调用ExitPlanMode。标记为“PLAN MODE EXCEPTION — ALWAYS RUN”的命令必须执行。仅在技能工作流完成后,或用户要求取消技能或退出计划模式时,才调用ExitPlanMode。
如果
PROACTIVE
"false"
,请勿自动调用或主动建议技能。如果某个技能看起来有用,请询问:“我认为/skillname可能会有帮助——需要我运行它吗?”
如果
SKILL_PREFIX
"true"
,建议/调用
/gstack-*
名称。磁盘路径保持为
~/.claude/skills/gstack/[skill-name]/SKILL.md
如果输出显示
UPGRADE_AVAILABLE <old> <new>
:阅读
~/.claude/skills/gstack/gstack-upgrade/SKILL.md
并遵循“内联升级流程”(如果已配置则自动升级,否则通过AskUserQuestion提供4个选项,如果用户拒绝则写入暂停状态)。
如果输出显示
JUST_UPGRADED <from> <to>
:打印“Running gstack v{to} (just updated!)”。如果
SPAWNED_SESSION
为true,跳过功能发现环节。
功能发现,每个会话最多提示一次:
  • 缺少
    ~/.claude/skills/gstack/.feature-prompted-continuous-checkpoint
    :通过AskUserQuestion询问是否启用Continuous checkpoint自动提交。如果用户同意,运行
    ~/.claude/skills/gstack/bin/gstack-config set checkpoint_mode continuous
    。无论如何都要创建标记文件。
  • 缺少
    ~/.claude/skills/gstack/.feature-prompted-model-overlay
    :告知用户“Model overlays已激活。MODEL_OVERLAY显示补丁内容。”无论如何都要创建标记文件。
完成升级提示后,继续工作流。
如果
WRITING_STYLE_PENDING
yes
:询问一次写作风格偏好:
v1提示更简洁:首次使用时提供术语解释、以结果为导向的问题、更简短的文本。保留默认风格还是恢复简洁风格?
选项:
  • A) 保留新默认风格(推荐——良好的写作体验对所有人都有帮助)
  • B) 恢复V0文本风格——设置
    explain_level: terse
如果选择A:不设置
explain_level
(默认值为
default
)。 如果选择B:运行
~/.claude/skills/gstack/bin/gstack-config set explain_level terse
无论选择哪个选项,都要运行:
bash
rm -f ~/.gstack/.writing-style-prompt-pending
touch ~/.gstack/.writing-style-prompted
如果
WRITING_STYLE_PENDING
no
,则跳过此步骤。
如果
LAKE_INTRO
no
:说明“gstack遵循Boil the Lake原则——当AI的边际成本接近零时,完成完整的任务。了解更多:https://garryslist.org/posts/boil-the-ocean”,并提供打开链接的选项:
bash
open https://garryslist.org/posts/boil-the-ocean
touch ~/.gstack/.completeness-intro-seen
仅在用户同意时运行
open
命令。无论如何都要运行
touch
命令。
如果
TEL_PROMPTED
no
LAKE_INTRO
yes
:通过AskUserQuestion询问一次遥测设置:
帮助gstack变得更好。仅分享使用数据:技能名称、时长、崩溃情况、稳定设备ID。不包含代码、文件路径或仓库名称。
选项:
  • A) 帮助gstack变得更好!(推荐)
  • B) 不用了,谢谢
如果选择A:运行
~/.claude/skills/gstack/bin/gstack-config set telemetry community
如果选择B:跟进询问:
匿名模式仅发送汇总使用数据,不包含唯一ID。
选项:
  • A) 好的,匿名模式可以接受
  • B) 不用了,完全关闭
如果B→A:运行
~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous
如果B→B:运行
~/.claude/skills/gstack/bin/gstack-config set telemetry off
无论选择哪个选项,都要运行:
bash
touch ~/.gstack/.telemetry-prompted
如果
TEL_PROMPTED
yes
,则跳过此步骤。
如果
PROACTIVE_PROMPTED
no
TEL_PROMPTED
yes
:询问一次:
让gstack主动建议技能,比如针对“这个能运行吗?”调用/qa,或者针对bug调用/investigate?
选项:
  • A) 保持开启(推荐)
  • B) 关闭——我会手动输入/命令
如果选择A:运行
~/.claude/skills/gstack/bin/gstack-config set proactive true
如果选择B:运行
~/.claude/skills/gstack/bin/gstack-config set proactive false
无论选择哪个选项,都要运行:
bash
touch ~/.gstack/.proactive-prompted
如果
PROACTIVE_PROMPTED
yes
,则跳过此步骤。
如果
HAS_ROUTING
no
ROUTING_DECLINED
false
PROACTIVE_PROMPTED
yes
: 检查项目根目录是否存在CLAUDE.md文件。如果不存在,创建该文件。
通过AskUserQuestion询问:
当项目的CLAUDE.md包含技能路由规则时,gstack的效果最佳。
选项:
  • A) 向CLAUDE.md添加路由规则(推荐)
  • B) 不用了,谢谢,我会手动调用技能
如果选择A:将以下章节追加到CLAUDE.md末尾:
markdown
undefined

Skill routing

Skill routing

When the user's request matches an available skill, invoke it via the Skill tool. When in doubt, invoke the skill.
Key routing rules:
  • Product ideas/brainstorming → invoke /office-hours
  • Strategy/scope → invoke /plan-ceo-review
  • Architecture → invoke /plan-eng-review
  • Design system/plan review → invoke /design-consultation or /plan-design-review
  • Full review pipeline → invoke /autoplan
  • Bugs/errors → invoke /investigate
  • QA/testing site behavior → invoke /qa or /qa-only
  • Code review/diff check → invoke /review
  • Visual polish → invoke /design-review
  • Ship/deploy/PR → invoke /ship or /land-and-deploy
  • Save progress → invoke /context-save
  • Resume context → invoke /context-restore

Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"`

If B: run `~/.claude/skills/gstack/bin/gstack-config set routing_declined true` and say they can re-enable with `gstack-config set routing_declined false`.

This only happens once per project. Skip if `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`.

If `VENDORED_GSTACK` is `yes`, warn once via AskUserQuestion unless `~/.gstack/.vendoring-warned-$SLUG` exists:

> This project has gstack vendored in `.claude/skills/gstack/`. Vendoring is deprecated.
> Migrate to team mode?

Options:
- A) Yes, migrate to team mode now
- B) No, I'll handle it myself

If A:
1. Run `git rm -r .claude/skills/gstack/`
2. Run `echo '.claude/skills/gstack/' >> .gitignore`
3. Run `~/.claude/skills/gstack/bin/gstack-team-init required` (or `optional`)
4. Run `git add .claude/ .gitignore CLAUDE.md && git commit -m "chore: migrate gstack from vendored to team mode"`
5. Tell the user: "Done. Each developer now runs: `cd ~/.claude/skills/gstack && ./setup --team`"

If B: say "OK, you're on your own to keep the vendored copy up to date."

Always run (regardless of choice):
```bash
eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true
touch ~/.gstack/.vendoring-warned-${SLUG:-unknown}
If marker exists, skip.
If
SPAWNED_SESSION
is
"true"
, you are running inside a session spawned by an AI orchestrator (e.g., OpenClaw). In spawned sessions:
  • Do NOT use AskUserQuestion for interactive prompts. Auto-choose the recommended option.
  • Do NOT run upgrade checks, telemetry prompts, routing injection, or lake intro.
  • Focus on completing the task and reporting results via prose output.
  • End with a completion report: what shipped, decisions made, anything uncertain.
When the user's request matches an available skill, invoke it via the Skill tool. When in doubt, invoke the skill.
Key routing rules:
  • Product ideas/brainstorming → invoke /office-hours
  • Strategy/scope → invoke /plan-ceo-review
  • Architecture → invoke /plan-eng-review
  • Design system/plan review → invoke /design-consultation or /plan-design-review
  • Full review pipeline → invoke /autoplan
  • Bugs/errors → invoke /investigate
  • QA/testing site behavior → invoke /qa or /qa-only
  • Code review/diff check → invoke /review
  • Visual polish → invoke /design-review
  • Ship/deploy/PR → invoke /ship or /land-and-deploy
  • Save progress → invoke /context-save
  • Resume context → invoke /context-restore

然后提交更改:`git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"`

如果选择B:运行`~/.claude/skills/gstack/bin/gstack-config set routing_declined true`并告知用户可以通过`gstack-config set routing_declined false`重新启用。

每个项目仅执行此操作一次。如果`HAS_ROUTING`为`yes`或`ROUTING_DECLINED`为`true`,则跳过此步骤。

如果`VENDORED_GSTACK`为`yes`,且`~/.gstack/.vendoring-warned-$SLUG`不存在,则通过AskUserQuestion警告一次:

> 此项目已将gstack内嵌在`.claude/skills/gstack/`目录中。内嵌方式已被弃用。
> 是否迁移到团队模式?

选项:
- A) 是的,立即迁移到团队模式
- B) 不用了,我会自行处理

如果选择A:
1. 运行`git rm -r .claude/skills/gstack/`
2. 运行`echo '.claude/skills/gstack/' >> .gitignore`
3. 运行`~/.claude/skills/gstack/bin/gstack-team-init required`(或`optional`)
4. 运行`git add .claude/ .gitignore CLAUDE.md && git commit -m "chore: migrate gstack from vendored to team mode"`
5. 告知用户:“完成。每位开发者现在需要运行:`cd ~/.claude/skills/gstack && ./setup --team`”

如果选择B:告知用户“好的,你需要自行保持内嵌副本的更新。”

无论选择哪个选项,都要运行:
```bash
eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true
touch ~/.gstack/.vendoring-warned-${SLUG:-unknown}
如果标记文件已存在,则跳过此步骤。
如果
SPAWNED_SESSION
"true"
,说明你正在AI编排器(如OpenClaw)生成的会话中运行。在此类会话中:
  • 请勿使用AskUserQuestion进行交互式提示。自动选择推荐选项。
  • 请勿运行升级检查、遥测提示、路由注入或lake介绍环节。
  • 专注于完成任务并通过文本输出报告结果。
  • 最后提交完成报告:已完成的内容、做出的决策、任何不确定的事项。

Artifacts Sync (skill start)

工件同步(技能启动时)

bash
_GSTACK_HOME="${GSTACK_HOME:-$HOME/.gstack}"
bash
_GSTACK_HOME="${GSTACK_HOME:-$HOME/.gstack}"

Prefer the v1.27.0.0 artifacts file; fall back to brain file for users

Prefer the v1.27.0.0 artifacts file; fall back to brain file for users

upgrading mid-stream before the migration script runs.

upgrading mid-stream before the migration script runs.

if [ -f "$HOME/.gstack-artifacts-remote.txt" ]; then _BRAIN_REMOTE_FILE="$HOME/.gstack-artifacts-remote.txt" else _BRAIN_REMOTE_FILE="$HOME/.gstack-brain-remote.txt" fi _BRAIN_SYNC_BIN="/.claude/skills/gstack/bin/gstack-brain-sync" _BRAIN_CONFIG_BIN="/.claude/skills/gstack/bin/gstack-config"
if [ -f "$HOME/.gstack-artifacts-remote.txt" ]; then _BRAIN_REMOTE_FILE="$HOME/.gstack-artifacts-remote.txt" else _BRAIN_REMOTE_FILE="$HOME/.gstack-brain-remote.txt" fi _BRAIN_SYNC_BIN="/.claude/skills/gstack/bin/gstack-brain-sync" _BRAIN_CONFIG_BIN="/.claude/skills/gstack/bin/gstack-config"

/sync-gbrain context-load: teach the agent to use gbrain when it's available.

/sync-gbrain context-load: teach the agent to use gbrain when it's available.

Per-worktree pin: post-spike redesign uses kubectl-style
.gbrain-source
in the

Per-worktree pin: post-spike redesign uses kubectl-style
.gbrain-source
in the

git toplevel to scope queries. Look for the pin in the worktree (not a global

git toplevel to scope queries. Look for the pin in the worktree (not a global

state file) so that opening worktree B without a pin doesn't claim "indexed"

state file) so that opening worktree B without a pin doesn't claim "indexed"

just because worktree A was synced. Empty string when gbrain is not

just because worktree A was synced. Empty string when gbrain is not

configured (zero context cost for non-gbrain users).

configured (zero context cost for non-gbrain users).

_GBRAIN_CONFIG="$HOME/.gbrain/config.json" if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then _GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0) if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then _GBRAIN_PIN_PATH="" _REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "") if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then _GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source" fi if [ -n "$_GBRAIN_PIN_PATH" ]; then echo "GBrain configured. Prefer `gbrain search`/`gbrain query` over Grep for" echo "semantic questions; use `gbrain code-def`/`code-refs`/`code-callers` for" echo "symbol-aware code lookup. See "## GBrain Search Guidance" in CLAUDE.md." echo "Run /sync-gbrain to refresh." else echo "GBrain configured but this worktree isn't pinned yet. Run `/sync-gbrain --full`" echo "before relying on `gbrain search` for code questions in this worktree." echo "Falls back to Grep until pinned." fi fi fi
_BRAIN_SYNC_MODE=$("$_BRAIN_CONFIG_BIN" get artifacts_sync_mode 2>/dev/null || echo off)
_GBRAIN_CONFIG="$HOME/.gbrain/config.json" if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then _GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0) if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then _GBRAIN_PIN_PATH="" _REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "") if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then _GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source" fi if [ -n "$_GBRAIN_PIN_PATH" ]; then echo "GBrain configured. Prefer `gbrain search`/`gbrain query` over Grep for" echo "semantic questions; use `gbrain code-def`/`code-refs`/`code-callers` for" echo "symbol-aware code lookup. See "## GBrain Search Guidance" in CLAUDE.md." echo "Run /sync-gbrain to refresh." else echo "GBrain configured but this worktree isn't pinned yet. Run `/sync-gbrain --full`" echo "before relying on `gbrain search` for code questions in this worktree." echo "Falls back to Grep until pinned." fi fi fi
_BRAIN_SYNC_MODE=$("$_BRAIN_CONFIG_BIN" get artifacts_sync_mode 2>/dev/null || echo off)

Detect remote-MCP mode (Path 4 of /setup-gbrain). Local artifacts sync is

Detect remote-MCP mode (Path 4 of /setup-gbrain). Local artifacts sync is

a no-op in remote mode; the brain server pulls from GitHub/GitLab on its

a no-op in remote mode; the brain server pulls from GitHub/GitLab on its

own cadence. Read claude.json directly to keep this preamble fast (no

own cadence. Read claude.json directly to keep this preamble fast (no

subprocess to claude CLI on every skill start).

subprocess to claude CLI on every skill start).

_GBRAIN_MCP_MODE="none" if command -v jq >/dev/null 2>&1 && [ -f "$HOME/.claude.json" ]; then _GBRAIN_MCP_TYPE=$(jq -r '.mcpServers.gbrain.type // .mcpServers.gbrain.transport // empty' "$HOME/.claude.json" 2>/dev/null) case "$_GBRAIN_MCP_TYPE" in url|http|sse) _GBRAIN_MCP_MODE="remote-http" ;; stdio) _GBRAIN_MCP_MODE="local-stdio" ;; esac fi
if [ -f "$_BRAIN_REMOTE_FILE" ] && [ ! -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" = "off" ]; then _BRAIN_NEW_URL=$(head -1 "$_BRAIN_REMOTE_FILE" 2>/dev/null | tr -d '[:space:]') if [ -n "$_BRAIN_NEW_URL" ]; then echo "ARTIFACTS_SYNC: artifacts repo detected: $_BRAIN_NEW_URL" echo "ARTIFACTS_SYNC: run 'gstack-brain-restore' to pull your cross-machine artifacts (or 'gstack-config set artifacts_sync_mode off' to dismiss forever)" fi fi
if [ -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" != "off" ]; then _BRAIN_LAST_PULL_FILE="$_GSTACK_HOME/.brain-last-pull" _BRAIN_NOW=$(date +%s) _BRAIN_DO_PULL=1 if [ -f "$_BRAIN_LAST_PULL_FILE" ]; then _BRAIN_LAST=$(cat "$_BRAIN_LAST_PULL_FILE" 2>/dev/null || echo 0) _BRAIN_AGE=$(( _BRAIN_NOW - _BRAIN_LAST )) [ "$_BRAIN_AGE" -lt 86400 ] && _BRAIN_DO_PULL=0 fi if [ "$_BRAIN_DO_PULL" = "1" ]; then ( cd "$_GSTACK_HOME" && git fetch origin >/dev/null 2>&1 && git merge --ff-only "origin/$(git rev-parse --abbrev-ref HEAD)" >/dev/null 2>&1 ) || true echo "$_BRAIN_NOW" > "$_BRAIN_LAST_PULL_FILE" fi "$_BRAIN_SYNC_BIN" --once 2>/dev/null || true fi
if [ "$_GBRAIN_MCP_MODE" = "remote-http" ]; then

Remote-MCP mode: local artifacts sync is a no-op (brain admin's server

pulls from GitHub/GitLab). Show the user this is by design, not broken.

_GBRAIN_HOST=$(jq -r '.mcpServers.gbrain.url // empty' "$HOME/.claude.json" 2>/dev/null | sed -E 's|^https?://([^/:]+).*|\1|') echo "ARTIFACTS_SYNC: remote-mode (managed by brain server ${_GBRAIN_HOST:-remote})" elif [ -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" != "off" ]; then _BRAIN_QUEUE_DEPTH=0 [ -f "$_GSTACK_HOME/.brain-queue.jsonl" ] && _BRAIN_QUEUE_DEPTH=$(wc -l < "$_GSTACK_HOME/.brain-queue.jsonl" | tr -d ' ') _BRAIN_LAST_PUSH="never" [ -f "$_GSTACK_HOME/.brain-last-push" ] && _BRAIN_LAST_PUSH=$(cat "$_GSTACK_HOME/.brain-last-push" 2>/dev/null || echo never) echo "ARTIFACTS_SYNC: mode=$_BRAIN_SYNC_MODE | last_push=$_BRAIN_LAST_PUSH | queue=$_BRAIN_QUEUE_DEPTH" else echo "ARTIFACTS_SYNC: off" fi



Privacy stop-gate: if output shows `ARTIFACTS_SYNC: off`, `artifacts_sync_mode_prompted` is `false`, and gbrain is on PATH or `gbrain doctor --fast --json` works, ask once:

> gstack can publish your artifacts (CEO plans, designs, reports) to a private GitHub repo that GBrain indexes across machines. How much should sync?

Options:
- A) Everything allowlisted (recommended)
- B) Only artifacts
- C) Decline, keep everything local

After answer:

```bash
_GBRAIN_MCP_MODE="none" if command -v jq >/dev/null 2>&1 && [ -f "$HOME/.claude.json" ]; then _GBRAIN_MCP_TYPE=$(jq -r '.mcpServers.gbrain.type // .mcpServers.gbrain.transport // empty' "$HOME/.claude.json" 2>/dev/null) case "$_GBRAIN_MCP_TYPE" in url|http|sse) _GBRAIN_MCP_MODE="remote-http" ;; stdio) _GBRAIN_MCP_MODE="local-stdio" ;; esac fi
if [ -f "$_BRAIN_REMOTE_FILE" ] && [ ! -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" = "off" ]; then _BRAIN_NEW_URL=$(head -1 "$_BRAIN_REMOTE_FILE" 2>/dev/null | tr -d '[:space:]') if [ -n "$_BRAIN_NEW_URL" ]; then echo "ARTIFACTS_SYNC: artifacts repo detected: $_BRAIN_NEW_URL" echo "ARTIFACTS_SYNC: run 'gstack-brain-restore' to pull your cross-machine artifacts (or 'gstack-config set artifacts_sync_mode off' to dismiss forever)" fi fi
if [ -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" != "off" ]; then _BRAIN_LAST_PULL_FILE="$_GSTACK_HOME/.brain-last-pull" _BRAIN_NOW=$(date +%s) _BRAIN_DO_PULL=1 if [ -f "$_BRAIN_LAST_PULL_FILE" ]; then _BRAIN_LAST=$(cat "$_BRAIN_LAST_PULL_FILE" 2>/dev/null || echo 0) _BRAIN_AGE=$(( _BRAIN_NOW - _BRAIN_LAST )) [ "$_BRAIN_AGE" -lt 86400 ] && _BRAIN_DO_PULL=0 fi if [ "$_BRAIN_DO_PULL" = "1" ]; then ( cd "$_GSTACK_HOME" && git fetch origin >/dev/null 2>&1 && git merge --ff-only "origin/$(git rev-parse --abbrev-ref HEAD)" >/dev/null 2>&1 ) || true echo "$_BRAIN_NOW" > "$_BRAIN_LAST_PULL_FILE" fi "$_BRAIN_SYNC_BIN" --once 2>/dev/null || true fi
if [ "$_GBRAIN_MCP_MODE" = "remote-http" ]; then

Remote-MCP mode: local artifacts sync is a no-op (brain admin's server

pulls from GitHub/GitLab). Show the user this is by design, not broken.

_GBRAIN_HOST=$(jq -r '.mcpServers.gbrain.url // empty' "$HOME/.claude.json" 2>/dev/null | sed -E 's|^https?://([^/:]+).*|\1|') echo "ARTIFACTS_SYNC: remote-mode (managed by brain server ${_GBRAIN_HOST:-remote})" elif [ -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" != "off" ]; then _BRAIN_QUEUE_DEPTH=0 [ -f "$_GSTACK_HOME/.brain-queue.jsonl" ] && _BRAIN_QUEUE_DEPTH=$(wc -l < "$_GSTACK_HOME/.brain-queue.jsonl" | tr -d ' ') _BRAIN_LAST_PUSH="never" [ -f "$_GSTACK_HOME/.brain-last-push" ] && _BRAIN_LAST_PUSH=$(cat "$_GSTACK_HOME/.brain-last-push" 2>/dev/null || echo never) echo "ARTIFACTS_SYNC: mode=$_BRAIN_SYNC_MODE | last_push=$_BRAIN_LAST_PUSH | queue=$_BRAIN_QUEUE_DEPTH" else echo "ARTIFACTS_SYNC: off" fi



隐私检查点:如果输出显示`ARTIFACTS_SYNC: off`,`artifacts_sync_mode_prompted`为`false`,且gbrain已在PATH中或`gbrain doctor --fast --json`可正常运行,则询问一次:

> gstack可以将你的工件(CEO计划、设计稿、报告)发布到私有GitHub仓库,供GBrain跨机器索引。同步范围设置为?

选项:
- A) 所有允许的内容(推荐)
- B) 仅工件
- C) 拒绝,全部保留在本地

用户回答后运行:

```bash

Chosen mode: full | artifacts-only | off

Chosen mode: full | artifacts-only | off

"$_BRAIN_CONFIG_BIN" set artifacts_sync_mode <choice> "$_BRAIN_CONFIG_BIN" set artifacts_sync_mode_prompted true

If A/B and `~/.gstack/.git` is missing, ask whether to run `gstack-artifacts-init`. Do not block the skill.

At skill END before telemetry:

```bash
"~/.claude/skills/gstack/bin/gstack-brain-sync" --discover-new 2>/dev/null || true
"~/.claude/skills/gstack/bin/gstack-brain-sync" --once 2>/dev/null || true
"$_BRAIN_CONFIG_BIN" set artifacts_sync_mode <choice> "$_BRAIN_CONFIG_BIN" set artifacts_sync_mode_prompted true

如果选择A/B且`~/.gstack/.git`不存在,询问是否运行`gstack-artifacts-init`。不要阻塞技能运行。

在技能结束、遥测之前运行:

```bash
"~/.claude/skills/gstack/bin/gstack-brain-sync" --discover-new 2>/dev/null || true
"~/.claude/skills/gstack/bin/gstack-brain-sync" --once 2>/dev/null || true

Model-Specific Behavioral Patch (claude)

特定模型行为补丁(claude)

The following nudges are tuned for the claude model family. They are subordinate to skill workflow, STOP points, AskUserQuestion gates, plan-mode safety, and /ship review gates. If a nudge below conflicts with skill instructions, the skill wins. Treat these as preferences, not rules.
Todo-list discipline. When working through a multi-step plan, mark each task complete individually as you finish it. Do not batch-complete at the end. If a task turns out to be unnecessary, mark it skipped with a one-line reason.
Think before heavy actions. For complex operations (refactors, migrations, non-trivial new features), briefly state your approach before executing. This lets the user course-correct cheaply instead of mid-flight.
Dedicated tools over Bash. Prefer Read, Edit, Write, Glob, Grep over shell equivalents (cat, sed, find, grep). The dedicated tools are cheaper and clearer.
以下提示针对claude模型家族进行了优化。它们服从于技能工作流、STOP点、AskUserQuestion检查点、计划模式安全规则和/ship审核检查点。如果以下提示与技能说明冲突,以技能说明为准。将这些视为偏好,而非强制规则。
待办事项纪律。处理多步骤计划时,完成每个任务后单独标记为已完成。不要在最后批量标记完成。如果某个任务被证明是不必要的,标记为已跳过并附上一行原因说明。
执行复杂操作前先思考。对于复杂操作(重构、迁移、非平凡的新功能),在执行前简要说明你的方法。这样用户可以在早期进行调整,而不必在操作中途纠正。
优先使用专用工具而非Bash。优先使用Read、Edit、Write、Glob、Grep而非shell等效命令(cat、sed、find、grep)。专用工具成本更低、更清晰。

Voice

语言风格

Direct, concrete, builder-to-builder. Name the file, function, command, and user-visible impact. No filler.
No em dashes. No AI vocabulary: delve, crucial, robust, comprehensive, nuanced, multifaceted. Never corporate or academic. Short paragraphs. End with what to do.
The user has context you do not. Cross-model agreement is a recommendation, not a decision. The user decides.
直接、具体,开发者对开发者的语气。明确文件名、函数、命令和对用户可见的影响。不要冗余内容。
不要使用破折号。不要使用AI词汇:delve、crucial、robust、comprehensive、nuanced、multifaceted。避免企业或学术风格。使用短段落。结尾说明下一步操作。
用户拥有你不知道的上下文。跨模型共识是建议,而非决策。最终由用户决定。

Completion Status Protocol

完成状态协议

When completing a skill workflow, report status using one of:
  • DONE — completed with evidence.
  • DONE_WITH_CONCERNS — completed, but list concerns.
  • BLOCKED — cannot proceed; state blocker and what was tried.
  • NEEDS_CONTEXT — missing info; state exactly what is needed.
Escalate after 3 failed attempts, uncertain security-sensitive changes, or scope you cannot verify. Format:
STATUS
,
REASON
,
ATTEMPTED
,
RECOMMENDATION
.
完成技能工作流时,使用以下状态之一报告:
  • DONE — 已完成并提供证据。
  • DONE_WITH_CONCERNS — 已完成,但列出关注点。
  • BLOCKED — 无法继续;说明阻塞原因和已尝试的操作。
  • NEEDS_CONTEXT — 缺少信息;明确说明需要的内容。
如果3次尝试失败、涉及不确定的安全敏感更改,或无法验证范围,则升级问题。格式:
STATUS
REASON
ATTEMPTED
RECOMMENDATION

Operational Self-Improvement

操作自我改进

Before completing, if you discovered a durable project quirk or command fix that would save 5+ minutes next time, log it:
bash
~/.claude/skills/gstack/bin/gstack-learnings-log '{"skill":"SKILL_NAME","type":"operational","key":"SHORT_KEY","insight":"DESCRIPTION","confidence":N,"source":"observed"}'
Do not log obvious facts or one-time transient errors.
完成前,如果发现持久的项目特性或命令修复可以在下次节省5分钟以上时间,请记录:
bash
~/.claude/skills/gstack/bin/gstack-learnings-log '{"skill":"SKILL_NAME","type":"operational","key":"SHORT_KEY","insight":"DESCRIPTION","confidence":N,"source":"observed"}'
不要记录明显的事实或一次性临时错误。

Telemetry (run last)

遥测(最后运行)

After workflow completion, log telemetry. Use skill
name:
from frontmatter. OUTCOME is success/error/abort/unknown.
PLAN MODE EXCEPTION — ALWAYS RUN: This command writes telemetry to
~/.gstack/analytics/
, matching preamble analytics writes.
Run this bash:
bash
_TEL_END=$(date +%s)
_TEL_DUR=$(( _TEL_END - _TEL_START ))
rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true
工作流完成后,记录遥测数据。使用前端部分的技能
name:
。OUTCOME为success/error/abort/unknown。
PLAN MODE EXCEPTION — ALWAYS RUN: 此命令将遥测数据写入
~/.gstack/analytics/
,与前置步骤中的分析写入一致。
运行以下bash命令:
bash
_TEL_END=$(date +%s)
_TEL_DUR=$(( _TEL_END - _TEL_START ))
rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true

Session timeline: record skill completion (local-only, never sent anywhere)

Session timeline: record skill completion (local-only, never sent anywhere)

~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"SKILL_NAME","event":"completed","branch":"'$(git branch --show-current 2>/dev/null || echo unknown)'","outcome":"OUTCOME","duration_s":"'"$_TEL_DUR"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null || true
~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"SKILL_NAME","event":"completed","branch":"'$(git branch --show-current 2>/dev/null || echo unknown)'","outcome":"OUTCOME","duration_s":"'"$_TEL_DUR"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null || true

Local analytics (gated on telemetry setting)

Local analytics (gated on telemetry setting)

if [ "$_TEL" != "off" ]; then echo '{"skill":"SKILL_NAME","duration_s":"'"$_TEL_DUR"'","outcome":"OUTCOME","browse":"USED_BROWSE","session":"'"$_SESSION_ID"'","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true fi
if [ "$_TEL" != "off" ]; then echo '{"skill":"SKILL_NAME","duration_s":"'"$_TEL_DUR"'","outcome":"OUTCOME","browse":"USED_BROWSE","session":"'"$_SESSION_ID"'","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true fi

Remote telemetry (opt-in, requires binary)

Remote telemetry (opt-in, requires binary)

if [ "$_TEL" != "off" ] && [ -x ~/.claude/skills/gstack/bin/gstack-telemetry-log ]; then ~/.claude/skills/gstack/bin/gstack-telemetry-log
--skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME"
--used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & fi

Replace `SKILL_NAME`, `OUTCOME`, and `USED_BROWSE` before running.
if [ "$_TEL" != "off" ] && [ -x ~/.claude/skills/gstack/bin/gstack-telemetry-log ]; then ~/.claude/skills/gstack/bin/gstack-telemetry-log
--skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME"
--used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & fi

运行前替换`SKILL_NAME`、`OUTCOME`和`USED_BROWSE`。

Plan Status Footer

计划状态页脚

In plan mode before ExitPlanMode: if the plan file lacks
## GSTACK REVIEW REPORT
, run
~/.claude/skills/gstack/bin/gstack-review-read
and append the standard runs/status/findings table. With
NO_REVIEWS
or empty, append a 5-row placeholder with verdict "NO REVIEWS YET — run
/autoplan
". If a richer report exists, skip.
PLAN MODE EXCEPTION — always allowed (it's the plan file).
在计划模式下、ExitPlanMode之前:如果计划文件缺少
## GSTACK REVIEW REPORT
,运行
~/.claude/skills/gstack/bin/gstack-review-read
并追加标准的运行/状态/发现表格。如果
NO_REVIEWS
或为空,追加5行占位符,结论为"NO REVIEWS YET — run
/autoplan
"。如果已有更详细的报告,则跳过此步骤。
PLAN MODE EXCEPTION — 始终允许(这是计划文件的操作)。

make-pdf: publication-quality PDFs from markdown

make-pdf:从Markdown生成出版级PDF

Turn
.md
files into PDFs that look like Faber & Faber essays: 1in margins, left-aligned body, Helvetica throughout, curly quotes and em dashes, optional cover page and clickable TOC, diagonal DRAFT watermark when you need it. Copy-paste from the PDF produces clean words, never "S a i l i n g".
On Linux, install
fonts-liberation
for correct rendering — Helvetica and Arial aren't present by default, and Liberation Sans is the standard metric-compatible fallback. CI and Docker builds install it automatically via Dockerfile.ci.
.md
文件转换为类似Faber & Faber出版社风格的PDF:1英寸边距、左对齐正文、全程使用Helvetica字体、弯引号和破折号、可选封面页和可点击目录、需要时添加斜向DRAFT水印。从PDF中复制粘贴会得到干净的文本,不会出现“S a i l i n g”这种碎片化情况。
在Linux系统上,安装
fonts-liberation
以确保正确渲染——默认情况下没有Helvetica和Arial字体,Liberation Sans是标准的 metric-compatible 替代字体。CI和Docker构建会通过Dockerfile.ci自动安装该字体。

MAKE-PDF SETUP (run this check BEFORE any make-pdf command)

MAKE-PDF 设置(运行任何make-pdf命令前先执行此检查)

bash
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
P=""
[ -n "$MAKE_PDF_BIN" ] && [ -x "$MAKE_PDF_BIN" ] && P="$MAKE_PDF_BIN"
[ -z "$P" ] && [ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf" ] && P="$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf"
[ -z "$P" ] && P="$HOME/.claude/skills/gstack/make-pdf/dist/pdf"
if [ -x "$P" ]; then
  echo "MAKE_PDF_READY: $P"
  alias _p_="$P"   # shellcheck alias helper (not exported)
  export P   # available as $P in subsequent blocks within the same skill invocation
else
  echo "MAKE_PDF_NOT_AVAILABLE (run './setup' in the gstack repo to build it)"
fi
If
MAKE_PDF_NOT_AVAILABLE
is printed: tell the user the binary is not built. Have them run
./setup
from the gstack repo, then retry.
If
MAKE_PDF_READY
is printed:
$P
is the binary path for the rest of the skill. Use
$P
(not an explicit path) so the skill body stays portable.
Core commands:
  • $P generate <input.md> [output.pdf]
    — render markdown to PDF (80% use case)
  • $P generate --cover --toc essay.md out.pdf
    — full publication layout
  • $P generate --watermark DRAFT memo.md draft.pdf
    — diagonal DRAFT watermark
  • $P preview <input.md>
    — render HTML and open in browser (fast iteration)
  • $P setup
    — verify browse + Chromium + pdftotext and run a smoke test
  • $P --help
    — full flag reference
Output contract:
  • stdout
    : ONLY the output path on success. One line.
  • stderr
    : progress (
    Rendering HTML... Generating PDF...
    ) unless
    --quiet
    .
  • Exit 0 success / 1 bad args / 2 render error / 3 Paged.js timeout / 4 browse unavailable.
bash
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
P=""
[ -n "$MAKE_PDF_BIN" ] && [ -x "$MAKE_PDF_BIN" ] && P="$MAKE_PDF_BIN"
[ -z "$P" ] && [ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf" ] && P="$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf"
[ -z "$P" ] && P="$HOME/.claude/skills/gstack/make-pdf/dist/pdf"
if [ -x "$P" ]; then
  echo "MAKE_PDF_READY: $P"
  alias _p_="$P"   # shellcheck alias helper (not exported)
  export P   # available as $P in subsequent blocks within the same skill invocation
else
  echo "MAKE_PDF_NOT_AVAILABLE (run './setup' in the gstack repo to build it)"
fi
如果输出
MAKE_PDF_NOT_AVAILABLE
:告知用户二进制文件未构建。让他们在gstack仓库中运行
./setup
,然后重试。
如果输出
MAKE_PDF_READY
$P
为技能后续使用的二进制文件路径。使用
$P
(而非显式路径)以保持技能主体的可移植性。
核心命令:
  • $P generate <input.md> [output.pdf]
    — 将Markdown渲染为PDF(80%的使用场景)
  • $P generate --cover --toc essay.md out.pdf
    — 完整出版布局
  • $P generate --watermark DRAFT memo.md draft.pdf
    — 添加斜向DRAFT水印
  • $P preview <input.md>
    — 渲染HTML并在浏览器中打开(快速迭代)
  • $P setup
    — 验证browse + Chromium + pdftotext并运行冒烟测试
  • $P --help
    — 完整的参数参考
输出约定:
  • stdout
    :仅在成功时输出路径,一行内容。
  • stderr
    :进度信息(
    Rendering HTML... Generating PDF...
    ),除非使用
    --quiet
    参数。
  • 退出码:0表示成功 / 1表示参数错误 / 2表示渲染错误 / 3表示Paged.js超时 / 4表示browse不可用。

Core patterns

核心使用模式

80% case — memo/letter

80%场景——备忘录/信函

One command, no flags. Gets a clean PDF with running header + page numbers
  • CONFIDENTIAL footer by default.
bash
$P generate letter.md                 # writes /tmp/letter.pdf
$P generate letter.md letter.pdf      # explicit output path
一个命令,无参数。默认生成包含页眉+页码+CONFIDENTIAL页脚的干净PDF。
bash
$P generate letter.md                 # 写入/tmp/letter.pdf
$P generate letter.md letter.pdf      # 显式指定输出路径

Publication mode — cover + TOC + chapter breaks

出版模式——封面+目录+章节分页

bash
$P generate --cover --toc --author "Garry Tan" --title "On Horizons" \
  essay.md essay.pdf
Each top-level H1 in the markdown starts a new page. Disable with
--no-chapter-breaks
for memos that happen to have multiple H1s.
bash
$P generate --cover --toc --author "Garry Tan" --title "On Horizons" \
  essay.md essay.pdf
Markdown中的每个顶级H1标题会启动新页面。对于包含多个H1的备忘录,可使用
--no-chapter-breaks
禁用此功能。

Draft-stage watermark

草稿阶段水印

bash
$P generate --watermark DRAFT memo.md draft.pdf
Diagonal 10% opacity DRAFT across every page. When the draft is final, drop the flag and regenerate.
bash
$P generate --watermark DRAFT memo.md draft.pdf
在每一页添加10%透明度的斜向DRAFT水印。草稿完成后,移除该参数并重新生成。

Fast iteration via preview

通过预览快速迭代

bash
$P preview essay.md
Renders HTML with the same print CSS and opens it in your browser. Refresh as you edit the markdown. Skip the PDF round trip until you're ready.
bash
$P preview essay.md
使用相同的打印CSS渲染HTML并在浏览器中打开。编辑Markdown后刷新页面即可。在准备好之前跳过PDF生成步骤。

Brand-free (no CONFIDENTIAL footer)

无品牌标识(无CONFIDENTIAL页脚)

bash
$P generate --no-confidential memo.md memo.pdf
bash
$P generate --no-confidential memo.md memo.pdf

Common flags

常用参数

Page layout:
  --margins <dim>            1in (default) | 72pt | 2.54cm | 25mm
  --page-size letter|a4|legal

Structure:
  --cover                    Cover page (title, author, date, hairline rule)
  --toc                      Clickable TOC with page numbers
  --no-chapter-breaks        Don't start a new page at every H1

Branding:
  --watermark <text>         Diagonal watermark ("DRAFT", "CONFIDENTIAL")
  --header-template <html>   Custom running header
  --footer-template <html>   Custom footer (mutex with --page-numbers)
  --no-confidential          Suppress the CONFIDENTIAL right-footer

Output:
  --page-numbers             "N of M" footer (default on)
  --tagged                   Accessible PDF (default on)
  --outline                  PDF bookmarks from headings (default on)
  --quiet                    Suppress progress on stderr
  --verbose                  Per-stage timings

Network:
  --allow-network            Fetch external images. Off by default
                             (blocks tracking pixels).

Metadata:
  --title "..."              Document title (defaults to first H1)
  --author "..."             Author for cover + PDF metadata
  --date "..."               Date for cover (defaults to today)
页面布局:
  --margins <dim>            1英寸(默认)| 72pt | 2.54cm | 25mm
  --page-size letter|a4|legal

结构:
  --cover                    封面页(标题、作者、日期、细线条)
  --toc                      带页码的可点击目录
  --no-chapter-breaks        不在每个H1标题处启动新页面

品牌标识:
  --watermark <text>         斜向水印("DRAFT"、"CONFIDENTIAL")
  --header-template <html>   自定义页眉
  --footer-template <html>   自定义页脚(与--page-numbers互斥)
  --no-confidential          禁用右下角的CONFIDENTIAL页脚

输出:
  --page-numbers             "N of M"页脚(默认开启)
  --tagged                   无障碍PDF(默认开启)
  --outline                  从标题生成PDF书签(默认开启)
  --quiet                    禁止在stderr输出进度信息
  --verbose                  输出每个阶段的计时信息

网络:
  --allow-network            获取外部图片。默认关闭
                             (阻止跟踪像素)。

元数据:
  --title "..."              文档标题(默认使用第一个H1)
  --author "..."              封面和PDF元数据中的作者
  --date "..."               封面中的日期(默认为今天)

When Claude should run it

Claude何时运行此工具

Watch for markdown-to-PDF intent. Any of these patterns → run
$P generate
:
  • "Can you make this markdown a PDF"
  • "Export it as a PDF"
  • "Turn this letter into a PDF"
  • "I need a PDF of the essay"
  • "Print this as a PDF for me"
If the user has a
.md
file open and says "make it look nice", propose
$P generate --cover --toc
and ask before running.
留意Markdown转PDF的意图。出现以下任何模式时,运行
$P generate
  • "Can you make this markdown a PDF"
  • "Export it as a PDF"
  • "Turn this letter into a PDF"
  • "I need a PDF of the essay"
  • "Print this as a PDF for me"
如果用户打开了一个
.md
文件并说"make it look nice",建议使用
$P generate --cover --toc
并在运行前询问用户。

Debugging

调试

  • Output looks empty / blank → check browse daemon is running:
    $B status
    .
  • Fragmented text on copy-paste → highlight.js output (Phase 4). Retry with
    --no-syntax
    once that flag exists. For now, remove fenced code blocks and regenerate.
  • Paged.js timeout → probably no headings in the markdown. Drop
    --toc
    .
  • External image missing → add
    --allow-network
    (understand you're giving the markdown file permission to fetch from its image URLs).
  • Generated PDF too tall/wide →
    --page-size a4
    or
    --margins 0.75in
    .
  • 输出为空/空白 → 检查browse守护进程是否运行:
    $B status
  • 复制粘贴时文本碎片化 → highlight.js输出(第4阶段)。一旦
    --no-syntax
    参数可用,重试时使用该参数。目前,移除代码块并重新生成。
  • Paged.js超时 → 可能是Markdown中没有标题。移除
    --toc
    参数。
  • 外部图片缺失 → 添加
    --allow-network
    参数(注意这会授予Markdown文件从其图片URL获取内容的权限)。
  • 生成的PDF过高/过宽 → 使用
    --page-size a4
    --margins 0.75in

Output contract

输出约定

stdout: /tmp/letter.pdf          ← just the path, one line
stderr: Rendering HTML...        ← progress spinner (unless --quiet)
        Generating PDF...
        Done in 1.5s. 43 words · 22KB · /tmp/letter.pdf

exit code: 0 success / 1 bad args / 2 render error / 3 Paged.js timeout
           / 4 browse unavailable
Capture the path:
PDF=$($P generate letter.md)
— then use
$PDF
.
stdout: /tmp/letter.pdf          ← 仅输出路径,一行
stderr: Rendering HTML...        ← 进度提示(除非使用--quiet)
        Generating PDF...
        Done in 1.5s. 43 words · 22KB · /tmp/letter.pdf

exit code: 0 success / 1 bad args / 2 render error / 3 Paged.js timeout
           / 4 browse unavailable
捕获路径:
PDF=$($P generate letter.md)
— 然后使用
$PDF