hermes-task-framework 1.0.0__py3-none-any.whl
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.
- hermes_task_framework-1.0.0.dist-info/METADATA +7 -0
- hermes_task_framework-1.0.0.dist-info/RECORD +56 -0
- hermes_task_framework-1.0.0.dist-info/WHEEL +5 -0
- hermes_task_framework-1.0.0.dist-info/licenses/LICENSE +1 -0
- hermes_task_framework-1.0.0.dist-info/top_level.txt +1 -0
- task-framework/__init__.py +2 -0
- task-framework/skills/task-external-repos-pattern/SKILL.md +165 -0
- task-framework/skills/task-framework/CHANGELOG.md +45 -0
- task-framework/skills/task-framework/SKILL.md +1365 -0
- task-framework/skills/task-framework/docs/TASKS.md +3 -0
- task-framework/skills/task-framework/docs/architecture.dot +65 -0
- task-framework/skills/task-framework/docs/architecture.svg +188 -0
- task-framework/skills/task-framework/docs/product-requirements.md +65 -0
- task-framework/skills/task-framework/references/auto-runner.md +32 -0
- task-framework/skills/task-framework/references/composites/code-review-session.md +30 -0
- task-framework/skills/task-framework/references/composites/research.md +45 -0
- task-framework/skills/task-framework/references/composites/software-dev.md +41 -0
- task-framework/skills/task-framework/references/document-analysis-workflow.md +95 -0
- task-framework/skills/task-framework/references/file-safety-lesson.md +38 -0
- task-framework/skills/task-framework/references/generating-output-documents.md +166 -0
- task-framework/skills/task-framework/references/operations/code-write.md +30 -0
- task-framework/skills/task-framework/references/operations/document-write.md +185 -0
- task-framework/skills/task-framework/references/operations/info-search.md +27 -0
- task-framework/skills/task-framework/references/operations/web-research.md +57 -0
- task-framework/skills/task-framework/references/policy-time-metadata.md +137 -0
- task-framework/skills/task-framework/references/research-workflow.md +220 -0
- task-framework/skills/task-framework/references/task-format-validation.md +25 -0
- task-framework/skills/task-framework/references/task-hash-naming.md +40 -0
- task-framework/skills/task-framework/references/task-lifecycle-example.md +122 -0
- task-framework/skills/task-framework/references/task-overview-discovery.md +31 -0
- task-framework/skills/task-framework/references/task-types/analysis.md +60 -0
- task-framework/skills/task-framework/references/task-types/external-audit.md +56 -0
- task-framework/skills/task-framework/references/task-types/video-production-pipeline.md +77 -0
- task-framework/skills/task-framework/scripts/__init__.py +0 -0
- task-framework/skills/task-framework/scripts/__pycache__/manage_task.cpython-312.pyc +0 -0
- task-framework/skills/task-framework/scripts/__pycache__/task_ref.cpython-312.pyc +0 -0
- task-framework/skills/task-framework/scripts/__pycache__/update-index.cpython-311.pyc +0 -0
- task-framework/skills/task-framework/scripts/__pycache__/update-index.cpython-312.pyc +0 -0
- task-framework/skills/task-framework/scripts/convert_md_to_pdf.py +236 -0
- task-framework/skills/task-framework/scripts/manage_task.py +442 -0
- task-framework/skills/task-framework/scripts/task-runner.sh +42 -0
- task-framework/skills/task-framework/scripts/task_ref.py +119 -0
- task-framework/skills/task-framework/scripts/update-index.py +293 -0
- task-framework/skills/task-framework/templates/TASK.md +114 -0
- task-framework/skills/task-framework/templates/TASK_MEMORY.md +27 -0
- task-framework/skills/task-framework/templates/run.py +187 -0
- task-framework/skills/task-lifecycle-edge-cases/SKILL.md +84 -0
- task-framework/skills/task-lifecycle-edge-cases/references/task-5d5a1a-recovery-example.md +67 -0
- task-framework/skills/task-lifecycle-portability/SKILL.md +128 -0
- task-framework/skills/task-lifecycle-portability/references/design-session-20260611.md +32 -0
- task-framework/skills/task-lifecycle-portability/references/output-model-design.md +55 -0
- task-framework/skills/task-lifecycle-portability/references/pipeline-output-transition.md +41 -0
- task-framework/skills/task-lifecycle-portability/references/task-recovery-5d5a1a-example.md +27 -0
- task-framework/skills/task-lifecycle-portability/references/task-recovery-procedure.md +63 -0
- task-framework/skills/task-timestamp-convention/SKILL.md +72 -0
- task-framework/skills/task-tracker/SKILL.md +80 -0
|
@@ -0,0 +1,1365 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: task-framework
|
|
3
|
+
description: 'Three-layer task system: (1) methodology — decompose complex work into
|
|
4
|
+
composable operations (info-search, code-write, paper-reproduce…) and composite
|
|
5
|
+
patterns (software-dev, research); (2) container — structured tasks/ directory with
|
|
6
|
+
TASK.md, logs, docs; (3) tooling — reusable scripts for logging, PDF conversion,
|
|
7
|
+
and task execution.'
|
|
8
|
+
author: Hauzer S. Lee
|
|
9
|
+
license: MIT
|
|
10
|
+
category: software-development
|
|
11
|
+
platforms:
|
|
12
|
+
- linux
|
|
13
|
+
- macos
|
|
14
|
+
tags:
|
|
15
|
+
- task
|
|
16
|
+
- methodology
|
|
17
|
+
- container
|
|
18
|
+
- tooling
|
|
19
|
+
- decompose
|
|
20
|
+
- operations
|
|
21
|
+
- logging
|
|
22
|
+
- pdf
|
|
23
|
+
version: 1.0.0
|
|
24
|
+
metadata:
|
|
25
|
+
hermes:
|
|
26
|
+
tags:
|
|
27
|
+
- docker
|
|
28
|
+
- container
|
|
29
|
+
- logging
|
|
30
|
+
- software-development
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
# Task Framework
|
|
36
|
+
|
|
37
|
+
A three-layer system covering the full task lifecycle:
|
|
38
|
+
|
|
39
|
+
| Layer | What | Examples |
|
|
40
|
+
|-------|------|----------|
|
|
41
|
+
| **Methodology** | 如何拆解复杂工作为可组合的操作 | operation catalog (`info-search`, `code-write`…), composite patterns (`software-dev`), decomposition guide |
|
|
42
|
+
| **Container** | 如何组织任务的物理文件 | `tasks/<ts>.<name>-<hash6>/` with `TASK.md`, `README.md`, `logs/`, `docs/`, `scripts/` |
|
|
43
|
+
| **Tooling** | 执行任务的复用工具 | `scripts/task-runner.sh` (日志封装), `scripts/convert_md_to_pdf.py`, `templates/TASK.md` |
|
|
44
|
+
|
|
45
|
+
## The Model
|
|
46
|
+
|
|
47
|
+
A **task** is a goal with structured tracking (directory, checklist, logs).
|
|
48
|
+
An **operation** is a unit of work with a defined input, process, and output.
|
|
49
|
+
Complex tasks decompose into multiple operations; simple tasks may be a single operation.
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
Task: "复现这篇论文的实验结果"
|
|
53
|
+
└── Operation: paper-reproduce (environment → run → compare)
|
|
54
|
+
|
|
55
|
+
Task: "开发用户登录功能"
|
|
56
|
+
├── Operation: info-search (调研认证方案)
|
|
57
|
+
├── Operation: code-write (写后端+前端)
|
|
58
|
+
└── Operation: code-review (审查)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Task Types
|
|
64
|
+
|
|
65
|
+
每个任务都有**类型**,类型决定了生命周期(创建、执行、清理)和目录结构。类型定义在 `references/task-types/` 下。
|
|
66
|
+
|
|
67
|
+
### 类型注册表
|
|
68
|
+
|
|
69
|
+
| 类型 | 说明 | 目录结构 | 生命周期参考 |
|
|
70
|
+
|------|------|---------|------------|
|
|
71
|
+
| `analysis` | 文档分析/调研:从源文件提取信息,产出分析文档 | `input/`(源文件) + `output/docs/`(产出) | `references/task-types/analysis.md` |
|
|
72
|
+
| `external-audit` | 外部项目审计:读取外部路径下的文件,产出分析报告,不复制源文件、不修改外部路径 | `output/docs/`(无 input/) | `references/task-types/external-audit.md` |
|
|
73
|
+
| `video-production-pipeline` | 视频生产流水线:根据 REQUIREMENTS.md 自动化录屏配音,由 `video-production-pipeline` skill 驱动 | `input/` (REQUIREMENTS.md + images/) + `output/` (各 phase 目录) | `references/task-types/video-production-pipeline.md` |
|
|
74
|
+
|
|
75
|
+
### 添加新类型
|
|
76
|
+
|
|
77
|
+
当发现一种新的任务模式(比如代码开发、数据库迁移等),需要:
|
|
78
|
+
|
|
79
|
+
1. 在 `references/task-types/` 下创建 `<新类型>.md`
|
|
80
|
+
2. 在类型参考中写明完整生命周期:创建 → 执行 → 修改 → 清理 → 完成
|
|
81
|
+
3. 更新本注册表,加入新类型
|
|
82
|
+
4. 如果新类型需要特殊的 `task_create` 行为,创建 `scripts/create_task.py`(参考 task_create 的 skill 接口)
|
|
83
|
+
|
|
84
|
+
**生命周期文档模板:**
|
|
85
|
+
|
|
86
|
+
```markdown
|
|
87
|
+
# <类型名> 任务生命周期
|
|
88
|
+
|
|
89
|
+
## 创建
|
|
90
|
+
创建时生成哪些目录和文件?
|
|
91
|
+
|
|
92
|
+
## 执行
|
|
93
|
+
执行时有哪些步骤?产物放在哪?
|
|
94
|
+
|
|
95
|
+
## 修改
|
|
96
|
+
如何安全地修改已有任务?
|
|
97
|
+
|
|
98
|
+
## 清理
|
|
99
|
+
如何清理产物?`task_reset --hard` 做了什么?
|
|
100
|
+
|
|
101
|
+
## 完成
|
|
102
|
+
完成时有什么收尾工作?
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
When you receive a task request:
|
|
108
|
+
0. **Determine task type** — lookup in the task types registry, load `references/task-types/<type>.md` for lifecycle guidance
|
|
109
|
+
1. **Identify the operation pattern** — single-operation or composite? Check the task type's lifecycle doc for the standard workflow
|
|
110
|
+
2. **If composite** — break into operations, sequence in TASK.md
|
|
111
|
+
3. **For each operation** — follow the standard workflow in its reference
|
|
112
|
+
4. **Choose execution strategy** — by complexity
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Environment Variables
|
|
117
|
+
|
|
118
|
+
This skill uses environment variables for portability across machines. After Personal Suite installation, these are set in `~/.hermes/personal/env.sh`:
|
|
119
|
+
|
|
120
|
+
| Variable | Default | Purpose |
|
|
121
|
+
|----------|---------|---------|
|
|
122
|
+
| `HERMES_TASKS_ROOT` | `~/studio/hermes/tasks` | Task container root (`tasks/2*/`, `tasks/inbox/`) |
|
|
123
|
+
| `HERMES_PROJECTS_ROOT` | `~/studio/hermes/projects` | Project repos root |
|
|
124
|
+
|
|
125
|
+
**Usage rule:** All inline shell commands in this SKILL.md use `$HERMES_TASKS_ROOT` instead of bare `tasks/` paths. When running commands from a Hermes session, source the env file first:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
source ~/.hermes/personal/env.sh
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
If the variable is unset, fall back to `~/studio/hermes/tasks` (the historical default).
|
|
132
|
+
|
|
133
|
+
## Task Directory Structure
|
|
134
|
+
|
|
135
|
+
The canonical tasks root is defined by `$HERMES_TASKS_ROOT` (default: `~/studio/hermes/tasks/`). All relative paths (e.g. `tasks/YYYYMMDD-*`) in documentation are relative to this root. When the user says "tasks" without qualification, this directory is the default reference — not the abstract concept of "任务". "创建一个任务" means creating a `YYYYMMDD-HHMMSS.<name>-<hash6>/` structure here using this skill.
|
|
136
|
+
|
|
137
|
+
🔴 **Semantic disambiguation (important):** When the user says "任务" or "task", first determine whether they mean (a) a task-framework managed task (in `tasks/YY.../` directories) or (b) a generic concept. Clues: specific name/timestamp, operating on a task directory → (a); abstract discussion → (b). For (a), always use task-framework tools (task_create, task_set_status, etc.) — never raw `mv`/`cp`/`rm` on task directories. For (b), handle as normal conversation.
|
|
138
|
+
|
|
139
|
+
```\ntasks/\n├── README.md ← summary index (directory façade)\n├── TASKS.md ← aggregated checklist view (done/total per task)\n├── YYYYMMDD-HHMMSS.<task-name>-<hash6>/\n│ ├── README.md ← goal, scope, key findings\n│ ├── TASK.md ← checklist with status + checkboxes\n│ ├── TASK_MEMORY.md ← per-task memory: auto-appended log of decisions, state, findings\n│ ├── input/ ← **source files** — NEVER deleted by cleanup operations\n│ │ (PDF, DOCX, images, REQUIREMENTS.md copied from inbox)\n│ ├── output/ ← **generated files** — CAN be safely deleted entirely\n│ │ ├── docs/ ← analysis documents, reports (for analysis tasks)\n│ │ ├── logs/ ← execution logs\n│ │ ├── tts-<hash6>/ ← pipeline phase dirs (for pipeline tasks)\n│ │ ├── RECORDING.md ← pipeline generated specs\n│ │ ├── COMPOSITING.md\n│ │ └── ...\n│ ├── inbox/ ← proposal inbox (one file/dir per idea)\n│ └── declined/ ← rejected proposals (with DECLINED.md)\n```
|
|
140
|
+
|
|
141
|
+
**`input/` 目录** — 存放从 inbox 复制来的源文件(PDF、DOCX、图片、REQUIREMENTS.md 等)。**核心规则:所有删除操作不得触及 `input/`。**
|
|
142
|
+
|
|
143
|
+
**`output/` 目录** — 存放所有生成文件(分析文档、执行日志、pipeline 产物如 tts-*/RECORDING.md/COMPOSITING.md 等)。**核心规则:所有删除操作只针对 `output/`。**
|
|
144
|
+
|
|
145
|
+
`task_reset --hard` 默认清空 `output/`,不动 `input/`。
|
|
146
|
+
|
|
147
|
+
### 自定义清理脚本
|
|
148
|
+
|
|
149
|
+
部分 task 有需要特殊保护的目录(如 clone 的仓库、大文件等),可以在 `scripts/clean.sh` 中定义自定义清理行为:
|
|
150
|
+
|
|
151
|
+
**查找顺序:**
|
|
152
|
+
1. 检查 `tasks/<ts>.<name>-<hash6>/scripts/clean.sh` — 存在则执行它(替代默认行为)
|
|
153
|
+
2. 不存在 → 回退到默认 `rm -rf output/`
|
|
154
|
+
|
|
155
|
+
**clean.sh 模板:**
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
#!/usr/bin/env bash
|
|
159
|
+
set -euo pipefail
|
|
160
|
+
TASK_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
161
|
+
|
|
162
|
+
# 明确声明要保留的路径
|
|
163
|
+
echo "[clean] repos/ — PRESERVED (cloned repos)"
|
|
164
|
+
echo "[clean] input/ — PRESERVED (source materials)"
|
|
165
|
+
|
|
166
|
+
# 只清理 output/
|
|
167
|
+
rm -rf "$TASK_DIR/output"
|
|
168
|
+
mkdir -p "$TASK_DIR/output"/{docs,logs}
|
|
169
|
+
echo "[clean] output/ cleaned"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**设计原则:**
|
|
173
|
+
- clean.sh 只控制"删什么不删什么",不修改 TASK.md 或状态
|
|
174
|
+
- 输出中列出保留路径方便审计
|
|
175
|
+
- 没有 clean.sh 时回退到默认行为,不破坏现有任务
|
|
176
|
+
|
|
177
|
+
**`scripts/task-runner.sh`** 是一个可复用的执行日志封装脚本,使用方式:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
bash scripts/task-runner.sh <task-dir> <command...>
|
|
181
|
+
# 自动创建 logs/output.<ts>.log + logs/error.<ts>.log
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Operation Catalog
|
|
187
|
+
|
|
188
|
+
Each operation has a reference under `references/operations/<name>.md`.
|
|
189
|
+
|
|
190
|
+
### Current Operations
|
|
191
|
+
|
|
192
|
+
| Operation | When to Use | Ref |
|
|
193
|
+
|-----------|-------------|-----|
|
|
194
|
+
| `file-concat` | 拼接多个源文件为一个 | `references/operations/file-concat.md` |
|
|
195
|
+
| `file-convert` | 文件格式转换(docx→md, xlsx→csv, pdf→md) | `references/operations/file-convert.md` |
|
|
196
|
+
| `info-search` | 多源信息搜索和抓取(竞品分析、政策调研) | `references/operations/info-search.md` |
|
|
197
|
+
| `code-write` | 写代码:单一功能实现,含测试 | `references/operations/code-write.md` |
|
|
198
|
+
| `paper-reproduce` | 论文代码复现:环境搭建、跑 pipeline、对比 | `references/operations/paper-reproduce.md` |
|
|
199
|
+
| `document-write` | 编写结构化文档(产品需求、产品设计、技术需求、技术设计) | `references/operations/document-write.md` ✅ |
|
|
200
|
+
| `code-review` | 代码审查:diff 分析、安全扫描 | `references/operations/code-review.md` |
|
|
201
|
+
| `data-analysis` | 数据分析:探索、统计、可视化 | `references/operations/data-analysis.md` |
|
|
202
|
+
| `task-overview-discovery` | 扫描 tasks/ 目录、读取 README.md 生成概览表 | `references/task-overview-discovery.md` |
|
|
203
|
+
| `web-research` | 网页调研:读取 URL、OCR 截图、生成 summary + discuss | `references/operations/web-research.md` |
|
|
204
|
+
|
|
205
|
+
New operation types discovered during real tasks should be added here.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Composite Task Patterns
|
|
210
|
+
|
|
211
|
+
Recurring multi-operation patterns. Each has a reference under `references/composites/<name>.md`.
|
|
212
|
+
|
|
213
|
+
### Software Development
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
0. [git] Pre-Change Sync → fetch + cherry + ff-only / rebase
|
|
217
|
+
1. info-search → 调研现有方案/技术选型
|
|
218
|
+
2. document-write → 写产品需求/产品设计/技术需求/技术设计四份文档
|
|
219
|
+
3. code-write → 实现(TDD)
|
|
220
|
+
4. code-review → 审查
|
|
221
|
+
5. [git] Post-Change Workflow → commit → quality-gate → re-sweep
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Step 0 loads GIT.md's Pre-Change Sync (fetch → cherry → ff-only → rebase → verify).
|
|
225
|
+
Step 5 runs GIT.md's Post-Change Workflow (sweep → commit → quality-gate → fix → re-sweep).
|
|
226
|
+
|
|
227
|
+
Common loops: 需求讨论 (2↔用户), review→fix (3↔4).
|
|
228
|
+
|
|
229
|
+
### Research Task
|
|
230
|
+
|
|
231
|
+
For open-ended investigation (competitor analysis, policy study, tech feasibility):
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
1. info-search → 多源搜索
|
|
235
|
+
2. data-analysis → 整理发现
|
|
236
|
+
3. document-write → 写出调研报告
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Code Review Session
|
|
240
|
+
|
|
241
|
+
For a batch review of changes:
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
1. 加载 TASK.md,确认审查范围
|
|
245
|
+
2. code-review → 逐个文件审查
|
|
246
|
+
3. document-write → 写 review/SUMMARY.md
|
|
247
|
+
4. 更新 TASK.md 状态
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Cross-Skill Composite Tasks
|
|
251
|
+
|
|
252
|
+
Some tasks span multiple tools/skills. For example: generate TTS audio → record browser video → composite audio onto video.
|
|
253
|
+
|
|
254
|
+
**How composite tasks work:**
|
|
255
|
+
|
|
256
|
+
1. TASK.md includes a `## Skills` section listing all required skills
|
|
257
|
+
2. Each phase in the checklist is prefixed with the skill that handles it
|
|
258
|
+
3. Each phase can declare execution mode: default (sequential), `和 Phase X 同步进行` (parallel), or `等待 Phase X 完成` (dependency)
|
|
259
|
+
4. When executing, phases run according to their dependency graph
|
|
260
|
+
5. Pass outputs between phases (file paths, durations, timestamps)
|
|
261
|
+
|
|
262
|
+
#### Phase isolation directories
|
|
263
|
+
|
|
264
|
+
每个 phase 使用独立的子目录,防止文件互相覆盖:
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
tasks/<ts>.<name>-<hash6>/
|
|
268
|
+
├── TASK.md
|
|
269
|
+
├── RECORDING.md
|
|
270
|
+
├── COMPOSITING.md
|
|
271
|
+
├── README.md
|
|
272
|
+
├── tts-a3f8c2/ ← text-to-speech 的工作目录
|
|
273
|
+
│ ├── audio_000001.mp3
|
|
274
|
+
│ ├── audio_000002.mp3
|
|
275
|
+
│ └── audio_manifest.json
|
|
276
|
+
├── recording-bd71ef/ ← browser-video-recording 的工作目录
|
|
277
|
+
│ ├── video.mp4
|
|
278
|
+
│ └── timeline.txt
|
|
279
|
+
├── compositing-c9f3a2/ ← video-audio-compositing 的工作目录
|
|
280
|
+
│ └── output.mp4
|
|
281
|
+
├── docs/ ← 共享文档(timestamps.json、多 phase 共用文件等)
|
|
282
|
+
└── logs/
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**规则:**
|
|
286
|
+
|
|
287
|
+
1. 目录命名:`<short-name>-<hash6>/`,短名用 `-` 连接,尾部加 6 位 hash。不用 `phase_NN_` 前缀,避免步骤顺序变化时目录名需要改动。
|
|
288
|
+
2. hash 用随机字符串(如 `a3f8c2`),**不是顺序编号**,避免对顺序的隐含依赖
|
|
289
|
+
3. 每个 phase 执行时,CWD 切换到自己的子目录
|
|
290
|
+
4. phase 间的文件传递通过 `docs/` 或通过 `## Data Flow` 表中明确定义的路径进行
|
|
291
|
+
5. 跨 phase 引用的文件使用相对路径(从任务根目录出发)或绝对路径
|
|
292
|
+
6. 合成类 phase(如 compositing)需要读取其他 phase 的输出时,通过 Data Flow 表的路径定位文件
|
|
293
|
+
|
|
294
|
+
**命名示例:**
|
|
295
|
+
|
|
296
|
+
```
|
|
297
|
+
- [ ] Phase 2 (browser-video-recording) — 录制视频
|
|
298
|
+
|
|
299
|
+
→ 目录 browser-video-recording-a3f8c2/
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**两条命名线:** Checklist 的 `()` 与目录名是**不同的东西**,不要混淆:
|
|
303
|
+
|
|
304
|
+
| 位置 | 内容 | 规则 |
|
|
305
|
+
|------|------|------|
|
|
306
|
+
| Checklist `(Phase 名)` | 描述性 phase 名称 | 完整词、无 hash、无缩写,如 `(text-to-speech)` |
|
|
307
|
+
| 实际目录 | `<short-name>-<hash6>/` | 短名 + hash,如 `tts-a3f8c2/` |
|
|
308
|
+
| Data Flow 表 | 实际路径 | 目录名 + 文件名,如 `tts-a3f8c2/audio_000001.mp3` |
|
|
309
|
+
|
|
310
|
+
`()` 里的内容是给**人读的 phase 标识**,目录名是给**机器用的存储位置**。两者可以不同——`(text-to-speech)` 表示"这是 TTS 阶段",但目录可以是 `tts-a3f8c2/`。不要照搬目录名到 `()` 中,也不要照搬 `()` 中的名称到目录名中。
|
|
311
|
+
|
|
312
|
+
好处:增删、重排步骤时,hash 不变,目录名不变,不会导致步骤对应的目录错乱。
|
|
313
|
+
|
|
314
|
+
**Execution Model:**
|
|
315
|
+
|
|
316
|
+
### Execution Model (unified runner)
|
|
317
|
+
|
|
318
|
+
When a task has a `run.py` at its root, use it as the single entry point. The auto-runner reads TASK.md checklist, marks BREAK items complete, and executes phases until the next BREAK or end of list. See [auto-runner pattern](references/auto-runner.md).
|
|
319
|
+
|
|
320
|
+
| 标注 | 行为 | 示例 |
|
|
321
|
+
|------|------|------|
|
|
322
|
+
| (无标注) | 按顺序串行,在前一阶段之后执行 | `Phase 2 — 录制视频` |
|
|
323
|
+
| `和 Phase X 同步进行` | 和 Phase X 并行执行 | `Phase 2 (browser-video-recording) — 和 Phase 1 同步进行, 录制视频` |
|
|
324
|
+
| `等待 Phase X 完成` | Phase X 完成后才执行,不关心其他阶段 | `Phase 3 (video-audio-compositing) — 等待 Phase 1 完成, 等待 Phase 2 完成, 合成` |
|
|
325
|
+
|
|
326
|
+
**Implementation:** 并行阶段通过 `delegate_task()` 启动子代理执行。等待阶段通过 `process(action='wait')` 或检查输出产物来判断完成。
|
|
327
|
+
|
|
328
|
+
**Format:**
|
|
329
|
+
|
|
330
|
+
```markdown
|
|
331
|
+
# Task: <Name>
|
|
332
|
+
|
|
333
|
+
## Goal
|
|
334
|
+
|
|
335
|
+
## Skills
|
|
336
|
+
|
|
337
|
+
- `text-to-speech` — 生成语音音频
|
|
338
|
+
- `browser-video-recording` — 录制浏览器操作视频
|
|
339
|
+
- `video-audio-compositing` — 合成音视频
|
|
340
|
+
|
|
341
|
+
## 环境要求
|
|
342
|
+
|
|
343
|
+
## Data Flow
|
|
344
|
+
|
|
345
|
+
| 文件 | 来源 Phase | 被消费 Phase | 格式说明 |
|
|
346
|
+
|------|-----------|-------------|---------|
|
|
347
|
+
| `{file_path}` | {phase} | {phase} | {格式文档路径} |
|
|
348
|
+
|
|
349
|
+
## Checklist
|
|
350
|
+
|
|
351
|
+
- [ ] Phase 1 (text-to-speech) — 根据解说脚本生成 N 段音频
|
|
352
|
+
- [ ] Phase 2 (browser-video-recording) — 和 Phase 1 同步进行, 录制浏览器操作视频
|
|
353
|
+
- [ ] Phase 3 (video-audio-compositing) — 等待 Phase 1 完成, 等待 Phase 2 完成, 将音频合成到视频的正确时间点
|
|
354
|
+
- [ ] BREAK: 检查最终视频效果
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Execution rule for cross-skill tasks:**
|
|
358
|
+
|
|
359
|
+
1. Read `## Skills` to know which skills to load
|
|
360
|
+
2. For each checklist item, identify the skill from the parenthesized prefix
|
|
361
|
+
3. Load that skill and follow its workflow for the phase
|
|
362
|
+
4. **Consult `## Data Flow`** — before writing or reading a file listed in the Data Flow table, find its `格式说明` column. That column tells you which skill's reference contains the file's schema. Load that skill and read its reference to understand the format before producing or consuming the file.
|
|
363
|
+
5. Pass file paths, durations, and metadata between phases via the task's `docs/` directory
|
|
364
|
+
6. On `task_reset`, re-run all phases in order
|
|
365
|
+
|
|
366
|
+
**执行方式(uv run):** 如果 task 目录下有 `.venv/`(即创建了 `## Venv`),所有脚本必须通过 `uv run` 执行:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
cd "$HERMES_TASKS_ROOT"/<ts>.<name>-<hash6>/
|
|
370
|
+
uv run python scripts/do_something.py
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
脚本内引用 skill 通用代码(`scripts/utils/`)的方式:
|
|
374
|
+
|
|
375
|
+
```python
|
|
376
|
+
#!/usr/bin/env python3
|
|
377
|
+
import sys, os
|
|
378
|
+
# 按需添加 skill utils 路径
|
|
379
|
+
sys.path.insert(0, os.path.expanduser(
|
|
380
|
+
"~/.hermes/skills/<category>/<skill>/scripts"))
|
|
381
|
+
from utils.xxx import ...
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**选择依据:** 有外部依赖的 skill → `uv pip install -r requirements.txt`(装进 task .venv)
|
|
385
|
+
纯 stdlib 的 utils/ → `sys.path` 引用,无需 pip install。
|
|
386
|
+
|
|
387
|
+
### Unified Runner (run.py)
|
|
388
|
+
|
|
389
|
+
When a task has multiple phases, add a `run.py` at the task root. Copy from `templates/run.py`.
|
|
390
|
+
|
|
391
|
+
```
|
|
392
|
+
./run.py — auto: find first unchecked item & execute until next BREAK
|
|
393
|
+
./run.py phase<N> — run specific phase
|
|
394
|
+
./run.py list — show checklist status
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
The auto mode:
|
|
398
|
+
1. Reads TASK.md checklist, finds first `[ ]` item
|
|
399
|
+
2. If it's a BREAK, marks it done, continues to next item
|
|
400
|
+
3. Executes phases until the next BREAK or end of list
|
|
401
|
+
4. Marks each completed phase as `[x]`
|
|
402
|
+
|
|
403
|
+
Unimplemented phases (5-7 in the template) return True (skip, don't fail).
|
|
404
|
+
|
|
405
|
+
### Current Composite Pattern: Video Recording with Audio
|
|
406
|
+
|
|
407
|
+
支持两种初始化方式:
|
|
408
|
+
|
|
409
|
+
**方式 A:从 VIDEO_PRODUCTION.md 统一规格生成**(推荐)
|
|
410
|
+
|
|
411
|
+
用一个文件描述完整流水线,`generate_all()` 自动拆解生成各子 spec。
|
|
412
|
+
|
|
413
|
+
参考 `standards/video-production-spec.md`,工具入口 `video-audio-compositing/scripts/utils/production_spec.py`:
|
|
414
|
+
|
|
415
|
+
```python
|
|
416
|
+
from utils.production_spec import generate_all
|
|
417
|
+
|
|
418
|
+
results = generate_all("VIDEO_PRODUCTION.md", task_dir, video_path, tts_dir)
|
|
419
|
+
# → RECORDING.md, SCRIPT.txt, COMPOSITING.md, SUBTITLE_SPEC.md, IMAGE_SLIDESHOW.md
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**方式 B:手工编写各子 spec 文件**
|
|
423
|
+
|
|
424
|
+
分别编写 RECORDING.md + SCRIPT.txt + COMPOSITING.md。
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
通用执行流程(Phase 1~7):
|
|
429
|
+
|
|
430
|
+
```
|
|
431
|
+
Phase 1 (text-to-speech):
|
|
432
|
+
├── 工作目录: tts/
|
|
433
|
+
├── 根据 SCRIPT.txt 逐行生成 audio_NNNNNN.mp3
|
|
434
|
+
└── 输出 audio_manifest.json(增量模式:已有 manifest 时只更新改动的行)
|
|
435
|
+
|
|
436
|
+
Phase 2 (browser-video-recording):
|
|
437
|
+
├── 工作目录: recording/
|
|
438
|
+
├── 读取 RECORDING.md(用户编写的操作指令,timeline-spec 格式)
|
|
439
|
+
├── 时间驱动:在 [HH:MM:SS.mmm] 指定的时间点执行操作
|
|
440
|
+
├── 输出 video.mp4 + timestamps.json
|
|
441
|
+
└── 写入 timeline.txt(含事件点和空白行)
|
|
442
|
+
|
|
443
|
+
Phase 3 (timeline-chart-preview):
|
|
444
|
+
├── 工作目录: timeline-chart-<hash6>/
|
|
445
|
+
├── 读取 COMPOSITING.md
|
|
446
|
+
├── 运行 generate_timeline_chart(format='both') — 默认生成 .txt + .png
|
|
447
|
+
├── 输出 timeline_chart.txt(文本条形图)
|
|
448
|
+
└── 输出 timeline_chart.png(图片版,暗色主题)
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**Data Flow:** 每个 phase 在自己的子目录中独立工作。跨 phase 引用使用相对路径(从 task 根目录出发)或 COMPOSITING.md 定义的路径。
|
|
452
|
+
|
|
453
|
+
**Every file cross between phases** must be documented in the task's `## Data Flow` table with a `格式说明` column pointing to the standard or skill reference that defines its schema. The executing agent reads this table to know which skill's reference to load before producing or consuming each file.
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## TASK.md Template
|
|
458
|
+
|
|
459
|
+
**Always read the actual template at `templates/TASK.md` when creating a task.**
|
|
460
|
+
|
|
461
|
+
Every TASK.md uses:
|
|
462
|
+
|
|
463
|
+
```markdown
|
|
464
|
+
# Task: <Name>
|
|
465
|
+
|
|
466
|
+
## Status
|
|
467
|
+
|
|
468
|
+
active — <brief description>
|
|
469
|
+
|
|
470
|
+
## Goal
|
|
471
|
+
|
|
472
|
+
<one-liner>
|
|
473
|
+
|
|
474
|
+
## Affinity (cluster task)
|
|
475
|
+
|
|
476
|
+
`local` | `any` | `<hash6>` | `<tag>,<tag>`
|
|
477
|
+
|
|
478
|
+
## Skills (用于跨 skill 组合任务)
|
|
479
|
+
|
|
480
|
+
- `<skill-name>` — <该 skill 在本任务中的用途>
|
|
481
|
+
|
|
482
|
+
## 环境要求
|
|
483
|
+
|
|
484
|
+
| 项目 | 最低要求 | 说明 |
|
|
485
|
+
|------|---------|------|
|
|
486
|
+
|
|
487
|
+
## Pre-checks (optional)
|
|
488
|
+
|
|
489
|
+
*Resolve before main checklist.*
|
|
490
|
+
- [ ] Investigate X
|
|
491
|
+
|
|
492
|
+
## Checklist
|
|
493
|
+
- [ ] Phase 1 — <understanding / research>
|
|
494
|
+
- [ ] Phase 2 — <execution / writing / coding>
|
|
495
|
+
- [ ] BREAK: <optional — delete if no pause needed here>
|
|
496
|
+
- [ ] Phase 3 — <verification / review / cleanup>
|
|
497
|
+
|
|
498
|
+
## Tracking
|
|
499
|
+
|
|
500
|
+
<!-- 可选。每个 phase 完成后加载 `task-tracker` skill 回写状态。
|
|
501
|
+
编排者读到此段后自动注入到各 phase 的 card/worker brief 中。 -->
|
|
502
|
+
|
|
503
|
+
| 参数 | 说明 |
|
|
504
|
+
|------|------|
|
|
505
|
+
| `task_dir` | 本 TASK.md 所在目录的绝对路径 |
|
|
506
|
+
| `phase` | 当前 phase 标识,如 `Phase 0: scrutiny-pipeline` |
|
|
507
|
+
| `executor` | 执行者名称 |
|
|
508
|
+
| `findings` | 关键发现(每行一条)|
|
|
509
|
+
| `outputs` | 产出文件路径(相对 task_dir)|
|
|
510
|
+
| `next` | 下一个 phase |
|
|
511
|
+
|
|
512
|
+
## Notes
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### Execution Logic
|
|
516
|
+
|
|
517
|
+
**第 0 步:验证 TASK.md 格式**
|
|
518
|
+
|
|
519
|
+
**TASK.md 关键字段规范(新 task 必须遵守):**
|
|
520
|
+
|
|
521
|
+
| 字段 | 格式 | 用途 | 解析 fallback |
|
|
522
|
+
|------|------|------|--------------|
|
|
523
|
+
| `# Task: <Name>` | 英文标题 | 任务标题(索引展示) | 任意 `# 中文标题` |
|
|
524
|
+
| `## Status` | 英文 | 任务状态(active/completed/—) | `## 状态` |
|
|
525
|
+
| `## Goal` | 英文 | 一行描述任务目标 | `## 目标` / `## 概述` |
|
|
526
|
+
| `## Checklist` | 英文 | `- [ ]` 步骤清单 | `## 步骤` |
|
|
527
|
+
| `## Notes` | 英文 | 备注信息 | `## 备注` |
|
|
528
|
+
| `## Related Tasks` | 英文 | 关联任务关系表(可选) | — |
|
|
529
|
+
|
|
530
|
+
`update-index.py` 优先解析英文关键字段,中文字段为向下兼容而支持。
|
|
531
|
+
**新 task 一律用英文关键字段。**
|
|
532
|
+
|
|
533
|
+
每次执行的第一步,检查 TASK.md 的结构:
|
|
534
|
+
|
|
535
|
+
1. `## Status` 是否存在,值是否合法(active / completed / paused / cancelled / failed)
|
|
536
|
+
2. `## Checklist` 是否存在
|
|
537
|
+
3. 每个 checklist 项是否为 `[ ]` 或 `[x]` 开头
|
|
538
|
+
4. BREAK 行是否放在正确的上下文位置
|
|
539
|
+
|
|
540
|
+
发现问题时**不自动修正**,先问你"TASK.md 第 X 行有问题,建议改为 YYY,可以吗?",得到确认后再改。
|
|
541
|
+
|
|
542
|
+
**硬性规则:没有 BREAK 就不停**
|
|
543
|
+
|
|
544
|
+
两个 checklist 项之间如果没有 `[ ] BREAK:` 行,执行完前一项后**直接执行下一项**,不问"要不要继续"。`[ ] BREAK:` 是唯一合法的暂停信号。以下情况都不需要停下来问:
|
|
545
|
+
- Phase X 完成之后
|
|
546
|
+
- `和 Phase X 同步进行` 标注的依赖满足后
|
|
547
|
+
- 看到 "等待 Phase X 完成" 但产物已存在时
|
|
548
|
+
|
|
549
|
+
**执行逻辑:**
|
|
550
|
+
|
|
551
|
+
The agent reads TASK.md from top to bottom:
|
|
552
|
+
|
|
553
|
+
```
|
|
554
|
+
逐行读取:
|
|
555
|
+
[x] DONE* → 跳过(用户已确认的断点)
|
|
556
|
+
[x] → 跳过(已完成)
|
|
557
|
+
[ ] BREAK:* → 输出已完成摘要,退出等待
|
|
558
|
+
[ ] → 执行此项
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
**Pre-checks section** (如果存在) → 只执行 Pre-checks 下的 `[ ]` 项,输出结果,等用户确认后再进入 Checklist。
|
|
562
|
+
|
|
563
|
+
**BREAK 行** → 执行到此时暂停,输出内容给用户。用户确认后将 `[ ] BREAK:` 改成 `[x] DONE:`,下次自动跳过。
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
**🔴 执行纪律:非 BREAK 不停** — 完成一个 `[ ]` 项后,立即找到下一个未完成的 `[ ]` 项。如果中间没有 `[ ] BREAK:`,直接执行,绝不询问"要不要继续"。用户对停顿询问非常反感。
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
## Operations Reference
|
|
571
|
+
|
|
572
|
+
### task_list
|
|
573
|
+
|
|
574
|
+
List all active tasks, inbox proposals, and declined items:
|
|
575
|
+
|
|
576
|
+
```bash
|
|
577
|
+
echo "=== Active Tasks ==="
|
|
578
|
+
printf "%-20s %-30s %-10s %7s %5s\n" "Timestamp" "Name" "Status" "Pending" "Done"
|
|
579
|
+
for d in "$HERMES_TASKS_ROOT"/2*/; do
|
|
580
|
+
[ -f "$d/TASK.md" ] || continue
|
|
581
|
+
dir=$(basename "$d")
|
|
582
|
+
ts=${dir%%.*}
|
|
583
|
+
name=${dir#*.}
|
|
584
|
+
status=$(grep -A2 '^## Status' "$d/TASK.md" | tail -1 | sed 's/^ *//; s/ —.*//')
|
|
585
|
+
pending=$(grep -c '^- \['" "'\]' "$d/TASK.md" 2>/dev/null)
|
|
586
|
+
done=$(grep -c '^- \[x\]' "$d/TASK.md" 2>/dev/null)
|
|
587
|
+
printf "%-20s %-30s %-10s %3d %3d\n" "$ts" "$name" "$status" "$pending" "$done"
|
|
588
|
+
done
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
For inbox and declined, see `scripts/task-list.sh` or inline:
|
|
592
|
+
|
|
593
|
+
```bash
|
|
594
|
+
echo "=== Inbox ==="
|
|
595
|
+
ls "$HERMES_TASKS_ROOT"/inbox/ 2>/dev/null || echo " (empty)"
|
|
596
|
+
echo "=== Declined ==="
|
|
597
|
+
ls "$HERMES_TASKS_ROOT"/declined/ 2>/dev/null || echo " (empty)"
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### task_create <name> [description] [--skill <skill-name>] [--ticket <ticket-id>]
|
|
601
|
+
|
|
602
|
+
Create a new task with timestamped directory. **After creation, show the user the README + checklist. Do NOT fill in placeholder content based on prior conversation.**
|
|
603
|
+
|
|
604
|
+
**流程:**
|
|
605
|
+
|
|
606
|
+
0. **确定任务类型** — 根据任务目标判断属于哪种类型(`analysis`、`video-pipeline` 等),加载 `references/task-types/<类型>.md`
|
|
607
|
+
1. 创建 `tasks/<ts>.<name>-<hash6>/` 目录和 `input/` `output/` `scripts/`(`output/` 下按需创建 `docs/` `logs/` 子目录)
|
|
608
|
+
2. **如果是从 inbox 文件创建任务** — 将 inbox 源文件复制到 `input/`(该文件成为 task 自持的输入材料,不依赖 inbox 的原始路径)
|
|
609
|
+
3. 调用 `create_task_meta()` 生成 `.hermes-task.json`
|
|
610
|
+
- 自动在 `default` 看板创建 kanban 卡片,卡片 ID 写入 `.hermes-task.json`
|
|
611
|
+
- 卡片标题: `<task-name> [task:<目录名>]`
|
|
612
|
+
- 卡片 assignee: `default`
|
|
613
|
+
4. **如果传了 `--ticket <id>`** — 将 ticket 信息写入 TASK.md 的 `## Related Tickets` 节,并将 task hash 写回 ticket 的 `task_id` 字段(实现双向关联)
|
|
614
|
+
5. 检查 `--skill` 指向的 skill 是否有 `scripts/create_task.py`:
|
|
615
|
+
|
|
616
|
+
```
|
|
617
|
+
~/.hermes/skills/<category>/<skill-name>/scripts/create_task.py
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
有则委托其创建 TASK.md 和其他模板文件(skill 自己决定要生成什么)。
|
|
621
|
+
没有则使用 task-framework 的默认 TASK.md 模板。
|
|
622
|
+
|
|
623
|
+
6. **Venv 管理(按需创建):**
|
|
624
|
+
遍历 `--skill` 涉及的 skills(或 TASK.md `## Skills` 中列出的),如果任意 skill 有 `scripts/` 目录(含代码),执行:
|
|
625
|
+
|
|
626
|
+
```bash
|
|
627
|
+
cd "$HERMES_TASKS_ROOT"/<ts>.<name>-<hash6>/
|
|
628
|
+
uv venv
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
然后对每个有代码的 skill:
|
|
632
|
+
|
|
633
|
+
```bash
|
|
634
|
+
# 如果 skill 有外部依赖
|
|
635
|
+
[ -f ~/.hermes/skills/<category>/<skill>/scripts/requirements.txt ] && \
|
|
636
|
+
uv pip install -r ~/.hermes/skills/<category>/<skill>/scripts/requirements.txt
|
|
637
|
+
|
|
638
|
+
# 如果 skill 有 scripts/utils/(通用代码),在 task 执行脚本中通过 sys.path 引用
|
|
639
|
+
# 不需要 pip install,详见执行模型章节
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
如果没有任何 skill 有代码 → 跳过 venv 创建,TASK.md 中不写 `## Venv`。
|
|
643
|
+
|
|
644
|
+
7. **按需追加 `## Venv` 节到 TASK.md:**
|
|
645
|
+
如果创建了 venv,在 TASK.md 末尾(Checklist 之前)追加:
|
|
646
|
+
|
|
647
|
+
```markdown
|
|
648
|
+
## Venv
|
|
649
|
+
|
|
650
|
+
路径: `.venv/`
|
|
651
|
+
创建: `uv venv`
|
|
652
|
+
依赖:
|
|
653
|
+
- <skill> (<外部包>)
|
|
654
|
+
执行: `uv run python <script>`
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
Skill 的 `scripts/create_task.py` 接口约定:
|
|
658
|
+
|
|
659
|
+
```python
|
|
660
|
+
#!/usr/bin/env python3
|
|
661
|
+
"""create_task.py — 由 task-framework 调用。
|
|
662
|
+
|
|
663
|
+
参数: <task_dir> <task_name> <task_hash>
|
|
664
|
+
返回: 0 (成功) 或非0 (失败)
|
|
665
|
+
|
|
666
|
+
职责: 写入 TASK.md、REQUIREMENTS.md、或其他模版文件、创建所需目录。
|
|
667
|
+
"""
|
|
668
|
+
import sys, os
|
|
669
|
+
task_dir = sys.argv[1]
|
|
670
|
+
task_name = sys.argv[2]
|
|
671
|
+
task_hash = sys.argv[3]
|
|
672
|
+
# ... skill 自己的逻辑
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
**示例:** 创建带 browser-screen-record-task 模板的任务:
|
|
676
|
+
|
|
677
|
+
```bash
|
|
678
|
+
task_create "demo-video" --skill browser-screen-record-task
|
|
679
|
+
# → task-framework 创建目录 + .hermes-task.json
|
|
680
|
+
# → 创建 .venv/ + 安装依赖(playwright)
|
|
681
|
+
# → 委托 browser-screen-record-task/scripts/create_task.py 写 TASK.md + REQUIREMENTS.md
|
|
682
|
+
# → 按需追加 ## Venv 节到 TASK.md
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
**Skill-specific templates:** If this task belongs to a specific skill (e.g., `browser-video-recording`), load that skill to get its template. Use task_create for the directory structure, then apply the skill's templates on top.
|
|
688
|
+
|
|
689
|
+
**RECORDING.md dual-file pattern:** Some skills (e.g., `browser-video-recording`) use two files: a standard `TASK.md` plus a skill-specific spec file (e.g., `RECORDING.md`). When creating a task for such skills, generate BOTH files from the skill's templates directory.
|
|
690
|
+
|
|
691
|
+
### task_view <name-or-hash>
|
|
692
|
+
|
|
693
|
+
按名或 hash 定位 task 并显示 README + TASK.md:
|
|
694
|
+
|
|
695
|
+
```bash
|
|
696
|
+
# 1. Try hash-first: find dir containing this hash
|
|
697
|
+
dir=$(ls -d "$HERMES_TASKS_ROOT"/*"${1}"*/ 2>/dev/null | head -1)
|
|
698
|
+
# 2. Fallback: try name glob (requires full name including hash6 suffix)
|
|
699
|
+
if [ -z "$dir" ]; then
|
|
700
|
+
dir=$(ls -d "$HERMES_TASKS_ROOT"/*."${1}"/ 2>/dev/null | head -1)
|
|
701
|
+
fi
|
|
702
|
+
if [ -z "$dir" ]; then
|
|
703
|
+
echo "Task not found: $1"
|
|
704
|
+
exit 1
|
|
705
|
+
fi
|
|
706
|
+
cat "$dir/README.md"
|
|
707
|
+
echo "---"
|
|
708
|
+
cat "$dir/TASK.md"
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
### task_set_status <name> <status> [reason]
|
|
712
|
+
|
|
713
|
+
Update the `## Status` line. Valid statuses:
|
|
714
|
+
|
|
715
|
+
| Status | Context | Description |
|
|
716
|
+
|--------|---------|-------------|
|
|
717
|
+
| `active` | Solo | Task is actively being worked on (non-cluster) |
|
|
718
|
+
| `paused` | Solo | Temporarily paused |
|
|
719
|
+
| `completed` | Solo | Finished (legacy, prefer `done`) |
|
|
720
|
+
| `cancelled` | Solo | Abandoned |
|
|
721
|
+
| `failed` | Solo/Cluster | Unrecoverable error; reset to `active` or `pending` to retry |
|
|
722
|
+
| `pending` | Cluster | Waiting to be claimed by a node |
|
|
723
|
+
| `claimed:<node_id>` | Cluster | Claimed by a node, not yet started |
|
|
724
|
+
| `in_progress` | Cluster | Being executed by the claiming node |
|
|
725
|
+
| `pending_review` | Cluster | Execution complete, awaiting creator confirmation |
|
|
726
|
+
| `done` | Cluster | Confirmed complete |
|
|
727
|
+
|
|
728
|
+
- `failed` 用于执行过程中遇到不可恢复的错误(如未找到特殊操作条目),中止执行等待修复。Cluster 中可重置为 `pending` 重新分发。
|
|
729
|
+
|
|
730
|
+
### task_inbox
|
|
731
|
+
|
|
732
|
+
List all inbox proposals. Inbox items are files or subdirectories under `tasks/inbox/`:
|
|
733
|
+
|
|
734
|
+
```markdown
|
|
735
|
+
tasks/inbox/
|
|
736
|
+
├── 20260510-生物年龄检测与逆转干预技术(深圳).pdf ← raw source file
|
|
737
|
+
├── feature-login/ ← directory with REQUIREMENTS.md
|
|
738
|
+
│ └── REQUIREMENTS.md
|
|
739
|
+
└── ...
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
Inbox items can be:
|
|
743
|
+
- **Raw files** (`.pdf`, `.docx`, `.xlsx`, `.md`, etc.) — treated as the task's input source material
|
|
744
|
+
- **Directories** with `REQUIREMENTS.md` — the directory may also contain additional source files
|
|
745
|
+
|
|
746
|
+
每个 inbox 子目录可以包含 `REQUIREMENTS.md`(可选),由人手工编写,描述任务的目标、输入、输出等。task-framework **不修改** REQUIREMENTS.md 的内容,只读取它作为任务创建的输入。
|
|
747
|
+
|
|
748
|
+
### task_inbox_accept <name>
|
|
749
|
+
|
|
750
|
+
将 inbox 条目转换为正式任务:
|
|
751
|
+
|
|
752
|
+
**如果 inbox 是 RAW 文件**(如 `.pdf`、`.docx`):
|
|
753
|
+
|
|
754
|
+
1. **创建任务目录** — `tasks/<ts>.<name>-<hash6>/`
|
|
755
|
+
2. **移动 source 文件到 task** — `mv inbox/<file> tasks/<ts>.<name>-<hash6>/input/`(源文件成为 task 自持材料,inbox 不留残影)
|
|
756
|
+
3. **生成 TASK.md** — 在 Data Flow 中将 source 路径写为 `input/<filename>`
|
|
757
|
+
4. **通知用户** — 展示 TASK.md 内容,等待确认
|
|
758
|
+
|
|
759
|
+
**如果 inbox 是目录(无论是否存在 REQUIREMENTS.md):**
|
|
760
|
+
|
|
761
|
+
核心原则:**改名为任务目录,整体挪入 tasks/,不 copy-leave**。避免 inbox 遗留和文件重复。
|
|
762
|
+
|
|
763
|
+
1. **读取目录内容** — 了解有哪些源文件(DESCRIPTION.md、REQUIREMENTS.md、图片、PDF 等)
|
|
764
|
+
2. **读取相关 skill 模板** — 根据任务类型加载对应 skill 的 templates/
|
|
765
|
+
3. **重命名并移动** — 将 inbox 目录原地改名为任务目录,然后整体移入 `tasks/`:
|
|
766
|
+
|
|
767
|
+
```bash
|
|
768
|
+
# 步骤:
|
|
769
|
+
# 1. 生成 timestamp + hash
|
|
770
|
+
ts=$(date +%Y%m%d-%H%M%S)
|
|
771
|
+
hash=$(python3 -c "import secrets; print(secrets.token_hex(3))")
|
|
772
|
+
new_name="${ts}.${name}-${hash}"
|
|
773
|
+
|
|
774
|
+
# 2. 重命名 inbox 目录(原地改名,都在 HERMES_TASKS_ROOT 内)
|
|
775
|
+
mv "$HERMES_TASKS_ROOT/inbox/$old_name" "$HERMES_TASKS_ROOT/$new_name"
|
|
776
|
+
|
|
777
|
+
# 3. 创建 task 骨架
|
|
778
|
+
mkdir -p "$HERMES_TASKS_ROOT/$new_name/output/docs" "$HERMES_TASKS_ROOT/$new_name/output/logs"
|
|
779
|
+
touch "$HERMES_TASKS_ROOT/$new_name/TASK.md" "$HERMES_TASKS_ROOT/$new_name/README.md"
|
|
780
|
+
|
|
781
|
+
# 4. 将原有文件归入 input/
|
|
782
|
+
# 原有的 DESCRIPTION.md / REQUIREMENTS.md / 图片 / PDF 等已在新目录下
|
|
783
|
+
# 它们自动成为 input/ 材料(注入到 input/ 子目录或保持原位)
|
|
784
|
+
# 如果想让结构更规整,将散落在根目录的文件移入 input/:
|
|
785
|
+
for f in "$HERMES_TASKS_ROOT/$new_name"/*; do
|
|
786
|
+
name=$(basename "$f")
|
|
787
|
+
case "$name" in
|
|
788
|
+
TASK.md|README.md|TASK_MEMORY.md|.hermes-task.json|input|output|logs|scripts|docs) ;;
|
|
789
|
+
*) mv "$f" "$HERMES_TASKS_ROOT/$new_name/input/" 2>/dev/null || true ;;
|
|
790
|
+
esac
|
|
791
|
+
done
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
4. **生成 .hermes-task.json** — 写入 hash、name、创建时间
|
|
795
|
+
5. **生成 TASK.md** — 根据 REQUIREMENTS.md 或 DESCRIPTION.md 的描述生成初步 checklist
|
|
796
|
+
6. **生成 README.md** — 简单概述
|
|
797
|
+
7. **通知用户** — 展示目录结构和 TASK.md 内容,等待确认
|
|
798
|
+
|
|
799
|
+
**注意:** 原有 inbox 目录被 rename+move 后,inbox 中不再有任何残余。如果用户仍需要通过 inbox 引用原始描述,可在 task 的 `input/` 中找到。
|
|
800
|
+
|
|
801
|
+
如果 inbox 条目是非目录且没有 REQUIREMENTS.md 的未知格式,降级为:创建空任务,等待用户填写。
|
|
802
|
+
|
|
803
|
+
### task_inbox_decline <name> [reason]
|
|
804
|
+
|
|
805
|
+
Move to `tasks/declined/<ts>.<name>/` with DECLINED.md.
|
|
806
|
+
|
|
807
|
+
### task_run <name> <command...>
|
|
808
|
+
|
|
809
|
+
Execute a command within the task context with logging.
|
|
810
|
+
|
|
811
|
+
### task_submit <name>
|
|
812
|
+
|
|
813
|
+
Delegate to subagent via `delegate_task()` — reads TASK.md, works through checklist.
|
|
814
|
+
|
|
815
|
+
### task_reset <name> [--hard]
|
|
816
|
+
|
|
817
|
+
将任务重置到初始状态,支持从头重新执行。
|
|
818
|
+
|
|
819
|
+
**--hard** (默认): 清空所有执行产物:
|
|
820
|
+
|
|
821
|
+
1. **清空 output/** — `rm -rf output/`(删除所有生成文件,input/ 不动)
|
|
822
|
+
2. **重置 TASK.md** — 将所有手写的 `[x]` 改为 `[ ]`(保留 `[x] DONE:` 断点,这是用户确认过的标记)
|
|
823
|
+
3. **重置状态** — `task_set_status <name> active`(从 `failed`、`completed`、`cancelled`、`paused` 均可重置)
|
|
824
|
+
4. **更新索引** — 运行 `python3 ~/.hermes/skills/software-development/task-framework/scripts/update-index.py`
|
|
825
|
+
|
|
826
|
+
> **注意:** `rm -rf output/` 是最安全的通用清理方式。`input/` 中的源文件(PDF、REQUIREMENTS.md、images/ 等)不受影响。不需要按任务类型区分清理策略。
|
|
827
|
+
|
|
828
|
+
**使用场景:** 任务执行后需要修改操作步骤并重新从头开始执行。
|
|
829
|
+
|
|
830
|
+
```bash
|
|
831
|
+
# 重置任务,清空所有产物
|
|
832
|
+
task_reset "my-task-name"
|
|
833
|
+
|
|
834
|
+
# 重置后查看任务
|
|
835
|
+
task_view "my-task-name"
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
---
|
|
839
|
+
|
|
840
|
+
## Root Index Files
|
|
841
|
+
|
|
842
|
+
Two auto-generated root index files live in `tasks/`:
|
|
843
|
+
|
|
844
|
+
| File | Purpose | Content |
|
|
845
|
+
|------|---------|---------|
|
|
846
|
+
| `tasks/README.md` | Directory façade | Summary table: timestamp, name, status, description |
|
|
847
|
+
| `tasks/TASKS.md` | Aggregated deep view | Per-task: status, goal, full checklist with done/total counts |
|
|
848
|
+
|
|
849
|
+
Both become stale when tasks are created, updated, or change status — **always regenerate after any task operation**.
|
|
850
|
+
|
|
851
|
+
### Regeneration
|
|
852
|
+
|
|
853
|
+
Use the unified script to rebuild both files:
|
|
854
|
+
|
|
855
|
+
```bash
|
|
856
|
+
python3 ~/.hermes/skills/software-development/task-framework/scripts/update-index.py
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
Output:
|
|
860
|
+
```
|
|
861
|
+
Updated:
|
|
862
|
+
/home/hauzer/studio/hermes/tasks/README.md (1464B)
|
|
863
|
+
/home/hauzer/studio/hermes/tasks/TASKS.md (6912B)
|
|
864
|
+
Found 9 active tasks
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
The script reads all `tasks/2*/TASK.md` files, extracts status/goal/checklist/notes, and writes both files with consistent formatting.
|
|
868
|
+
|
|
869
|
+
### 🔴 Pitfall: forgot to update indexes
|
|
870
|
+
|
|
871
|
+
A recurring issue — after creating, modifying, renaming, or deleting any task, always run the script above. This is now a mandatory post-operation step (see post-flight skill).
|
|
872
|
+
|
|
873
|
+
---
|
|
874
|
+
|
|
875
|
+
## Execution Strategies
|
|
876
|
+
|
|
877
|
+
| Strategy | When | How |
|
|
878
|
+
|----------|------|-----|
|
|
879
|
+
| **A — Inline** | Simple, <5 tool calls | Execute directly in conversation |
|
|
880
|
+
| **B — Script** | Well-defined steps, repeatable | Write `run.sh`, execute with `task_run` |
|
|
881
|
+
| **C — Subagent** | Needs reasoning, composite | `delegate_task()` with TASK.md as context |
|
|
882
|
+
| **D — Cron job** | Independent, outlive session | `cronjob(action='create', schedule='now')` |
|
|
883
|
+
|
|
884
|
+
Choose the lightest strategy that fits. Prefer A→B→C→D in that order.
|
|
885
|
+
|
|
886
|
+
### Script vs LLM Boundary
|
|
887
|
+
|
|
888
|
+
If an operation has a well-defined, deterministic workflow (file conversion, data transform, paper run, formatting), **write a script** — don't have the LLM re-reason through the same steps each time. The script is:
|
|
889
|
+
|
|
890
|
+
- Faster (no LLM latency)
|
|
891
|
+
- Deterministic (same input → same output)
|
|
892
|
+
- Auditable (check into git, review the logic)
|
|
893
|
+
|
|
894
|
+
If the operation needs open-ended reasoning (investigating a bug, designing a feature, evaluating results), **use Strategy C (Subagent)** — it brings the LLM's judgment to bear where it adds value.
|
|
895
|
+
|
|
896
|
+
## Scripts/ Directory Layout
|
|
897
|
+
|
|
898
|
+
### Scripts/ Directory Layout
|
|
899
|
+
|
|
900
|
+
Simple scripts go directly under `scripts/`:
|
|
901
|
+
|
|
902
|
+
```\nscripts/\n├── task-runner.sh ← logging wrapper\n├── update-index.py ← regenerate README.md + TASKS.md\n└── convert_md_to_pdf.py ← doc converter\n```
|
|
903
|
+
|
|
904
|
+
For complex tools that span multiple files (a multi-step data pipeline, a paper reproduction suite), create a **subdirectory**:
|
|
905
|
+
|
|
906
|
+
```
|
|
907
|
+
scripts/paper-reproduce/
|
|
908
|
+
├── run.sh ← entry point
|
|
909
|
+
├── download-data.py ← data preparation
|
|
910
|
+
├── run-experiment.py ← experiment execution
|
|
911
|
+
└── compare-results.py ← output comparison
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
The entry point (`run.sh` or `main.py`) should be the only file referenced from the operation's section in SKILL.md. The supporting files live alongside it.
|
|
915
|
+
|
|
916
|
+
## Task Lifecycle Management (`manage_task.py`)
|
|
917
|
+
|
|
918
|
+
`scripts/manage_task.py` 管理任务的完整生命周期。所有文件直接存放在任务目录下(`$HERMES_TASKS_ROOT/<ts>.<name>-<hash6>/`),单一存储,无镜像目录,无 symlink。
|
|
919
|
+
|
|
920
|
+
### 命令
|
|
921
|
+
|
|
922
|
+
```bash
|
|
923
|
+
# 初始化一个任务(创建目录 + TASK.md + TASK_MEMORY.md + .hermes-task.json)
|
|
924
|
+
python3 scripts/manage_task.py init 5d5a1a
|
|
925
|
+
python3 scripts/manage_task.py init tasks/20260605-233355.health-sales-demo-5d5a1a/
|
|
926
|
+
|
|
927
|
+
# 导出任务(tar.gz)
|
|
928
|
+
python3 scripts/manage_task.py export 5d5a1a
|
|
929
|
+
|
|
930
|
+
# 导入任务
|
|
931
|
+
python3 scripts/manage_task.py import tasks/20260605-233355.health-sales-demo-5d5a1a.tar.gz
|
|
932
|
+
|
|
933
|
+
# 按 hash 重建(查找最近 tar.gz)
|
|
934
|
+
python3 scripts/manage_task.py rebuild 5d5a1a
|
|
935
|
+
|
|
936
|
+
# 一次性迁移:将旧 ~/.hermes/personal/tasks/ 文件迁移到统一目录
|
|
937
|
+
python3 scripts/manage_task.py migrate
|
|
938
|
+
|
|
939
|
+
# 全量注册所有现有任务
|
|
940
|
+
python3 scripts/manage_task.py ensure-all
|
|
941
|
+
|
|
942
|
+
# 重建索引
|
|
943
|
+
python3 scripts/manage_task.py reindex
|
|
944
|
+
|
|
945
|
+
# 查看所有任务
|
|
946
|
+
python3 scripts/manage_task.py list
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
### tar.gz 格式
|
|
950
|
+
|
|
951
|
+
```
|
|
952
|
+
<ts>.<name>-<hash6>.tar.gz
|
|
953
|
+
└── <ts>.<name>-<hash6>/ ← 任务目录(含 input/ + output/ + TASK.md + TASK_MEMORY.md + .hermes-task.json)
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
### 跨机器迁移流程
|
|
957
|
+
|
|
958
|
+
```bash
|
|
959
|
+
# 源机器:导出
|
|
960
|
+
cd ~/studio/hermes
|
|
961
|
+
python3 ~/.hermes/skills/software-development/task-framework/scripts/manage_task.py export 5d5a1a
|
|
962
|
+
git add tasks/*5d5a1a*.tar.gz
|
|
963
|
+
git commit -m "export 5d5a1a"
|
|
964
|
+
git push
|
|
965
|
+
|
|
966
|
+
# 目标机器:拉取 + 导入
|
|
967
|
+
git pull
|
|
968
|
+
python3 ~/.hermes/skills/software-development/task-framework/scripts/manage_task.py rebuild 5d5a1a
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
### 旧任务(无 hash)的管理
|
|
972
|
+
|
|
973
|
+
无 hash 的任务(目录名不以 `-<hash6>` 结尾)需先重命名目录追加 hash 才能使用 `manage_task.py`。
|
|
974
|
+
|
|
975
|
+
### Skill 文件结构一览
|
|
976
|
+
|
|
977
|
+
```
|
|
978
|
+
task-framework/
|
|
979
|
+
├── SKILL.md ← 规则文档 + API 文档
|
|
980
|
+
├── scripts/
|
|
981
|
+
│ ├── task-runner.sh ← logging wrapper
|
|
982
|
+
│ ├── task_ref.py ← ref: hash resolution + cycle detection
|
|
983
|
+
│ └── convert_md_to_pdf.py ← doc converter
|
|
984
|
+
├── templates/
|
|
985
|
+
│ ├── TASK.md ← 任务模板
|
|
986
|
+
│ ├── run.py ← 自动化执行模板
|
|
987
|
+
│ └── TASK_MEMORY.md ← per-task memory 模板
|
|
988
|
+
└── references/
|
|
989
|
+
├── task-hash-naming.md ← hash 命名规则
|
|
990
|
+
├── task-format-validation.md
|
|
991
|
+
├── file-safety-lesson.md
|
|
992
|
+
├── auto-runner.md
|
|
993
|
+
└── ...
|
|
994
|
+
|
|
995
|
+
---
|
|
996
|
+
|
|
997
|
+
## How to Decompose a Task
|
|
998
|
+
|
|
999
|
+
When the user says "do X" and X is complex:
|
|
1000
|
+
|
|
1001
|
+
1. **Ask**: "这个任务看起来包含多个操作,我拆解成以下步骤,你看看对不对?"
|
|
1002
|
+
2. **List the operations** with brief description
|
|
1003
|
+
3. **Sequence them** with dependencies
|
|
1004
|
+
4. **For each operation**, note which strategy fits
|
|
1005
|
+
5. **Write TASK.md** with operations as checklist items
|
|
1006
|
+
6. **Present to user** for confirmation before executing
|
|
1007
|
+
|
|
1008
|
+
---
|
|
1009
|
+
|
|
1010
|
+
## Quality-Gate Integration
|
|
1011
|
+
|
|
1012
|
+
After modifying any TASK.md, README.md, or log file inside a task directory, run quality-gate before reporting done.
|
|
1013
|
+
|
|
1014
|
+
## Task Tracking (automatic phase completion log)
|
|
1015
|
+
|
|
1016
|
+
When TASK.md includes a `## Tracking` section, orchestrators (stratis/corvan/valros)
|
|
1017
|
+
inject tracking instructions into each dispatched card. The executor loads
|
|
1018
|
+
`task-tracker` skill after each phase to:
|
|
1019
|
+
- Mark the phase checkbox `[x]` in TASK.md
|
|
1020
|
+
- Append a structured entry to TASK_MEMORY.md
|
|
1021
|
+
- Run `update-index.py`
|
|
1022
|
+
|
|
1023
|
+
See `skills/task-tracker/SKILL.md` for the parameter interface.
|
|
1024
|
+
|
|
1025
|
+
---
|
|
1026
|
+
|
|
1027
|
+
## Skill 架构规范
|
|
1028
|
+
|
|
1029
|
+
所有 skill 应遵循 **通用工具 + 临时脚本生成** 模式:
|
|
1030
|
+
|
|
1031
|
+
```
|
|
1032
|
+
skill-name/
|
|
1033
|
+
├── SKILL.md ← 规则文档 + API 文档
|
|
1034
|
+
├── scripts/
|
|
1035
|
+
│ ├── utils/ ← 通用工具方法(可复用,不含任务逻辑)
|
|
1036
|
+
│ │ ├── __init__.py
|
|
1037
|
+
│ │ ├── module_a.py
|
|
1038
|
+
│ │ └── module_b.py
|
|
1039
|
+
│ ├── requirements.txt ← Python 依赖声明
|
|
1040
|
+
│ └── setup_venv.sh ← 创建 .venv + 安装依赖
|
|
1041
|
+
├── .venv/ ← 技能独立虚拟环境(gitignore)
|
|
1042
|
+
├── templates/ ← 骨架模板
|
|
1043
|
+
└── references/ ← 参考文档
|
|
1044
|
+
```
|
|
1045
|
+
|
|
1046
|
+
**规则:**
|
|
1047
|
+
|
|
1048
|
+
1. **`.venv/` 在 skill 目录内** — 每个 skill 独立管理依赖,`setup_venv.sh` 一键安装
|
|
1049
|
+
2. **通用方法放 `scripts/utils/`** — 不包含任何任务特定逻辑,纯工具函数
|
|
1050
|
+
3. **任务特定逻辑写临时脚本** — 执行时生成 `task_script.py` 到任务目录,执行完后可清理
|
|
1051
|
+
4. **临时脚本 import 通用方法** — `sys.path.insert(0, skill_scripts_path)` → `from utils.xxx import ...`
|
|
1052
|
+
5. **SKILL.md 是唯一定义规则的地方** — 通用方法不包含业务规则,规则在 SKILL.md 中,由 LLM 读取后生成临时脚本
|
|
1053
|
+
|
|
1054
|
+
## Phase Directory Rename Procedure
|
|
1055
|
+
|
|
1056
|
+
When renaming phase directories (e.g. `tts/` → `tts-a3f8c2/`), the change cascades across multiple files. **Do not just rename the directory** — update all cross-references:
|
|
1057
|
+
|
|
1058
|
+
### Files to update
|
|
1059
|
+
|
|
1060
|
+
| # | File | What to check |
|
|
1061
|
+
|---|------|---------------|
|
|
1062
|
+
| 1 | `TASK.md` — Data Flow table | All source/consumer phase paths |
|
|
1063
|
+
| 2 | `TASK.md` — Checklist | Phase names in parentheses `(phase-name)` — descriptive, no hash |
|
|
1064
|
+
| 3 | `COMPOSITING.md` — Video header | `video.mp4` path |
|
|
1065
|
+
| 4 | `COMPOSITING.md` — Timeline | Every `audio_*.mp3` / `video.mp4` path |
|
|
1066
|
+
| 5 | `COMPOSITING.md` — Output | `## Output` section path |
|
|
1067
|
+
| 6 | `RECORDING.md` — Output line | `output:` path |
|
|
1068
|
+
| 7 | `scripts/composite.py` | `OUTPUT = "..."` + `timeline_chart.txt` path |
|
|
1069
|
+
| 8 | All `.py` scripts | Hardcoded paths to renamed dirs |
|
|
1070
|
+
| 9 | `generate_timeline_chart()` calls | Text + image output paths, if `format='both'` |
|
|
1071
|
+
|
|
1072
|
+
### Step-by-step
|
|
1073
|
+
|
|
1074
|
+
1. **Plan the mapping** — which old dir → which new dir (with hash)
|
|
1075
|
+
2. **Rename dirs** — `mv old/ new-hash6/`
|
|
1076
|
+
3. **Update spec files** (COMPOSITING.md, RECORDING.md) — all paths
|
|
1077
|
+
4. **Update TASK.md** — `## Data Flow` table (use actual dir paths with hashes) + checklist `()` (descriptive phase names, no hash)
|
|
1078
|
+
5. **Update scripts** — any hardcoded paths (composite.py is the most common offender)
|
|
1079
|
+
6. **Verify** — grep for old path names across all task files; nothing should match except venv references and intended coincidences
|
|
1080
|
+
|
|
1081
|
+
### Best practice: avoid the need for rename
|
|
1082
|
+
|
|
1083
|
+
Generate hash suffixes at task creation time, not post-hoc. When `task_create` detects this is a multi-phase task, pre-assign hashes to all anticipated phase directories and bake them into TASK.md from the start. In the `()` use only the descriptive phase name (no hash) — the hash lives only in the directory name and Data Flow table paths.
|
|
1084
|
+
|
|
1085
|
+
### Timeline chart images also need update
|
|
1086
|
+
|
|
1087
|
+
If Phase 3 uses `generate_timeline_chart(..., format='both')`, the PNG output path is derived from the text output path (`{stem}.png`). Renaming the text path's directory automatically renames the image path too — no separate update needed, as long as both file paths share the same directory stem. If you override the output path in composite.py, update both the text and image generation paths there.
|
|
1088
|
+
|
|
1089
|
+
## Task Identity (`.hermes-task.json`)
|
|
1090
|
+
|
|
1091
|
+
每个任务在创建时生成 `.hermes-task.json`,作为任务的唯一标识和接口声明。
|
|
1092
|
+
|
|
1093
|
+
```json
|
|
1094
|
+
{
|
|
1095
|
+
"hash": "a3f8c2",
|
|
1096
|
+
"name": "任务名",
|
|
1097
|
+
"created_at": "2026-06-05T23:00:00",
|
|
1098
|
+
"outputs": {},
|
|
1099
|
+
"dependencies": [],
|
|
1100
|
+
"related": [],
|
|
1101
|
+
"supersedes": [],
|
|
1102
|
+
|
|
1103
|
+
"affinity": "any",
|
|
1104
|
+
"claimed_by": null,
|
|
1105
|
+
"requires": [],
|
|
1106
|
+
"required_by": [],
|
|
1107
|
+
"priority": 2
|
|
1108
|
+
}
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
| 字段 | 说明 |
|
|
1112
|
+
|------|------|
|
|
1113
|
+
| `hash` | 6 位随机字符串,全局唯一 |
|
|
1114
|
+
| `name` | 任务名(目录名 `ts.name` 中的 name 部分) |
|
|
1115
|
+
| `outputs` | 命名输出,key 是输出名,value 是路径。由各 phase 填充 |
|
|
1116
|
+
| `dependencies` | 依赖的其他任务 hash 列表(硬依赖,本任务开始前 must 完成) |
|
|
1117
|
+
| `related` | 主题相关/互为参考的其他任务 hash 列表(无硬依赖) |
|
|
1118
|
+
| `supersedes` | 本任务替代/废弃的旧任务 hash 列表 |
|
|
1119
|
+
| `affinity` | Cluster 亲和性:`local` / `any` / `<hash6>` / `<capability-tag>` |
|
|
1120
|
+
| `claimed_by` | 认领此任务的节点 hash6,未认领为 `null` |
|
|
1121
|
+
| `requires` | 硬依赖:这些 task hash 必须 `done` 后才能认领 |
|
|
1122
|
+
| `required_by` | 反向依赖:哪些 task 依赖本 task(下游创建时回写) |
|
|
1123
|
+
| `priority` | 优先级:0 (最高) ~ 3 (最低),默认 2 |
|
|
1124
|
+
|
|
1125
|
+
See [task-hash-naming.md](references/task-hash-naming.md) for the complete naming convention rationale.
|
|
1126
|
+
|
|
1127
|
+
### Named Outputs
|
|
1128
|
+
|
|
1129
|
+
Phase 完成后将产物路径注册为 named output:
|
|
1130
|
+
|
|
1131
|
+
```bash
|
|
1132
|
+
python3 -c "
|
|
1133
|
+
import json
|
|
1134
|
+
with open('.hermes-task.json') as f: d = json.load(f)
|
|
1135
|
+
d['outputs']['video'] = 'compositing-a3f8c2/output.mp4'
|
|
1136
|
+
with open('.hermes-task.json', 'w') as f: json.dump(d, f, indent=2)
|
|
1137
|
+
"
|
|
1138
|
+
```
|
|
1139
|
+
|
|
1140
|
+
其他任务通过 `ref:hash/output_name` 引用:
|
|
1141
|
+
|
|
1142
|
+
```
|
|
1143
|
+
ref:a3f8c2/video → 解析为 compositing-a3f8c2/output.mp4
|
|
1144
|
+
```
|
|
1145
|
+
|
|
1146
|
+
### 依赖声明
|
|
1147
|
+
|
|
1148
|
+
任务创建时或手动在 `.hermes-task.json` 中声明 `dependencies`:
|
|
1149
|
+
|
|
1150
|
+
```json
|
|
1151
|
+
{
|
|
1152
|
+
"hash": "def456",
|
|
1153
|
+
"name": "下游任务",
|
|
1154
|
+
"dependencies": ["a3f8c2", "b7e9d1"],
|
|
1155
|
+
"outputs": {}
|
|
1156
|
+
}
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1159
|
+
### `ref:` 解析
|
|
1160
|
+
|
|
1161
|
+
🔴 **IMPORTANT: resolve_ref globs `*{hash_id}*` against directory names.** The hash MUST be part of the task directory name for `ref:` resolution to work. Directory naming convention: `YYYYMMDD-HHMMSS.<name>-<hash6>/`. If the hash is only in `.hermes-task.json` and not the dir name, `ref:` lookups will return `FileNotFoundError`.
|
|
1162
|
+
|
|
1163
|
+
pipeline 或任意 skill 遇到 `ref:` 前缀时,调用以下逻辑:
|
|
1164
|
+
|
|
1165
|
+
```python
|
|
1166
|
+
import os, glob, json
|
|
1167
|
+
|
|
1168
|
+
def resolve_ref(ref_str, tasks_root='~/studio/hermes/tasks'):
|
|
1169
|
+
if not ref_str.startswith('ref:'):
|
|
1170
|
+
return ref_str
|
|
1171
|
+
parts = ref_str[4:].split('/', 1)
|
|
1172
|
+
hash_id = parts[0]
|
|
1173
|
+
output_name = parts[1] if len(parts) > 1 else None
|
|
1174
|
+
tasks_root = os.path.expanduser(tasks_root)
|
|
1175
|
+
matches = glob.glob(os.path.join(tasks_root, f'*{hash_id}*'))
|
|
1176
|
+
if not matches:
|
|
1177
|
+
raise FileNotFoundError(f'Task with hash {hash_id} not found')
|
|
1178
|
+
task_dir = matches[0]
|
|
1179
|
+
meta_path = os.path.join(task_dir, '.hermes-task.json')
|
|
1180
|
+
if not os.path.exists(meta_path):
|
|
1181
|
+
raise FileNotFoundError(f'.hermes-task.json not found in {task_dir}')
|
|
1182
|
+
with open(meta_path) as f:
|
|
1183
|
+
meta = json.load(f)
|
|
1184
|
+
if output_name:
|
|
1185
|
+
if output_name not in meta.get('outputs', {}):
|
|
1186
|
+
raise KeyError(f'Output \"{output_name}\" not declared')
|
|
1187
|
+
return os.path.join(task_dir, meta['outputs'][output_name])
|
|
1188
|
+
return task_dir
|
|
1189
|
+
```
|
|
1190
|
+
|
|
1191
|
+
### 循环依赖检测
|
|
1192
|
+
|
|
1193
|
+
创建/更新依赖时验证:
|
|
1194
|
+
|
|
1195
|
+
```python
|
|
1196
|
+
def check_cycles(meta, tasks_root):
|
|
1197
|
+
seen = [meta['hash']]
|
|
1198
|
+
stack = list(meta.get('dependencies', []))
|
|
1199
|
+
while stack:
|
|
1200
|
+
h = stack.pop()
|
|
1201
|
+
if h in seen:
|
|
1202
|
+
raise ValueError(f'Cycle detected: {h} already in {seen}')
|
|
1203
|
+
seen.append(h)
|
|
1204
|
+
matches = glob.glob(os.path.join(tasks_root, f'*{h}*'))
|
|
1205
|
+
if matches:
|
|
1206
|
+
dep_meta = json.load(open(os.path.join(matches[0], '.hermes-task.json')))
|
|
1207
|
+
stack.extend(dep_meta.get('dependencies', []))
|
|
1208
|
+
return True
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
## Task Memory (TASK_MEMORY.md)
|
|
1212
|
+
|
|
1213
|
+
每个任务目录下有一个 `TASK_MEMORY.md`,用于在跨 session 操作同一任务时保持上下文连贯性。
|
|
1214
|
+
|
|
1215
|
+
### 定位
|
|
1216
|
+
|
|
1217
|
+
| 文件 | 用途 | 谁写 | 生命周期 |
|
|
1218
|
+
|------|------|------|---------|
|
|
1219
|
+
| `TASK.md` | checklist、状态、要求 | 创建时填充 | 手动维护 |
|
|
1220
|
+
| `TASK_MEMORY.md` | 操作记录、决策、发现、阻塞原因 | 自动追加 | 按时间追加,永不删除 |
|
|
1221
|
+
| `logs/` | 命令输出 | 自动生成 | 可清理 |
|
|
1222
|
+
| `.hermes-task.json` | hash、outputs、依赖 | 自动维护 | 随任务更新 |
|
|
1223
|
+
|
|
1224
|
+
### 读写规则
|
|
1225
|
+
|
|
1226
|
+
**每次操作任何 task 之前:**
|
|
1227
|
+
|
|
1228
|
+
1. 检查该 task 目录下是否存在 `TASK_MEMORY.md`
|
|
1229
|
+
2. 如果存在 → 读到最后 50 行,了解最近的上下文(做了什么、卡在哪、有什么发现)
|
|
1230
|
+
3. 如果不存在 → 从 `templates/TASK_MEMORY.md` 复制模板后写入第一条记录
|
|
1231
|
+
|
|
1232
|
+
**每次操作之后(特别是跨 session 时):**
|
|
1233
|
+
|
|
1234
|
+
在 `TASK_MEMORY.md` 末尾追加一条新记录。
|
|
1235
|
+
|
|
1236
|
+
### 记录格式
|
|
1237
|
+
|
|
1238
|
+
```
|
|
1239
|
+
## 2026-06-06 13:00
|
|
1240
|
+
|
|
1241
|
+
**操作:** 重命名 task 目录 demo-video-production-v2 → health-sales-demo-5d5a1a
|
|
1242
|
+
**原因:** 遵循新命名规则,目录名需包含 hash
|
|
1243
|
+
**改动:**
|
|
1244
|
+
- 目录改名
|
|
1245
|
+
- .hermes-task.json name 字段更新
|
|
1246
|
+
- TASK.md 执行入口路径更新
|
|
1247
|
+
- tasks/README.md 索引重建
|
|
1248
|
+
**状态:** 完成,等待用户确认下一步
|
|
1249
|
+
**素材状态:** tts-a2c2bc(17段音频✅) image-slideshow-a2c2bc(封面✅) subtitle-gen-a2c2bc(字幕✅) browser-video-recording-a2c2bc(上次中断⚠️)
|
|
1250
|
+
|
|
1251
|
+
## 2026-06-06 14:00
|
|
1252
|
+
|
|
1253
|
+
**操作:** 准备运行 Phase 3 录制
|
|
1254
|
+
**问题:** dev server 端口 5173 不可达
|
|
1255
|
+
**解决:** tmux 重新启动 dev server
|
|
1256
|
+
**结果:** Phase 3 录制成功(138s, 1.8MB)
|
|
1257
|
+
**下一步:** Phase 4 合成
|
|
1258
|
+
```
|
|
1259
|
+
|
|
1260
|
+
### 记录什么
|
|
1261
|
+
|
|
1262
|
+
- ✅ **发生了什么** — 文件名改动、pipeline 阶段、关键命令
|
|
1263
|
+
- ✅ **为什么** — 决策理由(避免下次不知道为什么这么做)
|
|
1264
|
+
- ✅ **问题与解决方案** — 踩过的坑和怎么解决的
|
|
1265
|
+
- ✅ **素材状态清单** — 什么有了、什么没有、哪个坏了
|
|
1266
|
+
- ✅ **下一步** — 这个 session 结束时停在哪
|
|
1267
|
+
- ❌ 纯命令输出(放 logs/)
|
|
1268
|
+
- ❌ checklist 勾选状态(放 TASK.md)
|
|
1269
|
+
- ❌ 详细的技术规范(放 docs/)
|
|
1270
|
+
|
|
1271
|
+
### `task_reset` 时
|
|
1272
|
+
|
|
1273
|
+
`task_reset --hard` **不清除** `TASK_MEMORY.md`,只清 logs/ 和 docs/。重置后追加一条"任务已重置"记录。
|
|
1274
|
+
|
|
1275
|
+
### 跨 session 价值
|
|
1276
|
+
|
|
1277
|
+
当新 session 打开这个任务时,`TASK_MEMORY.md` 让 agent 立刻知道:
|
|
1278
|
+
- 上次做到哪一步
|
|
1279
|
+
- 为什么停下来
|
|
1280
|
+
- 有什么已知问题
|
|
1281
|
+
- 哪个素材能复用、哪个要重做
|
|
1282
|
+
|
|
1283
|
+
不需要翻整段对话历史来找上下文。
|
|
1284
|
+
|
|
1285
|
+
### 主动创建触发信号
|
|
1286
|
+
|
|
1287
|
+
TASK_MEMORY.md 不仅属于 `task_create` 创建的任务。当会话从简单询问演化为复杂工作时,应当**主动创建 task 目录和 TASK_MEMORY.md**。
|
|
1288
|
+
|
|
1289
|
+
**触发信号(任一达到即触发):**
|
|
1290
|
+
|
|
1291
|
+
| 信号 | 说明 | 示例 |
|
|
1292
|
+
|------|------|------|
|
|
1293
|
+
| 5+ 工具调用 | 本轮已调用了 5 次以上 terminal/write_file/patch | 修 bug → 发现新问题 → 讨论方案 → 实施 → 验证 |
|
|
1294
|
+
| 跨子系统变更 | 改动了两个以上独立子系统 | service-manager + doc server + registry |
|
|
1295
|
+
| 设计讨论 | 出现了多方案对比、取舍、决策记录 | 方案 A/B/C 对比 → 选定一个 |
|
|
1296
|
+
| 文件系统结构性变更 | 创建文件、迁移数据、改 schema | registry 格式迁移、新增 skill 目录 |
|
|
1297
|
+
| 用户明确要求 | 用户说"列个清单"、"动手吧"、"继续完善" | |
|
|
1298
|
+
|
|
1299
|
+
**触发后的操作:**
|
|
1300
|
+
|
|
1301
|
+
```bash
|
|
1302
|
+
# 1. 创建 task 目录(不打断当前工作流)
|
|
1303
|
+
TS=$(date +%Y%m%d-%H%M%S)
|
|
1304
|
+
HASH=$(python3 -c "import secrets; print(secrets.token_hex(3))")
|
|
1305
|
+
DIR="$HERMES_TASKS_ROOT/${TS}.<task-name>-${HASH}"
|
|
1306
|
+
mkdir -p "$DIR/output/docs" "$DIR/output/logs"
|
|
1307
|
+
|
|
1308
|
+
# 2. 写入 TASK_MEMORY.md 首条记录
|
|
1309
|
+
cat > "$DIR/TASK_MEMORY.md" << 'EOF'
|
|
1310
|
+
# Task Memory — <task-name>
|
|
1311
|
+
|
|
1312
|
+
## YYYY-MM-DD HH:MM
|
|
1313
|
+
|
|
1314
|
+
**操作:** <本轮已完成的操作>
|
|
1315
|
+
**发现:** <关键发现>
|
|
1316
|
+
**决策:** <做出的决策>
|
|
1317
|
+
**下一步:** <下一步要做什么>
|
|
1318
|
+
EOF
|
|
1319
|
+
|
|
1320
|
+
# 3. 更新索引
|
|
1321
|
+
python3 ~/.hermes/skills/software-development/task-framework/scripts/update-index.py
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
### 追溯创建
|
|
1325
|
+
|
|
1326
|
+
如果 post-flight 检查发现本轮达到了触发条件但没有 task 目录,应当**事后补建**:
|
|
1327
|
+
|
|
1328
|
+
1. 扫描本轮所有操作记录(memory、终端输出、文件修改)
|
|
1329
|
+
2. 按时间顺序提炼关键节点
|
|
1330
|
+
3. 每个节点写一条 TASK_MEMORY.md 记录(操作/发现/决策/下一步)
|
|
1331
|
+
4. 创建目录、写入、更新索引
|
|
1332
|
+
|
|
1333
|
+
补建时不需要写满全部细节——每个决策点提炼 2-5 行即可,重点是"为什么选了这个方案"和"踩了哪些坑"。
|
|
1334
|
+
|
|
1335
|
+
### 与 post-flight 联动
|
|
1336
|
+
|
|
1337
|
+
post-flight 的 Integrity Check 会检查"本轮的复杂程度是否达到了触发条件",
|
|
1338
|
+
Pending Action Scan 会处理"达到了但没有 task 目录 → 立即补建"。
|
|
1339
|
+
TASK_MEMORY.md 的创建和维护是 post-flight 后置链的固定组成部分。
|
|
1340
|
+
|
|
1341
|
+
- **`.hermes-task.json` 必须在任务根目录** — 和 TASK.md 同级
|
|
1342
|
+
- **任务被删除后引用断掉** — `resolve_ref` 会抛异常,上游任务要考虑重建
|
|
1343
|
+
- **循环依赖在写入时检测** — 不要在运行时才发现
|
|
1344
|
+
|
|
1345
|
+
| Pitfall | Correction |
|
|
1346
|
+
|---------|------------|
|
|
1347
|
+
| Treating a composite task as a single operation | Always decompose. Complex tasks benefit from separation. |
|
|
1348
|
+
| Skipping decomposition for "simple" coding | Even a simple feature needs: research → design → code → review. |
|
|
1349
|
+
| Choosing wrong strategy | 5+ tool calls or reasoning → don't use A (Inline), use C (Subagent). |
|
|
1350
|
+
| Operation catalog out of date | Add new operations as they're discovered. |
|
|
1351
|
+
| **🔴 Never fill task placeholders from conversation history** | When user says \"create a task named X\", create an empty template with all `{placeholder}` intact. Do NOT infer URL, steps, or operations from earlier chat context unless user explicitly says \"根据上面的对话\" or similar. Corrected multiple times — the user will delete and re-create if you guess. |\n| **🔴 File moves must be ln/cp + verify + rm** | Never `mv`. Use `ln <src> <dst>`, verify with `ls -la`, then `rm <src>`. |
|
|
1352
|
+
| **🔴 Missing `## 环境要求` in TASK.md** | Executor pre-flight forces this check. Always include it. |
|
|
1353
|
+
| **🔴 Confirm CWD before creating tasks** | Project root must have `tasks/` dir. If not, confirm user expects `~/studio/hermes/tasks/` as base. |
|
|
1354
|
+
| **🔴 "tasks" naming ambiguity + no manual management** | When user says "tasks" or "task", first disambiguate: (a) task-framework managed → use task_create/task_set_status/etc., never raw `mv`/`cp`/`rm` on task dirs; (b) generic concept → normal conversation. See `PROJECT_STRUCTURE.md` for the full convention. Corrected: manual `mv` on a task dir instead of using framework. |
|
|
1355
|
+
| 🔴 Log accumulation | Clean old logs with `rm tasks/*.<name>/logs/*.YYYYMMDD-*.log`. |
|
|
1356
|
+
| 🔴 Root index files stale | After creating/updating/deleting any task, run `python3 ~/.hermes/skills/software-development/task-framework/scripts/update-index.py` to regenerate both `tasks/README.md` and `tasks/TASKS.md`. Users rely on these indexes for overview. |
|
|
1357
|
+
| **🔴 Data Flow table not consulted** | In cross-skill composite tasks, a phase that produces a file (e.g. TTS → `audio_manifest.json`) must write it in the format expected by the consumer phase. The `## Data Flow` table's `格式说明` column tells you where to find that format spec. Don't guess the schema — load the referenced skill/reference file and read it. Corrected in discussion about how compositing finds audio manifest format. |
|
|
1358
|
+
| **`tasks/2*/` glob matches active tasks only** | Inbox/declined don't start with `2` — natural filtering. |
|
|
1359
|
+
| **`## Status` empty line matters** | `grep -A2` not `-A1` to skip blank line after header. |
|
|
1360
|
+
| LLM reasoning where a script would do | If you've repeated the same manual sequence twice, write a script. The LLM should handle judgment, not memorized mechanical steps. |
|
|
1361
|
+
| **🔴 Don't stop & ask between checklist items unless there's a BREAK** | Execution Logic says: `[ ] BREAK:` → pause; `[ ]` → execute immediately. After completing one item, scan for the next unchecked `[ ]`. If there's no BREAK between them, execute it right away — do NOT ask 'do you want to continue?'. User corrected: '继续呀!!!你为什么要听下呢?这里有说要break吗?' Parallel dependencies (e.g. 'and Phase 1 同步进行') don't imply you should wait for instructions — check if the dependency is already resolved and act. |
|
|
1362
|
+
| **🔴 Never modify REQUIREMENTS.md** | REQUIREMENTS.md is user-owned. If changes are needed, tell the user what to change and let them do it themselves. Do NOT edit it directly — the user won't know what changed. Corrected twice in one session. |
|
|
1363
|
+
| **🔴 Input source files go in input/, output/ is for generated files** | `task_reset --hard` does `rm -rf output/`. Any source file (PDF, DOCX, images, REQUIREMENTS.md) placed in `output/` will be lost. Always put source material in `input/`. |
|
|
1364
|
+
| **🔴 Inbox source files must be copied to task** | When creating a task from an inbox file (PDF/DOCX/etc.), copy the file into the task's `input/` directory. A Data Flow reference to `tasks/inbox/...` is fragile — the inbox item could be moved or deleted independently of the task. The task must be self-contained. |
|
|
1365
|
+
| **🔴 Design discussion ≠ execution signal** | When the user makes observations, suggestions, or asks how a system/skill/process should work (e.g. "在从 REQUIREMENTS.md 生成 RECORDING.md 的时候,xxx 应该 yyy"), they are in **design/discussion mode**. Do NOT start executing pipeline steps or making code changes based on a design opinion. Wait for explicit go-ahead ("可以了" / "继续" / "跑吧"). Corrected with extreme frustration — user hadn't finished their thought. |
|