handoff-cli 0.3.5__tar.gz → 0.3.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- handoff_cli-0.3.6/Makefile +33 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/PKG-INFO +1 -1
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/commands/new.py +15 -3
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/commands/resume.py +20 -2
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/commands/run.py +13 -4
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/main.py +5 -3
- handoff_cli-0.3.6/cli/skills/handoff-codex/SKILL.md +52 -0
- handoff_cli-0.3.6/cli/skills/handoff-ds/SKILL.md +52 -0
- handoff_cli-0.3.6/cli/skills/handoff-ds.toml +63 -0
- handoff_cli-0.3.6/cli/skills/handoff-opus/SKILL.md +52 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/pyproject.toml +1 -1
- handoff_cli-0.3.5/Makefile +0 -7
- handoff_cli-0.3.5/cli/skills/handoff-codex/SKILL.md +0 -83
- handoff_cli-0.3.5/cli/skills/handoff-ds/SKILL.md +0 -83
- handoff_cli-0.3.5/cli/skills/handoff-ds.toml +0 -52
- handoff_cli-0.3.5/cli/skills/handoff-opus/SKILL.md +0 -83
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/.github/workflows/publish.yml +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/.gitignore +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/CLAUDE.md +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/README.md +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/README.zh-CN.md +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/__init__.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/backend.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/backend_types.yaml +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/commands/__init__.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/commands/env.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/commands/init.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/commands/list.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/commands/tail.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/config.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/core.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/jsonl_parser.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/jsonl_viewer.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/stream.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/tui.py +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/cli/user_config_template.yaml +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/docs/TODO.md +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/docs/assets/claude-code.jpg +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/docs/assets/codex.jpg +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/docs/assets/handoff-hero.jpg +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/docs/assets/list-tui.jpg +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/docs/assets/parallel.jpg +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/docs/assets/shell.jpg +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/docs/assets/tail.jpg +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/docs/cli-reference.zh-CN.md +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/docs/configuration.zh-CN.md +0 -0
- {handoff_cli-0.3.5 → handoff_cli-0.3.6}/docs/design.zh-CN.md +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
.PHONY: render skills
|
|
2
|
+
|
|
3
|
+
render: ## Preview PyPI long description rendering
|
|
4
|
+
pip install -q "readme_renderer[md]" 2>/dev/null
|
|
5
|
+
python -m readme_renderer README.md > /tmp/handoff-pypi-preview.html
|
|
6
|
+
@echo "✅ /tmp/handoff-pypi-preview.html ($(shell wc -c < /tmp/handoff-pypi-preview.html | tr -d ' ') bytes)"
|
|
7
|
+
open /tmp/handoff-pypi-preview.html
|
|
8
|
+
|
|
9
|
+
# ── skill 文档同步 ──────────────────────────────────────────────────
|
|
10
|
+
# handoff-ds/SKILL.md 是主文档(master),只改它。
|
|
11
|
+
# 它的 frontmatter(顶部的 `---...---` 块)不同步;其下的正文会被复制到
|
|
12
|
+
# 其它 backend 的 SKILL.md,并把 backend 名/缩写替换成对应值。占位符在
|
|
13
|
+
# 「构建时」由 sed 替换,落盘的都是具体值——LLM 永远读不到占位符。
|
|
14
|
+
SKILLS := cli/skills
|
|
15
|
+
MASTER := $(SKILLS)/handoff-ds/SKILL.md
|
|
16
|
+
|
|
17
|
+
skills: ## 把 handoff-ds/SKILL.md 正文同步到其它 backend 的 SKILL.md
|
|
18
|
+
@$(call sync_skill,handoff-codex,codex,cx)
|
|
19
|
+
@$(call sync_skill,handoff-opus,opus,op)
|
|
20
|
+
@echo "done."
|
|
21
|
+
|
|
22
|
+
# $(1)=目标目录 $(2)=backend 名 $(3)=run_id 缩写
|
|
23
|
+
define sync_skill
|
|
24
|
+
target="$(SKILLS)/$(1)/SKILL.md"; \
|
|
25
|
+
tmp=$$(mktemp); \
|
|
26
|
+
awk '{print} /^---[[:space:]]*$$/{n++; if(n==2) exit}' "$$target" > "$$tmp"; \
|
|
27
|
+
awk 'body{print} /^---[[:space:]]*$$/{n++; if(n==2) body=1}' "$(MASTER)" \
|
|
28
|
+
| sed -e 's/deepseek/$(2)/g' \
|
|
29
|
+
-e 's/handoff-ds/handoff-$(2)/g' \
|
|
30
|
+
-e 's/0613-ds-/0613-$(3)-/g' >> "$$tmp"; \
|
|
31
|
+
mv "$$tmp" "$$target"; \
|
|
32
|
+
echo "synced $$target (backend=$(2))";
|
|
33
|
+
endef
|
|
@@ -4,9 +4,10 @@ Pre-allocates a run_id and returns the canonical .prompt.md path so the caller
|
|
|
4
4
|
can write the prompt directly to its final archive location before dispatching.
|
|
5
5
|
|
|
6
6
|
Usage:
|
|
7
|
-
handoff new --backend <name> [--slug <slug>]
|
|
7
|
+
handoff new --backend <name> [--slug <slug>] [--write]
|
|
8
8
|
|
|
9
|
-
Stdout: one line — absolute path to the .prompt.md file
|
|
9
|
+
Stdout: one line — absolute path to the .prompt.md file.
|
|
10
|
+
By default the file is not created. With --write, stdin is written to the file.
|
|
10
11
|
"""
|
|
11
12
|
|
|
12
13
|
from __future__ import annotations
|
|
@@ -26,9 +27,10 @@ from ..config import Config
|
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
def cmd_new(argv: list[str], config: Config):
|
|
29
|
-
"""handoff new --backend <name> [--slug <slug>]"""
|
|
30
|
+
"""handoff new --backend <name> [--slug <slug>] [--write]"""
|
|
30
31
|
backend_arg = ""
|
|
31
32
|
slug_arg = ""
|
|
33
|
+
write_prompt = False
|
|
32
34
|
|
|
33
35
|
i = 0
|
|
34
36
|
while i < len(argv):
|
|
@@ -49,6 +51,8 @@ def cmd_new(argv: list[str], config: Config):
|
|
|
49
51
|
slug_arg = argv[i]
|
|
50
52
|
elif a.startswith("--slug="):
|
|
51
53
|
slug_arg = a.split("=", 1)[1]
|
|
54
|
+
elif a == "--write":
|
|
55
|
+
write_prompt = True
|
|
52
56
|
elif a in ("-h", "--help"):
|
|
53
57
|
from ..main import usage
|
|
54
58
|
usage()
|
|
@@ -85,4 +89,12 @@ def cmd_new(argv: list[str], config: Config):
|
|
|
85
89
|
run_id = f"{mmdd}-{b2}-{seq_code}-{clean_slug}"
|
|
86
90
|
prompt_path = os.path.join(TASKS_DIR, f"{run_id}.prompt.md")
|
|
87
91
|
|
|
92
|
+
if write_prompt:
|
|
93
|
+
if sys.stdin.isatty():
|
|
94
|
+
print("handoff new: --write requires prompt text on stdin", file=sys.stderr)
|
|
95
|
+
sys.exit(2)
|
|
96
|
+
os.makedirs(os.path.dirname(prompt_path), exist_ok=True)
|
|
97
|
+
with open(prompt_path, "w") as f:
|
|
98
|
+
f.write(sys.stdin.read())
|
|
99
|
+
|
|
88
100
|
print(prompt_path)
|
|
@@ -27,7 +27,7 @@ from ..config import Config
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def cmd_resume(argv: list[str], config: Config):
|
|
30
|
-
"""handoff resume [<run-id|seq>] [--backend <name>] [--pro] [--cwd <dir>]
|
|
30
|
+
"""handoff resume [<run-id|seq>] [--backend <name>] [--slug <slug>] [--pro] [--cwd <dir>]
|
|
31
31
|
[--verbose] [(<input-file|-> | --text <prompt...>)]."""
|
|
32
32
|
# Pre-scan --verbose so it works regardless of position (e.g. after --text).
|
|
33
33
|
verbose = "--verbose" in argv
|
|
@@ -36,6 +36,7 @@ def cmd_resume(argv: list[str], config: Config):
|
|
|
36
36
|
pro = False
|
|
37
37
|
cwd = ""
|
|
38
38
|
backend_arg = ""
|
|
39
|
+
slug_arg = ""
|
|
39
40
|
selector = ""
|
|
40
41
|
input_src = ""
|
|
41
42
|
text_mode = False
|
|
@@ -61,6 +62,14 @@ def cmd_resume(argv: list[str], config: Config):
|
|
|
61
62
|
backend_arg = filtered[i]
|
|
62
63
|
elif a.startswith("--backend="):
|
|
63
64
|
backend_arg = a.split("=", 1)[1]
|
|
65
|
+
elif a == "--slug":
|
|
66
|
+
i += 1
|
|
67
|
+
if i >= len(filtered):
|
|
68
|
+
print("handoff resume: --slug requires a value", file=sys.stderr)
|
|
69
|
+
sys.exit(2)
|
|
70
|
+
slug_arg = filtered[i]
|
|
71
|
+
elif a.startswith("--slug="):
|
|
72
|
+
slug_arg = a.split("=", 1)[1]
|
|
64
73
|
elif a == "--text":
|
|
65
74
|
text_mode = True
|
|
66
75
|
if input_src:
|
|
@@ -159,7 +168,16 @@ def cmd_resume(argv: list[str], config: Config):
|
|
|
159
168
|
# Non-interactive: dispatch a new turn through the run pipeline.
|
|
160
169
|
conn.close()
|
|
161
170
|
from .run import _execute
|
|
162
|
-
_execute(
|
|
171
|
+
_execute(
|
|
172
|
+
cwd,
|
|
173
|
+
prompt_text,
|
|
174
|
+
backend_name,
|
|
175
|
+
pro,
|
|
176
|
+
config,
|
|
177
|
+
resume_session_id=session_id,
|
|
178
|
+
slug=slug_arg or "resume",
|
|
179
|
+
verbose=verbose,
|
|
180
|
+
)
|
|
163
181
|
|
|
164
182
|
|
|
165
183
|
def _resume_interactive(config: Config, backend_name: str, session_id: str, cwd: str, pro: bool, verbose: bool = False):
|
|
@@ -40,7 +40,7 @@ def _is_adopted_path(input_src: str) -> bool:
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
def cmd_run(argv: list[str], config: Config):
|
|
43
|
-
"""handoff run [--backend <name>] [--cwd <dir>] [--pro] [--verbose] (<input-file|-> | --text <prompt...>)."""
|
|
43
|
+
"""handoff run [--backend <name>] [--cwd <dir>] [--slug <slug>] [--pro] [--verbose] (<input-file|-> | --text <prompt...>)."""
|
|
44
44
|
# Pre-scan --verbose so it works regardless of position (e.g. after --text).
|
|
45
45
|
verbose = "--verbose" in argv
|
|
46
46
|
filtered = [a for a in argv if a != "--verbose"]
|
|
@@ -48,6 +48,7 @@ def cmd_run(argv: list[str], config: Config):
|
|
|
48
48
|
pro = False
|
|
49
49
|
cwd = ""
|
|
50
50
|
backend_arg = ""
|
|
51
|
+
slug_arg = ""
|
|
51
52
|
input_src = ""
|
|
52
53
|
text_mode = False
|
|
53
54
|
text_parts = []
|
|
@@ -71,6 +72,14 @@ def cmd_run(argv: list[str], config: Config):
|
|
|
71
72
|
backend_arg = filtered[i]
|
|
72
73
|
elif a.startswith("--backend="):
|
|
73
74
|
backend_arg = a.split("=", 1)[1]
|
|
75
|
+
elif a == "--slug":
|
|
76
|
+
i += 1
|
|
77
|
+
if i >= len(filtered):
|
|
78
|
+
print("handoff run: --slug requires a value", file=sys.stderr)
|
|
79
|
+
sys.exit(2)
|
|
80
|
+
slug_arg = filtered[i]
|
|
81
|
+
elif a.startswith("--slug="):
|
|
82
|
+
slug_arg = a.split("=", 1)[1]
|
|
74
83
|
elif a == "--text":
|
|
75
84
|
text_mode = True
|
|
76
85
|
if input_src:
|
|
@@ -130,10 +139,10 @@ def cmd_run(argv: list[str], config: Config):
|
|
|
130
139
|
if not prompt_text:
|
|
131
140
|
print("handoff run: --text requires a non-empty value", file=sys.stderr)
|
|
132
141
|
sys.exit(2)
|
|
133
|
-
slug = "from-text"
|
|
142
|
+
slug = slug_arg or "from-text"
|
|
134
143
|
elif input_src == "-" or (not input_src and not sys.stdin.isatty()):
|
|
135
144
|
prompt_text = sys.stdin.read()
|
|
136
|
-
slug = "from-stdin"
|
|
145
|
+
slug = slug_arg or "from-stdin"
|
|
137
146
|
elif input_src:
|
|
138
147
|
if not os.path.isfile(input_src):
|
|
139
148
|
print(f"handoff run: input file not found: {input_src}", file=sys.stderr)
|
|
@@ -164,7 +173,7 @@ def cmd_run(argv: list[str], config: Config):
|
|
|
164
173
|
else:
|
|
165
174
|
with open(input_src) as f:
|
|
166
175
|
prompt_text = f.read()
|
|
167
|
-
slug = "from-file"
|
|
176
|
+
slug = slug_arg or "from-file"
|
|
168
177
|
else:
|
|
169
178
|
print("handoff run: input file required, or use --text <prompt...> / pipe via '-'", file=sys.stderr)
|
|
170
179
|
sys.exit(2)
|
|
@@ -12,10 +12,10 @@ def usage(config=None):
|
|
|
12
12
|
handoff --help
|
|
13
13
|
handoff env
|
|
14
14
|
handoff init [-y|--yes]
|
|
15
|
-
handoff new --backend <name> [--slug <slug>]
|
|
15
|
+
handoff new --backend <name> [--slug <slug>] [--write]
|
|
16
16
|
handoff list|ls [--uuid] [--cwd]
|
|
17
|
-
handoff run [--backend <name>] [--cwd <dir>] [--pro] [--verbose] (<input-file|-> | --text <prompt...>)
|
|
18
|
-
handoff resume [<run-id|seq>] [--pro] [--cwd <dir>] [--verbose] [(<input-file|-> | --text <prompt...>)]
|
|
17
|
+
handoff run [--backend <name>] [--cwd <dir>] [--slug <slug>] [--pro] [--verbose] (<input-file|-> | --text <prompt...>)
|
|
18
|
+
handoff resume [<run-id|seq>] [--slug <slug>] [--pro] [--cwd <dir>] [--verbose] [(<input-file|-> | --text <prompt...>)]
|
|
19
19
|
handoff tail [<run-id|seq>]
|
|
20
20
|
|
|
21
21
|
handoff env — print config / data paths (works even with broken config)
|
|
@@ -29,6 +29,8 @@ def usage(config=None):
|
|
|
29
29
|
Run ids: <mmdd>-<backend2>-<SEQ_CODE>-<slug> (e.g. 0611-ds-03-fix-auth)
|
|
30
30
|
--cwd defaults to the current directory of the calling process.
|
|
31
31
|
--backend picks a backend (default: first entry in config.yaml backends).
|
|
32
|
+
--slug sets the semantic suffix in generated run ids.
|
|
33
|
+
--write on `handoff new` writes stdin to the pre-allocated .prompt.md file.
|
|
32
34
|
--pro uses the backend's pro_model. A resume stays on its original backend."""
|
|
33
35
|
)
|
|
34
36
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: handoff-codex
|
|
3
|
+
description: 向 Codex (GPT-5.5) 咨询复杂问题 / 要第二意见 / 派发需要强推理的任务。后台运行,完成后自动通知。支持并行多任务,支持续接(resume)上次会话继续派发后续任务。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# handoff-codex Skill
|
|
7
|
+
|
|
8
|
+
<interaction_contract>
|
|
9
|
+
This skill is executed by Claude Code (an AI agent). The rules below are BINDING — follow them exactly; do not simplify or reinterpret.
|
|
10
|
+
## 命令模板(照抄,勿改结构)
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
handoff run --backend codex --slug <≤3个英文单词的任务助记词> - <<'__HF_EOF__'
|
|
14
|
+
[prompt 内容]
|
|
15
|
+
__HF_EOF__
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
必须用 `run_in_background: true` 启动——handoff 耗时 2~20 分钟,前台会阻塞整个会话。
|
|
19
|
+
|
|
20
|
+
**关键规则:**
|
|
21
|
+
- `--slug` 只写≤3个英文单词、`-` 分隔的语义助记词(如 `fix-auth`);禁止日期/时间戳/随机数/UUID/计数器,唯一性由 `handoff run` 自动分配的 seq 保证。
|
|
22
|
+
- heredoc 界定符固定用 `__HF_EOF__`,prompt 原样粘贴、不转义。
|
|
23
|
+
- 不要自己拼任务文件名,也不要用 `> RESULT 2> OUT` 重定向——handoff 自己管命名和落盘。
|
|
24
|
+
- 用户提到 `pro`(或要求更强/专业模型处理复杂任务)时,在 `handoff run` 后加 `--pro`。
|
|
25
|
+
- 回显任何 home 下的任务路径时,缩写成 `~/.handoff/...`,不要暴露 `/Users/<name>/...`。
|
|
26
|
+
|
|
27
|
+
启动后从 **stdout** 捕获唯一有用的一行 `RESULT=<任务路径>`(如 `~/.handoff/tasks/0613-cx-03-fix-auth.result.md`),缩写成 `~/.handoff/...` 后回显给用户。**这条路径的文件名主干(去掉目录和 `.result.md` 后缀)就是本次 run_id**(上例 → `0613-cx-03-fix-auth`);记住它,用户要求"继续上次/接着再做 X"时靠它 `resume`。
|
|
28
|
+
|
|
29
|
+
其余不要读:进度信息在 **stderr**(Claude Code 的 shell view 自动实时显示,别读进上下文);同名 `.out.txt` 是进度日志,仅诊断(无结果/超时)时才 `tail -f`/`Read`;同名 `.prompt.md` 就是你刚发的内容。
|
|
30
|
+
|
|
31
|
+
收到完成通知后,用 `Read` 读对应的 `.result.md` 汇报,**不要**再读后台输出(结果已在文件里,重复读只会把进度噪音吃进上下文)。`.result.md` 为空或异常时才读 `.out.txt` 诊断。
|
|
32
|
+
</interaction_contract>
|
|
33
|
+
|
|
34
|
+
## 多任务
|
|
35
|
+
|
|
36
|
+
- **并行**:在**同一条消息**里发出多个 `run_in_background: true` 的 Bash 调用,各自用 `handoff run --slug ... - <<'__HF_EOF__'` 派发不同 prompt(seq 自动递增),各自从 stdout 捕获 `RESULT=`,分别等通知、分别读 `.result.md` 汇报。
|
|
37
|
+
- **串行**:等上一个的完成通知到达、读并汇报后,再启动下一个。
|
|
38
|
+
|
|
39
|
+
## 续接上次会话(resume 续派)
|
|
40
|
+
|
|
41
|
+
要保留某次任务的上下文继续,而非开新会话:用 `resume` 替代 `run`,继续通过 heredoc/stdin 传入后续任务;其余约定(后台、捕获新 `RESULT=`、读 `.result.md`)完全相同:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
handoff resume <run_id> --backend codex --slug <任务助记词> - <<'__HF_EOF__'
|
|
45
|
+
[后续任务内容]
|
|
46
|
+
__HF_EOF__
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- `<run_id>` 用该会话**首次**任务的 run_id(上面那个文件名主干);它是稳定句柄,每轮续接都用它,不要追每轮新生成的 run_id。
|
|
50
|
+
- **必须带后续 prompt**:不带 heredoc、`-`、输入文件或 `--text` 的 `resume <run_id>` 是交互式重开,后台会卡死。
|
|
51
|
+
- 续接默认只继承 backend;原会话用过 `--pro` 的,续接要再次带上才沿用 pro_model。
|
|
52
|
+
- 不确定用户指哪次任务时,报候选 run_id + 摘要让其确认,别猜。
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: handoff-ds
|
|
3
|
+
description: 把执行性编码/调查任务整包交给 DeepSeek 后台执行,省主会话额度。后台运行,完成后自动通知。支持并行多任务,支持续接(resume)上次会话继续派发后续任务。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# handoff-ds Skill
|
|
7
|
+
|
|
8
|
+
<interaction_contract>
|
|
9
|
+
This skill is executed by Claude Code (an AI agent). The rules below are BINDING — follow them exactly; do not simplify or reinterpret.
|
|
10
|
+
## 命令模板(照抄,勿改结构)
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
handoff run --backend deepseek --slug <≤3个英文单词的任务助记词> - <<'__HF_EOF__'
|
|
14
|
+
[prompt 内容]
|
|
15
|
+
__HF_EOF__
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
必须用 `run_in_background: true` 启动——handoff 耗时 2~20 分钟,前台会阻塞整个会话。
|
|
19
|
+
|
|
20
|
+
**关键规则:**
|
|
21
|
+
- `--slug` 只写≤3个英文单词、`-` 分隔的语义助记词(如 `fix-auth`);禁止日期/时间戳/随机数/UUID/计数器,唯一性由 `handoff run` 自动分配的 seq 保证。
|
|
22
|
+
- heredoc 界定符固定用 `__HF_EOF__`,prompt 原样粘贴、不转义。
|
|
23
|
+
- 不要自己拼任务文件名,也不要用 `> RESULT 2> OUT` 重定向——handoff 自己管命名和落盘。
|
|
24
|
+
- 用户提到 `pro`(或要求更强/专业模型处理复杂任务)时,在 `handoff run` 后加 `--pro`。
|
|
25
|
+
- 回显任何 home 下的任务路径时,缩写成 `~/.handoff/...`,不要暴露 `/Users/<name>/...`。
|
|
26
|
+
|
|
27
|
+
启动后从 **stdout** 捕获唯一有用的一行 `RESULT=<任务路径>`(如 `~/.handoff/tasks/0613-ds-03-fix-auth.result.md`),缩写成 `~/.handoff/...` 后回显给用户。**这条路径的文件名主干(去掉目录和 `.result.md` 后缀)就是本次 run_id**(上例 → `0613-ds-03-fix-auth`);记住它,用户要求"继续上次/接着再做 X"时靠它 `resume`。
|
|
28
|
+
|
|
29
|
+
其余不要读:进度信息在 **stderr**(Claude Code 的 shell view 自动实时显示,别读进上下文);同名 `.out.txt` 是进度日志,仅诊断(无结果/超时)时才 `tail -f`/`Read`;同名 `.prompt.md` 就是你刚发的内容。
|
|
30
|
+
|
|
31
|
+
收到完成通知后,用 `Read` 读对应的 `.result.md` 汇报,**不要**再读后台输出(结果已在文件里,重复读只会把进度噪音吃进上下文)。`.result.md` 为空或异常时才读 `.out.txt` 诊断。
|
|
32
|
+
</interaction_contract>
|
|
33
|
+
|
|
34
|
+
## 多任务
|
|
35
|
+
|
|
36
|
+
- **并行**:在**同一条消息**里发出多个 `run_in_background: true` 的 Bash 调用,各自用 `handoff run --slug ... - <<'__HF_EOF__'` 派发不同 prompt(seq 自动递增),各自从 stdout 捕获 `RESULT=`,分别等通知、分别读 `.result.md` 汇报。
|
|
37
|
+
- **串行**:等上一个的完成通知到达、读并汇报后,再启动下一个。
|
|
38
|
+
|
|
39
|
+
## 续接上次会话(resume 续派)
|
|
40
|
+
|
|
41
|
+
要保留某次任务的上下文继续,而非开新会话:用 `resume` 替代 `run`,继续通过 heredoc/stdin 传入后续任务;其余约定(后台、捕获新 `RESULT=`、读 `.result.md`)完全相同:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
handoff resume <run_id> --backend deepseek --slug <任务助记词> - <<'__HF_EOF__'
|
|
45
|
+
[后续任务内容]
|
|
46
|
+
__HF_EOF__
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- `<run_id>` 用该会话**首次**任务的 run_id(上面那个文件名主干);它是稳定句柄,每轮续接都用它,不要追每轮新生成的 run_id。
|
|
50
|
+
- **必须带后续 prompt**:不带 heredoc、`-`、输入文件或 `--text` 的 `resume <run_id>` 是交互式重开,后台会卡死。
|
|
51
|
+
- 续接默认只继承 backend;原会话用过 `--pro` 的,续接要再次带上才沿用 pro_model。
|
|
52
|
+
- 不确定用户指哪次任务时,报候选 run_id + 摘要让其确认,别猜。
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name = "handoff-ds"
|
|
2
|
+
description = "Delegate one-shot analysis, review, and bounded coding tasks through handoff. Before invoking this agent, the caller must: (1) run `handoff new --backend deepseek --slug <slug> --write <<'__HF_EOF__' ... __HF_EOF__` to create the canonical .prompt.md file and capture its printed path, (2) send this agent only `PROMPT_FILE=~/.handoff/tasks/<run-id>.prompt.md` plus any pro/resume hint; do not expose `/Users/<name>/...` when the path is under home, and do not include the raw delegated prompt in the subagent message. Slugs must be semantic only, with no timestamps, random numbers, UUIDs, or counters. Supports hints like 'handoff-ds (pro)', 'handoff-ds pro', '专业模式', '更强模型'."
|
|
3
|
+
model = "gpt-5.4-mini"
|
|
4
|
+
model_reasoning_effort = "low"
|
|
5
|
+
web_search = "disabled"
|
|
6
|
+
features = { shell_tool = true, multi_agent = false }
|
|
7
|
+
|
|
8
|
+
developer_instructions = """
|
|
9
|
+
|
|
10
|
+
你是 `handoff` 命令启动器。不要分析任务,不要回答任务内容。
|
|
11
|
+
|
|
12
|
+
输入格式:
|
|
13
|
+
- 必须包含 `PROMPT_FILE=<path>`。
|
|
14
|
+
- `<path>` 是已经存在的 `.prompt.md` 文件路径,通常是 `~/.handoff/tasks/<run-id>.prompt.md`。
|
|
15
|
+
- 输入可能包含 `pro`、`专业模式`、`更强模型`,表示使用 `--pro`。
|
|
16
|
+
- 输入可能包含 `resume`、`继续`、`接着刚才`,表示续接上次任务。
|
|
17
|
+
|
|
18
|
+
第一条动作必须调用 `functions.exec_command`。不要先发 commentary。
|
|
19
|
+
|
|
20
|
+
只允许执行下面四种命令之一:
|
|
21
|
+
|
|
22
|
+
普通任务:
|
|
23
|
+
```bash
|
|
24
|
+
handoff run --backend deepseek <PROMPT_FILE> >/dev/null
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
pro 任务:
|
|
28
|
+
```bash
|
|
29
|
+
handoff run --backend deepseek --pro <PROMPT_FILE> >/dev/null
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
resume 任务:
|
|
33
|
+
```bash
|
|
34
|
+
handoff resume <run_id> --backend deepseek <PROMPT_FILE> >/dev/null
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
resume + pro:
|
|
38
|
+
```bash
|
|
39
|
+
handoff resume <run_id> --backend deepseek --pro <PROMPT_FILE> >/dev/null
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
规则:
|
|
43
|
+
- `<PROMPT_FILE>` 必须直接来自输入里的 `PROMPT_FILE=`。
|
|
44
|
+
- 如果路径以 `~` 开头,命令里直接使用这个 `~` 路径。
|
|
45
|
+
- 不要读取 `<PROMPT_FILE>`。禁止 `cat`、`sed`、`head`、`tail`、heredoc、命令替换。
|
|
46
|
+
- 不要运行其它命令。不要写文件。
|
|
47
|
+
- 必须前台阻塞执行。禁止 `&`、`nohup`、`disown`、`setsid`、`tmux`、`screen`。
|
|
48
|
+
- 如果 exec 返回仍在运行的 session,继续等待直到进程退出。
|
|
49
|
+
|
|
50
|
+
resume 的 `<run_id>`:
|
|
51
|
+
- 如果本会话之前最终回答过 `RESULT=.../<id>.result.md`,`<run_id>` 就是 `<id>`。
|
|
52
|
+
- 如果没有可用的上次 `RESULT=`,即使输入说 resume,也按普通任务执行 `handoff run`。
|
|
53
|
+
|
|
54
|
+
最终回答:
|
|
55
|
+
- 命令输出里如果有 `RESULT=<path>`,最终回答必须只包含最后一行 `RESULT=...`。
|
|
56
|
+
- 如果 `RESULT=` 路径在用户 home 下,回答前缩写成 `~/.handoff/...`。
|
|
57
|
+
- 不要总结,不要解释,不要读取 result 文件。
|
|
58
|
+
- 如果命令退出码非 0 但输出里有 `RESULT=...`,仍然只回答 `RESULT=...`。
|
|
59
|
+
- 只有完全没有 `RESULT=` 时,才用一句话说明失败。
|
|
60
|
+
|
|
61
|
+
如果没有可用 shell 工具,最终只回答 `HF_AGENT_EXEC_TOOL_UNAVAILABLE`。
|
|
62
|
+
|
|
63
|
+
"""
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: handoff-opus
|
|
3
|
+
description: 把关键决策/验收类任务交给 Claude Opus 执行。后台运行,完成后自动通知。支持并行多任务,支持续接(resume)上次会话继续派发后续任务。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# handoff-opus Skill
|
|
7
|
+
|
|
8
|
+
<interaction_contract>
|
|
9
|
+
This skill is executed by Claude Code (an AI agent). The rules below are BINDING — follow them exactly; do not simplify or reinterpret.
|
|
10
|
+
## 命令模板(照抄,勿改结构)
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
handoff run --backend opus --slug <≤3个英文单词的任务助记词> - <<'__HF_EOF__'
|
|
14
|
+
[prompt 内容]
|
|
15
|
+
__HF_EOF__
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
必须用 `run_in_background: true` 启动——handoff 耗时 2~20 分钟,前台会阻塞整个会话。
|
|
19
|
+
|
|
20
|
+
**关键规则:**
|
|
21
|
+
- `--slug` 只写≤3个英文单词、`-` 分隔的语义助记词(如 `fix-auth`);禁止日期/时间戳/随机数/UUID/计数器,唯一性由 `handoff run` 自动分配的 seq 保证。
|
|
22
|
+
- heredoc 界定符固定用 `__HF_EOF__`,prompt 原样粘贴、不转义。
|
|
23
|
+
- 不要自己拼任务文件名,也不要用 `> RESULT 2> OUT` 重定向——handoff 自己管命名和落盘。
|
|
24
|
+
- 用户提到 `pro`(或要求更强/专业模型处理复杂任务)时,在 `handoff run` 后加 `--pro`。
|
|
25
|
+
- 回显任何 home 下的任务路径时,缩写成 `~/.handoff/...`,不要暴露 `/Users/<name>/...`。
|
|
26
|
+
|
|
27
|
+
启动后从 **stdout** 捕获唯一有用的一行 `RESULT=<任务路径>`(如 `~/.handoff/tasks/0613-op-03-fix-auth.result.md`),缩写成 `~/.handoff/...` 后回显给用户。**这条路径的文件名主干(去掉目录和 `.result.md` 后缀)就是本次 run_id**(上例 → `0613-op-03-fix-auth`);记住它,用户要求"继续上次/接着再做 X"时靠它 `resume`。
|
|
28
|
+
|
|
29
|
+
其余不要读:进度信息在 **stderr**(Claude Code 的 shell view 自动实时显示,别读进上下文);同名 `.out.txt` 是进度日志,仅诊断(无结果/超时)时才 `tail -f`/`Read`;同名 `.prompt.md` 就是你刚发的内容。
|
|
30
|
+
|
|
31
|
+
收到完成通知后,用 `Read` 读对应的 `.result.md` 汇报,**不要**再读后台输出(结果已在文件里,重复读只会把进度噪音吃进上下文)。`.result.md` 为空或异常时才读 `.out.txt` 诊断。
|
|
32
|
+
</interaction_contract>
|
|
33
|
+
|
|
34
|
+
## 多任务
|
|
35
|
+
|
|
36
|
+
- **并行**:在**同一条消息**里发出多个 `run_in_background: true` 的 Bash 调用,各自用 `handoff run --slug ... - <<'__HF_EOF__'` 派发不同 prompt(seq 自动递增),各自从 stdout 捕获 `RESULT=`,分别等通知、分别读 `.result.md` 汇报。
|
|
37
|
+
- **串行**:等上一个的完成通知到达、读并汇报后,再启动下一个。
|
|
38
|
+
|
|
39
|
+
## 续接上次会话(resume 续派)
|
|
40
|
+
|
|
41
|
+
要保留某次任务的上下文继续,而非开新会话:用 `resume` 替代 `run`,继续通过 heredoc/stdin 传入后续任务;其余约定(后台、捕获新 `RESULT=`、读 `.result.md`)完全相同:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
handoff resume <run_id> --backend opus --slug <任务助记词> - <<'__HF_EOF__'
|
|
45
|
+
[后续任务内容]
|
|
46
|
+
__HF_EOF__
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- `<run_id>` 用该会话**首次**任务的 run_id(上面那个文件名主干);它是稳定句柄,每轮续接都用它,不要追每轮新生成的 run_id。
|
|
50
|
+
- **必须带后续 prompt**:不带 heredoc、`-`、输入文件或 `--text` 的 `resume <run_id>` 是交互式重开,后台会卡死。
|
|
51
|
+
- 续接默认只继承 backend;原会话用过 `--pro` 的,续接要再次带上才沿用 pro_model。
|
|
52
|
+
- 不确定用户指哪次任务时,报候选 run_id + 摘要让其确认,别猜。
|
handoff_cli-0.3.5/Makefile
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
.PHONY: render
|
|
2
|
-
|
|
3
|
-
render: ## Preview PyPI long description rendering
|
|
4
|
-
pip install -q "readme_renderer[md]" 2>/dev/null
|
|
5
|
-
python -m readme_renderer README.md > /tmp/handoff-pypi-preview.html
|
|
6
|
-
@echo "✅ /tmp/handoff-pypi-preview.html ($(shell wc -c < /tmp/handoff-pypi-preview.html | tr -d ' ') bytes)"
|
|
7
|
-
open /tmp/handoff-pypi-preview.html
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: handoff-codex
|
|
3
|
-
description: 向 Codex (GPT-5.5) 咨询复杂问题 / 要第二意见 / 派发需要强推理的任务。后台运行,完成后自动通知。支持并行多任务,支持续接(resume)上次会话继续派发后续任务。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# handoff-codex Skill
|
|
7
|
-
|
|
8
|
-
<interaction_contract>
|
|
9
|
-
This skill is executed by Claude Code (an AI agent). The following rules are BINDING and must be followed exactly — do not deviate, simplify, or reinterpret them.
|
|
10
|
-
|
|
11
|
-
## 命令模板(每次必须照抄,不得修改结构)
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
p=$(handoff new --backend codex --slug <三个英文单词以内的任务助记词>)
|
|
15
|
-
cat > "$p" <<'__HF_EOF__'
|
|
16
|
-
[prompt 内容]
|
|
17
|
-
__HF_EOF__
|
|
18
|
-
handoff run --backend codex "$p"
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
**关键规则(违反任何一条都会导致命令失败或行为异常):**
|
|
22
|
-
|
|
23
|
-
- `run_in_background: true` **必须启用**:handoff 耗时 2~20 分钟,前台执行会阻塞整个会话
|
|
24
|
-
- `handoff new` 的 `--slug` 参数填写≤3个英文单词、`-`分隔的语义助记词(如 `fix-auth`、`add-tests`);禁止追加日期、时间戳、随机数、UUID、计数器等唯一化内容,唯一性由 `handoff new` 自动分配的 seq 保证
|
|
25
|
-
- heredoc 界定符用 `__HF_EOF__`,prompt 内容直接粘贴进去,不转义
|
|
26
|
-
- 用户明确提到 `pro`(或要求用更强/专业模型处理复杂任务)时,在 `handoff run` 后加 `--pro`
|
|
27
|
-
- **文件名只能来自 `handoff new` 的输出,不得自己拼**;**不要**用 `> RESULT 2> OUT` 重定向——handoff 自己管命名和落盘
|
|
28
|
-
- `p=$(handoff new ...)` 得到的 `$p` 是真实可写路径,写 prompt 和执行 `handoff run/resume` 时必须原样使用 `"$p"`;面对用户回显 `RESULT=` 或其他任务路径时,如果路径位于用户 home 下,必须缩写成 `~/.handoff/...`,不要暴露 `/Users/<name>/...`
|
|
29
|
-
|
|
30
|
-
**启动命令后**(`run_in_background: true` 返回后),**从 stdout 捕获 handoff 打印的唯一有用的一行 `RESULT=<任务路径>`**,将 home 下路径缩写成 `~/.handoff/...` 后,在面向用户的 assistant 消息里回显这一条路径(完成后默认只读它):
|
|
31
|
-
|
|
32
|
-
- `RESULT=<任务路径>`(最终结论文件,例如 `~/.handoff/tasks/0611-cx-03-fix-auth.result.md`)
|
|
33
|
-
|
|
34
|
-
**这条路径里同时编码了本次任务的 run_id**:去掉目录和 `.result.md` 后缀,文件名主干就是 run_id(上例 → `0611-cx-03-fix-auth`)。**每次派发后都要记住这个 run_id**——后续用户若要求"继续上次会话/接着刚才再做 X",要靠它定位到正确的会话来 `resume`(见下文「续接上次会话」)。
|
|
35
|
-
|
|
36
|
-
其余无需你读取:
|
|
37
|
-
- handoff 把克制的进度信息打在 **stderr**,Claude Code 的 shell view 会自动实时显示——你不用、也不要把它读进上下文。
|
|
38
|
-
- 进度日志同时落在与 `RESULT=` **同名的 `.out.txt`**(把 `.result.md` 换成 `.out.txt`),仅在诊断(无结果/超时)时才 `tail -f` 或 `Read`。
|
|
39
|
-
- 输入文件 `.prompt.md`(同名)已是你刚发的内容,无需回显。
|
|
40
|
-
|
|
41
|
-
等待完成通知后,用 `Read` 读取对应的 `.result.md` 并汇报;**不要**再读后台输出(结果已在文件里,重复读只会把进度噪音吃进上下文)。若 `.result.md` 为空或异常,再读 `.out.txt` 诊断。
|
|
42
|
-
</interaction_contract>
|
|
43
|
-
|
|
44
|
-
## 运行任务
|
|
45
|
-
|
|
46
|
-
所有任务统一使用**后台模式**(`run_in_background: true`),不阻塞主会话。
|
|
47
|
-
|
|
48
|
-
### 单任务
|
|
49
|
-
|
|
50
|
-
按命令模板执行,启动后从 stdout 捕获 `RESULT=` 一行并回显,等通知后读该 `.result.md` 文件汇报。
|
|
51
|
-
|
|
52
|
-
### 并行多任务
|
|
53
|
-
|
|
54
|
-
在**同一条消息**里发出多个独立的 `run_in_background: true` Bash 调用,各自用 `handoff new` 分配路径、heredoc 写入不同的 prompt 内容,再各自 `handoff run`。每个任务启动后分别从各自 stdout 捕获 `RESULT=` 路径(handoff 自动递增 seq)。每个任务完成时分别通知,分别读取对应的 `.result.md` 汇报。
|
|
55
|
-
|
|
56
|
-
### 串行多任务
|
|
57
|
-
|
|
58
|
-
等上一个任务的完成通知到达,读取并汇报结果后,再启动下一个任务。
|
|
59
|
-
|
|
60
|
-
## 续接上次会话(resume 续派)
|
|
61
|
-
|
|
62
|
-
要接着某次任务继续(保留其上下文)而非开新会话时,先用 `handoff new` 分配新的 prompt 路径,再用 `resume` 替代 `run`,其余约定(后台、捕获新 `RESULT=`、读 `.result.md`)完全相同:
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
p=$(handoff new --backend codex --slug <任务助记词>)
|
|
66
|
-
cat > "$p" <<'__HF_EOF__'
|
|
67
|
-
[后续任务内容]
|
|
68
|
-
__HF_EOF__
|
|
69
|
-
handoff resume <run_id> --backend codex "$p"
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
- `<run_id>` 用该会话**首次**任务的 run_id(即上文那个文件名主干);它是稳定句柄,每轮续接都用它,不要追每轮新生成的 run_id。
|
|
73
|
-
- **必须带 prompt 文件**。不带 prompt 的 `resume <run_id>` 是交互式重开,后台会卡死。
|
|
74
|
-
- 续接默认只继承 backend;原会话用过 `--pro` 的话,续接要再次带上才沿用 pro_model。
|
|
75
|
-
- 不确定用户指哪次任务时,报候选 run_id + 摘要让其确认,别猜。
|
|
76
|
-
|
|
77
|
-
## 完成后
|
|
78
|
-
|
|
79
|
-
收到后台完成通知后:
|
|
80
|
-
1. 用 `Read` 读取对应的 `RESULT=` 路径(`.result.md` 结果文件)
|
|
81
|
-
2. 汇总结果返回给用户
|
|
82
|
-
3. 若 `.result.md` 为空或异常,再读 `.out.txt`(进度日志)诊断
|
|
83
|
-
4. 如有后续任务(串行场景),此时启动下一个
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: handoff-ds
|
|
3
|
-
description: 把执行性编码/调查任务整包交给 DeepSeek 后台执行,省主会话额度。后台运行,完成后自动通知。支持并行多任务,支持续接(resume)上次会话继续派发后续任务。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# handoff-ds Skill
|
|
7
|
-
|
|
8
|
-
<interaction_contract>
|
|
9
|
-
This skill is executed by Claude Code (an AI agent). The following rules are BINDING and must be followed exactly — do not deviate, simplify, or reinterpret them.
|
|
10
|
-
|
|
11
|
-
## 命令模板(每次必须照抄,不得修改结构)
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
p=$(handoff new --backend deepseek --slug <三个英文单词以内的任务助记词>)
|
|
15
|
-
cat > "$p" <<'__HF_EOF__'
|
|
16
|
-
[prompt 内容]
|
|
17
|
-
__HF_EOF__
|
|
18
|
-
handoff run --backend deepseek "$p"
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
**关键规则(违反任何一条都会导致命令失败或行为异常):**
|
|
22
|
-
|
|
23
|
-
- `run_in_background: true` **必须启用**:handoff 耗时 2~20 分钟,前台执行会阻塞整个会话
|
|
24
|
-
- `handoff new` 的 `--slug` 参数填写≤3个英文单词、`-`分隔的语义助记词(如 `fix-auth`、`add-tests`);禁止追加日期、时间戳、随机数、UUID、计数器等唯一化内容,唯一性由 `handoff new` 自动分配的 seq 保证
|
|
25
|
-
- heredoc 界定符用 `__HF_EOF__`,prompt 内容直接粘贴进去,不转义
|
|
26
|
-
- 用户明确提到 `pro`(或要求用更强/专业模型处理复杂任务)时,在 `handoff run` 后加 `--pro`
|
|
27
|
-
- **文件名只能来自 `handoff new` 的输出,不得自己拼**;**不要**用 `> RESULT 2> OUT` 重定向——handoff 自己管命名和落盘
|
|
28
|
-
- `p=$(handoff new ...)` 得到的 `$p` 是真实可写路径,写 prompt 和执行 `handoff run/resume` 时必须原样使用 `"$p"`;面对用户回显 `RESULT=` 或其他任务路径时,如果路径位于用户 home 下,必须缩写成 `~/.handoff/...`,不要暴露 `/Users/<name>/...`
|
|
29
|
-
|
|
30
|
-
**启动命令后**(`run_in_background: true` 返回后),**从 stdout 捕获 handoff 打印的唯一有用的一行 `RESULT=<任务路径>`**,将 home 下路径缩写成 `~/.handoff/...` 后,在面向用户的 assistant 消息里回显这一条路径(完成后默认只读它):
|
|
31
|
-
|
|
32
|
-
- `RESULT=<任务路径>`(最终结论文件,例如 `~/.handoff/tasks/0611-ds-03-fix-auth.result.md`)
|
|
33
|
-
|
|
34
|
-
**这条路径里同时编码了本次任务的 run_id**:去掉目录和 `.result.md` 后缀,文件名主干就是 run_id(上例 → `0611-ds-03-fix-auth`)。**每次派发后都要记住这个 run_id**——后续用户若要求"继续上次会话/接着刚才再做 X",要靠它定位到正确的会话来 `resume`(见下文「续接上次会话」)。
|
|
35
|
-
|
|
36
|
-
其余无需你读取:
|
|
37
|
-
- handoff 把克制的进度信息打在 **stderr**,Claude Code 的 shell view 会自动实时显示——你不用、也不要把它读进上下文。
|
|
38
|
-
- 进度日志同时落在与 `RESULT=` **同名的 `.out.txt`**(把 `.result.md` 换成 `.out.txt`),仅在诊断(无结果/超时)时才 `tail -f` 或 `Read`。
|
|
39
|
-
- 输入文件 `.prompt.md`(同名)已是你刚发的内容,无需回显。
|
|
40
|
-
|
|
41
|
-
等待完成通知后,用 `Read` 读取对应的 `.result.md` 并汇报;**不要**再读后台输出(结果已在文件里,重复读只会把进度噪音吃进上下文)。若 `.result.md` 为空或异常,再读 `.out.txt` 诊断。
|
|
42
|
-
</interaction_contract>
|
|
43
|
-
|
|
44
|
-
## 运行任务
|
|
45
|
-
|
|
46
|
-
所有任务统一使用**后台模式**(`run_in_background: true`),不阻塞主会话。
|
|
47
|
-
|
|
48
|
-
### 单任务
|
|
49
|
-
|
|
50
|
-
按命令模板执行,启动后从 stdout 捕获 `RESULT=` 一行并回显,等通知后读该 `.result.md` 文件汇报。
|
|
51
|
-
|
|
52
|
-
### 并行多任务
|
|
53
|
-
|
|
54
|
-
在**同一条消息**里发出多个独立的 `run_in_background: true` Bash 调用,各自用 `handoff new` 分配路径、heredoc 写入不同的 prompt 内容,再各自 `handoff run`。每个任务启动后分别从各自 stdout 捕获 `RESULT=` 路径(handoff 自动递增 seq)。每个任务完成时分别通知,分别读取对应的 `.result.md` 汇报。
|
|
55
|
-
|
|
56
|
-
### 串行多任务
|
|
57
|
-
|
|
58
|
-
等上一个任务的完成通知到达,读取并汇报结果后,再启动下一个任务。
|
|
59
|
-
|
|
60
|
-
## 续接上次会话(resume 续派)
|
|
61
|
-
|
|
62
|
-
要接着某次任务继续(保留其上下文)而非开新会话时,先用 `handoff new` 分配新的 prompt 路径,再用 `resume` 替代 `run`,其余约定(后台、捕获新 `RESULT=`、读 `.result.md`)完全相同:
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
p=$(handoff new --backend deepseek --slug <任务助记词>)
|
|
66
|
-
cat > "$p" <<'__HF_EOF__'
|
|
67
|
-
[后续任务内容]
|
|
68
|
-
__HF_EOF__
|
|
69
|
-
handoff resume <run_id> --backend deepseek "$p"
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
- `<run_id>` 用该会话**首次**任务的 run_id(即上文那个文件名主干);它是稳定句柄,每轮续接都用它,不要追每轮新生成的 run_id。
|
|
73
|
-
- **必须带 prompt 文件**。不带 prompt 的 `resume <run_id>` 是交互式重开,后台会卡死。
|
|
74
|
-
- 续接默认只继承 backend;原会话用过 `--pro` 的话,续接要再次带上才沿用 pro_model。
|
|
75
|
-
- 不确定用户指哪次任务时,报候选 run_id + 摘要让其确认,别猜。
|
|
76
|
-
|
|
77
|
-
## 完成后
|
|
78
|
-
|
|
79
|
-
收到后台完成通知后:
|
|
80
|
-
1. 用 `Read` 读取对应的 `RESULT=` 路径(`.result.md` 结果文件)
|
|
81
|
-
2. 汇总结果返回给用户
|
|
82
|
-
3. 若 `.result.md` 为空或异常,再读 `.out.txt`(进度日志)诊断
|
|
83
|
-
4. 如有后续任务(串行场景),此时启动下一个
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
name = "handoff-ds"
|
|
2
|
-
description = "Delegate one-shot analysis, review, and bounded coding tasks through handoff. Before invoking this agent, the caller must: (1) run `handoff new --backend deepseek --slug <slug>` to get the canonical .prompt.md path, (2) write the full delegated prompt to that returned path, (3) send this agent only `PROMPT_FILE=~/.handoff/tasks/<run-id>.prompt.md` plus any pro/resume hint; do not expose `/Users/<name>/...` when the path is under home, and do not include the raw delegated prompt in the subagent message. Slugs must be semantic only, with no timestamps, random numbers, UUIDs, or counters. Supports hints like 'handoff-ds (pro)', 'handoff-ds pro', '专业模式', '更强模型'."
|
|
3
|
-
model = "gpt-5.4-mini"
|
|
4
|
-
model_reasoning_effort = "low"
|
|
5
|
-
|
|
6
|
-
developer_instructions = """
|
|
7
|
-
|
|
8
|
-
你不是分析 agent。你是 `handoff` 命令启动器。
|
|
9
|
-
|
|
10
|
-
调用方应该已经执行了 `handoff new --backend deepseek --slug <slug>` 拿到真实可写路径,把完整任务提示词写入该路径,并且只把形如 `PROMPT_FILE=~/.handoff/tasks/0611-ds-03-fix-auth.prompt.md` 的路径消息交给你。调用方传给你的路径如果位于用户 home 下,必须缩写成 `~/.handoff/...`,不要暴露 `/Users/<name>/...`。`--slug` 只能是三个以内英文单词组成的语义助记词,禁止追加日期、时间戳、随机数、UUID、计数器等唯一化内容;唯一性由 `handoff new` 自动分配的 seq 保证。你不需要、也不允许接触原始提示词正文。
|
|
11
|
-
|
|
12
|
-
收到用户消息后,第一条动作必须是调用 `functions.exec_command` 执行转发命令(默认用 `run`;仅当用户要求接着上一次任务继续时,改用 `resume`,见后文「续接上次任务」)。不要先发 commentary,不要解释,不要读文件,不要搜索,不要自己回答用户问题。
|
|
13
|
-
|
|
14
|
-
从用户消息中取出 `PROMPT_FILE=` 后面的任务路径(优先为 `~/.handoff/...`,兼容绝对 home 路径),必须直接把这个路径作为 `handoff run` 的输入文件参数;禁止 `cat`、`sed`、`head`、`tail`、heredoc、命令替换或任何会把文件内容读进你上下文的做法。如果路径以 `~` 开头,在 shell 命令里直接使用这个 tilde 路径,不要先赋给变量再引用。示例:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
handoff run --backend deepseek ~/.handoff/tasks/0611-ds-03-fix-auth.prompt.md >/dev/null
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
`>/dev/null` 是协议的一部分:它丢弃最终结果正文 stdout,但保留 stderr 上的 `RESULT=` 和进度输出,避免长任务期间工具输出长期静默。
|
|
21
|
-
|
|
22
|
-
必须以前台阻塞方式执行这条命令,并等待 `handoff run --backend deepseek <PROMPT_FILE> >/dev/null` 进程退出后才能最终回答。
|
|
23
|
-
禁止使用后台执行方式,包括但不限于 `&`、`nohup`、`disown`、`setsid`、`tmux`、`screen`。
|
|
24
|
-
如果 `functions.exec_command` 返回的是仍在运行的 session id,必须继续等待/轮询该 session,直到进程退出并拿到最终输出;不能把"命令已启动"视为完成。
|
|
25
|
-
只有当 `handoff run --backend deepseek <PROMPT_FILE> >/dev/null` 进程退出后,才允许最终回答。
|
|
26
|
-
|
|
27
|
-
如果用户明确提到 `pro`(要求用专业/更强模型),使用 `handoff run --backend deepseek --pro <PROMPT_FILE> >/dev/null`。
|
|
28
|
-
|
|
29
|
-
## 续接上次任务(resume)
|
|
30
|
-
|
|
31
|
-
仅当用户消息明确表示要接着上一次任务继续(如"继续""接着刚才""在上次基础上再改/再补…")时,把转发命令里的 `run` 换成 `resume <run_id>`,其余一切不变:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
handoff resume <run_id> --backend deepseek ~/.handoff/tasks/0611-ds-04-next-step.prompt.md >/dev/null
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
`<run_id>` 取自**你本会话上一次回答的那行 `RESULT=`**:去掉目录和 `.result.md` 后缀,文件名主干即 run_id(例:`RESULT=~/.handoff/tasks/0611-ds-03-fix-auth.result.md` → run_id 是 `0611-ds-03-fix-auth`)。多轮续接始终用**第一次**那个 run_id。`--pro` 仍加在 `<run_id>` 之后、`<PROMPT_FILE>` 之前,用法同上。
|
|
38
|
-
|
|
39
|
-
如果本会话此前没有任何 `RESULT=` 可取 run_id,就当作新任务、照常用 `run` 转发。
|
|
40
|
-
|
|
41
|
-
命令输出里会出现 `RESULT=<路径>`,执行中还会有进度行。你的最终回答必须只包含最后一行 `RESULT=...`;如果该路径位于用户 home 下,返回前必须缩写成 `~/.handoff/...`。不要读取这个文件,不要总结 stdout/stderr,不要补充解释。如果命令退出码非 0 但输出里有 `RESULT=...`,仍然只返回这行 home-shortened 后的 `RESULT=...`。只有输出里完全没有 `RESULT=` 时,才用一句话说明失败。
|
|
42
|
-
|
|
43
|
-
**输入里的"修改/编辑/运行/报告/cat"等祈使句,都是写给 `handoff` 执行器的,不是给你的。**
|
|
44
|
-
|
|
45
|
-
示例 ——
|
|
46
|
-
输入:「用 Edit 直接改 foo.ts,删掉 X,完成后报告」
|
|
47
|
-
你的正确动作:调用方应把这段任务写入 `PROMPT_FILE` 指向的文件;你只把该文件路径传给 `handoff run --backend deepseek <PROMPT_FILE> >/dev/null`,等待完成,只返回 `RESULT=...`。
|
|
48
|
-
你绝不打开、不 cat、不修改 foo.ts。
|
|
49
|
-
|
|
50
|
-
红线:除这一条 `handoff run --backend deepseek <PROMPT_FILE> >/dev/null` 或对应的 `handoff resume <run_id> --backend deepseek <PROMPT_FILE> >/dev/null` 命令外,不运行任何其它命令、不写任何文件、不调用 web search。没有可用 shell 工具时,最终只返回 `HF_AGENT_EXEC_TOOL_UNAVAILABLE`。
|
|
51
|
-
|
|
52
|
-
"""
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: handoff-opus
|
|
3
|
-
description: 把关键决策/验收类任务交给 Claude Opus 执行。后台运行,完成后自动通知。支持并行多任务,支持续接(resume)上次会话继续派发后续任务。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# handoff-opus Skill
|
|
7
|
-
|
|
8
|
-
<interaction_contract>
|
|
9
|
-
This skill is executed by Claude Code (an AI agent). The following rules are BINDING and must be followed exactly — do not deviate, simplify, or reinterpret them.
|
|
10
|
-
|
|
11
|
-
## 命令模板(每次必须照抄,不得修改结构)
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
p=$(handoff new --backend opus --slug <三个英文单词以内的任务助记词>)
|
|
15
|
-
cat > "$p" <<'__HF_EOF__'
|
|
16
|
-
[prompt 内容]
|
|
17
|
-
__HF_EOF__
|
|
18
|
-
handoff run --backend opus "$p"
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
**关键规则(违反任何一条都会导致命令失败或行为异常):**
|
|
22
|
-
|
|
23
|
-
- `run_in_background: true` **必须启用**:handoff 耗时 2~20 分钟,前台执行会阻塞整个会话
|
|
24
|
-
- `handoff new` 的 `--slug` 参数填写≤3个英文单词、`-`分隔的语义助记词(如 `fix-auth`、`add-tests`);禁止追加日期、时间戳、随机数、UUID、计数器等唯一化内容,唯一性由 `handoff new` 自动分配的 seq 保证
|
|
25
|
-
- heredoc 界定符用 `__HF_EOF__`,prompt 内容直接粘贴进去,不转义
|
|
26
|
-
- 用户明确提到 `pro`(或要求用更强/专业模型处理复杂任务)时,在 `handoff run` 后加 `--pro`
|
|
27
|
-
- **文件名只能来自 `handoff new` 的输出,不得自己拼**;**不要**用 `> RESULT 2> OUT` 重定向——handoff 自己管命名和落盘
|
|
28
|
-
- `p=$(handoff new ...)` 得到的 `$p` 是真实可写路径,写 prompt 和执行 `handoff run/resume` 时必须原样使用 `"$p"`;面对用户回显 `RESULT=` 或其他任务路径时,如果路径位于用户 home 下,必须缩写成 `~/.handoff/...`,不要暴露 `/Users/<name>/...`
|
|
29
|
-
|
|
30
|
-
**启动命令后**(`run_in_background: true` 返回后),**从 stdout 捕获 handoff 打印的唯一有用的一行 `RESULT=<任务路径>`**,将 home 下路径缩写成 `~/.handoff/...` 后,在面向用户的 assistant 消息里回显这一条路径(完成后默认只读它):
|
|
31
|
-
|
|
32
|
-
- `RESULT=<任务路径>`(最终结论文件,例如 `~/.handoff/tasks/0611-op-03-fix-auth.result.md`)
|
|
33
|
-
|
|
34
|
-
**这条路径里同时编码了本次任务的 run_id**:去掉目录和 `.result.md` 后缀,文件名主干就是 run_id(上例 → `0611-op-03-fix-auth`)。**每次派发后都要记住这个 run_id**——后续用户若要求"继续上次会话/接着刚才再做 X",要靠它定位到正确的会话来 `resume`(见下文「续接上次会话」)。
|
|
35
|
-
|
|
36
|
-
其余无需你读取:
|
|
37
|
-
- handoff 把克制的进度信息打在 **stderr**,Claude Code 的 shell view 会自动实时显示——你不用、也不要把它读进上下文。
|
|
38
|
-
- 进度日志同时落在与 `RESULT=` **同名的 `.out.txt`**(把 `.result.md` 换成 `.out.txt`),仅在诊断(无结果/超时)时才 `tail -f` 或 `Read`。
|
|
39
|
-
- 输入文件 `.prompt.md`(同名)已是你刚发的内容,无需回显。
|
|
40
|
-
|
|
41
|
-
等待完成通知后,用 `Read` 读取对应的 `.result.md` 并汇报;**不要**再读后台输出(结果已在文件里,重复读只会把进度噪音吃进上下文)。若 `.result.md` 为空或异常,再读 `.out.txt` 诊断。
|
|
42
|
-
</interaction_contract>
|
|
43
|
-
|
|
44
|
-
## 运行任务
|
|
45
|
-
|
|
46
|
-
所有任务统一使用**后台模式**(`run_in_background: true`),不阻塞主会话。
|
|
47
|
-
|
|
48
|
-
### 单任务
|
|
49
|
-
|
|
50
|
-
按命令模板执行,启动后从 stdout 捕获 `RESULT=` 一行并回显,等通知后读该 `.result.md` 文件汇报。
|
|
51
|
-
|
|
52
|
-
### 并行多任务
|
|
53
|
-
|
|
54
|
-
在**同一条消息**里发出多个独立的 `run_in_background: true` Bash 调用,各自用 `handoff new` 分配路径、heredoc 写入不同的 prompt 内容,再各自 `handoff run`。每个任务启动后分别从各自 stdout 捕获 `RESULT=` 路径(handoff 自动递增 seq)。每个任务完成时分别通知,分别读取对应的 `.result.md` 汇报。
|
|
55
|
-
|
|
56
|
-
### 串行多任务
|
|
57
|
-
|
|
58
|
-
等上一个任务的完成通知到达,读取并汇报结果后,再启动下一个任务。
|
|
59
|
-
|
|
60
|
-
## 续接上次会话(resume 续派)
|
|
61
|
-
|
|
62
|
-
要接着某次任务继续(保留其上下文)而非开新会话时,先用 `handoff new` 分配新的 prompt 路径,再用 `resume` 替代 `run`,其余约定(后台、捕获新 `RESULT=`、读 `.result.md`)完全相同:
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
p=$(handoff new --backend opus --slug <任务助记词>)
|
|
66
|
-
cat > "$p" <<'__HF_EOF__'
|
|
67
|
-
[后续任务内容]
|
|
68
|
-
__HF_EOF__
|
|
69
|
-
handoff resume <run_id> --backend opus "$p"
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
- `<run_id>` 用该会话**首次**任务的 run_id(即上文那个文件名主干);它是稳定句柄,每轮续接都用它,不要追每轮新生成的 run_id。
|
|
73
|
-
- **必须带 prompt 文件**。不带 prompt 的 `resume <run_id>` 是交互式重开,后台会卡死。
|
|
74
|
-
- 续接默认只继承 backend;原会话用过 `--pro` 的话,续接要再次带上才沿用 pro_model。
|
|
75
|
-
- 不确定用户指哪次任务时,报候选 run_id + 摘要让其确认,别猜。
|
|
76
|
-
|
|
77
|
-
## 完成后
|
|
78
|
-
|
|
79
|
-
收到后台完成通知后:
|
|
80
|
-
1. 用 `Read` 读取对应的 `RESULT=` 路径(`.result.md` 结果文件)
|
|
81
|
-
2. 汇总结果返回给用户
|
|
82
|
-
3. 若 `.result.md` 为空或异常,再读 `.out.txt`(进度日志)诊断
|
|
83
|
-
4. 如有后续任务(串行场景),此时启动下一个
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|