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.
Files changed (56) hide show
  1. hermes_task_framework-1.0.0.dist-info/METADATA +7 -0
  2. hermes_task_framework-1.0.0.dist-info/RECORD +56 -0
  3. hermes_task_framework-1.0.0.dist-info/WHEEL +5 -0
  4. hermes_task_framework-1.0.0.dist-info/licenses/LICENSE +1 -0
  5. hermes_task_framework-1.0.0.dist-info/top_level.txt +1 -0
  6. task-framework/__init__.py +2 -0
  7. task-framework/skills/task-external-repos-pattern/SKILL.md +165 -0
  8. task-framework/skills/task-framework/CHANGELOG.md +45 -0
  9. task-framework/skills/task-framework/SKILL.md +1365 -0
  10. task-framework/skills/task-framework/docs/TASKS.md +3 -0
  11. task-framework/skills/task-framework/docs/architecture.dot +65 -0
  12. task-framework/skills/task-framework/docs/architecture.svg +188 -0
  13. task-framework/skills/task-framework/docs/product-requirements.md +65 -0
  14. task-framework/skills/task-framework/references/auto-runner.md +32 -0
  15. task-framework/skills/task-framework/references/composites/code-review-session.md +30 -0
  16. task-framework/skills/task-framework/references/composites/research.md +45 -0
  17. task-framework/skills/task-framework/references/composites/software-dev.md +41 -0
  18. task-framework/skills/task-framework/references/document-analysis-workflow.md +95 -0
  19. task-framework/skills/task-framework/references/file-safety-lesson.md +38 -0
  20. task-framework/skills/task-framework/references/generating-output-documents.md +166 -0
  21. task-framework/skills/task-framework/references/operations/code-write.md +30 -0
  22. task-framework/skills/task-framework/references/operations/document-write.md +185 -0
  23. task-framework/skills/task-framework/references/operations/info-search.md +27 -0
  24. task-framework/skills/task-framework/references/operations/web-research.md +57 -0
  25. task-framework/skills/task-framework/references/policy-time-metadata.md +137 -0
  26. task-framework/skills/task-framework/references/research-workflow.md +220 -0
  27. task-framework/skills/task-framework/references/task-format-validation.md +25 -0
  28. task-framework/skills/task-framework/references/task-hash-naming.md +40 -0
  29. task-framework/skills/task-framework/references/task-lifecycle-example.md +122 -0
  30. task-framework/skills/task-framework/references/task-overview-discovery.md +31 -0
  31. task-framework/skills/task-framework/references/task-types/analysis.md +60 -0
  32. task-framework/skills/task-framework/references/task-types/external-audit.md +56 -0
  33. task-framework/skills/task-framework/references/task-types/video-production-pipeline.md +77 -0
  34. task-framework/skills/task-framework/scripts/__init__.py +0 -0
  35. task-framework/skills/task-framework/scripts/__pycache__/manage_task.cpython-312.pyc +0 -0
  36. task-framework/skills/task-framework/scripts/__pycache__/task_ref.cpython-312.pyc +0 -0
  37. task-framework/skills/task-framework/scripts/__pycache__/update-index.cpython-311.pyc +0 -0
  38. task-framework/skills/task-framework/scripts/__pycache__/update-index.cpython-312.pyc +0 -0
  39. task-framework/skills/task-framework/scripts/convert_md_to_pdf.py +236 -0
  40. task-framework/skills/task-framework/scripts/manage_task.py +442 -0
  41. task-framework/skills/task-framework/scripts/task-runner.sh +42 -0
  42. task-framework/skills/task-framework/scripts/task_ref.py +119 -0
  43. task-framework/skills/task-framework/scripts/update-index.py +293 -0
  44. task-framework/skills/task-framework/templates/TASK.md +114 -0
  45. task-framework/skills/task-framework/templates/TASK_MEMORY.md +27 -0
  46. task-framework/skills/task-framework/templates/run.py +187 -0
  47. task-framework/skills/task-lifecycle-edge-cases/SKILL.md +84 -0
  48. task-framework/skills/task-lifecycle-edge-cases/references/task-5d5a1a-recovery-example.md +67 -0
  49. task-framework/skills/task-lifecycle-portability/SKILL.md +128 -0
  50. task-framework/skills/task-lifecycle-portability/references/design-session-20260611.md +32 -0
  51. task-framework/skills/task-lifecycle-portability/references/output-model-design.md +55 -0
  52. task-framework/skills/task-lifecycle-portability/references/pipeline-output-transition.md +41 -0
  53. task-framework/skills/task-lifecycle-portability/references/task-recovery-5d5a1a-example.md +27 -0
  54. task-framework/skills/task-lifecycle-portability/references/task-recovery-procedure.md +63 -0
  55. task-framework/skills/task-timestamp-convention/SKILL.md +72 -0
  56. task-framework/skills/task-tracker/SKILL.md +80 -0
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Unified task runner — single entry point for all phases.
4
+
5
+ Usage:
6
+ ./run.py — auto: find first unchecked item & execute
7
+ ./run.py phase<N> — run specific phase
8
+ ./run.py list — show checklist status
9
+
10
+ Auto mode (no args):
11
+ 1. Read TASK.md checklist, find first unchecked item
12
+ 2. If it's a BREAK, mark it done, continue to next Phase(s)
13
+ 3. Execute Phase(s) until next BREAK or end of list
14
+ """
15
+
16
+ import sys, os, subprocess, re
17
+
18
+ TASK_DIR = os.path.dirname(os.path.abspath(__file__))
19
+ TASK_MD = os.path.join(TASK_DIR, "TASK.md")
20
+ SCRIPTS = os.path.join(TASK_DIR, "scripts")
21
+ VENV_PY = os.path.expanduser("~/.venvs/playwright/bin/python")
22
+ PY = VENV_PY if os.path.exists(VENV_PY) else sys.executable
23
+
24
+
25
+ # ── Phase runners ──
26
+
27
+ def run_script(name, label):
28
+ path = os.path.join(SCRIPTS, name)
29
+ if not os.path.exists(path):
30
+ print(f" ❌ Script not found: {path}")
31
+ return False
32
+ print(f"\n{'='*60}")
33
+ print(f" {label}")
34
+ print(f"{'='*60}")
35
+ return subprocess.run([PY, path], cwd=TASK_DIR).returncode == 0
36
+
37
+
38
+ def phase1():
39
+ return run_script("gen_tts.py", "Phase 1: Text-to-Speech")
40
+
41
+
42
+ def phase2():
43
+ return run_script("record_timeline.py", "Phase 2: Browser Recording")
44
+
45
+
46
+ def phase3():
47
+ # Example: inline call with generate_timeline_chart
48
+ cmd = [
49
+ PY, "-c",
50
+ "import sys, os; "
51
+ "sys.path.insert(0, os.path.expanduser('~/.hermes/personal-suite/skills/video-audio-compositing/scripts')); "
52
+ "from utils.timeline import generate_timeline_chart; "
53
+ "generate_timeline_chart('COMPOSITING.md', 'timeline-chart-xxxxxx/timeline_chart.txt', format='both')"
54
+ ]
55
+ print(f"\n{'='*60}")
56
+ print(f" Phase 3: Timeline Chart Preview")
57
+ print(f"{'='*60}")
58
+ return subprocess.run(cmd, cwd=TASK_DIR).returncode == 0
59
+
60
+
61
+ def phase4():
62
+ return run_script("composite.py", "Phase 4: Compositing")
63
+
64
+
65
+ def phase5():
66
+ print(" ⏭ Phase 5 not implemented yet — skipping")
67
+ return True
68
+
69
+
70
+ def phase6():
71
+ print(" ⏭ Phase 6 not implemented yet — skipping")
72
+ return True
73
+
74
+
75
+ def phase7():
76
+ print(" ⏭ Phase 7 not implemented yet — skipping")
77
+ return True
78
+
79
+
80
+ PHASES = {
81
+ "phase1": phase1, "phase2": phase2, "phase3": phase3,
82
+ "phase4": phase4, "phase5": phase5, "phase6": phase6, "phase7": phase7,
83
+ }
84
+
85
+
86
+ # ── TASK.md checklist helpers ──
87
+
88
+ def parse_checklist():
89
+ with open(TASK_MD) as f:
90
+ lines = f.readlines()
91
+ items = []
92
+ for i, line in enumerate(lines):
93
+ m = re.match(r'^- \[([ x])\] (.+)', line)
94
+ if m:
95
+ items.append((i, m.group(2), m.group(1) == 'x'))
96
+ return items, lines
97
+
98
+
99
+ def mark_done(line_idx, lines):
100
+ lines[line_idx] = lines[line_idx].replace("- [ ]", "- [x]", 1)
101
+ with open(TASK_MD, 'w') as f:
102
+ f.writelines(lines)
103
+ return lines
104
+
105
+
106
+ def find_phase_num(text):
107
+ m = re.search(r'Phase (\d+)', text)
108
+ return int(m.group(1)) if m else None
109
+
110
+
111
+ def is_break(text):
112
+ return text.strip().startswith("BREAK")
113
+
114
+
115
+ # ── Auto mode ──
116
+
117
+ def run_auto():
118
+ items, lines = parse_checklist()
119
+ unchecked = [(idx, txt) for idx, txt, chk in items if not chk]
120
+ if not unchecked:
121
+ print("✅ All checklist items completed!")
122
+ return True
123
+
124
+ idx, txt = unchecked[0]
125
+ print(f"📋 First unchecked: {txt}")
126
+
127
+ if is_break(txt):
128
+ print(f" → Marking BREAK complete, continuing...")
129
+ lines = mark_done(idx, lines)
130
+ items, lines = parse_checklist()
131
+ unchecked = [(idx, txt) for idx, txt, chk in items if not chk]
132
+ if not unchecked:
133
+ print("✅ All items completed after marking BREAK!")
134
+ return True
135
+ idx, txt = unchecked[0]
136
+ print(f" → Next: {txt}")
137
+
138
+ for idx, txt in unchecked:
139
+ if is_break(txt):
140
+ print(f" ⏸ Stopping at BREAK: {txt}")
141
+ break
142
+ pnum = find_phase_num(txt)
143
+ if pnum is None:
144
+ print(f" ⏭ Skipping (not a phase): {txt}")
145
+ continue
146
+ phase_key = f"phase{pnum}"
147
+ fn = PHASES.get(phase_key)
148
+ if fn is None:
149
+ print(f" ❌ No runner for {phase_key}")
150
+ continue
151
+ print(f"\n ▶ Running {phase_key}...")
152
+ ok = fn()
153
+ if not ok:
154
+ print(f" ❌ {phase_key} failed!")
155
+ return False
156
+ lines = mark_done(idx, lines)
157
+
158
+ print(f"\n{'='*60}")
159
+ print(f" ✅ Auto-run complete")
160
+ print(f"{'='*60}")
161
+ return True
162
+
163
+
164
+ def cmd_list():
165
+ items, _ = parse_checklist()
166
+ for _, txt, chk in items:
167
+ status = "✅" if chk else "⬜"
168
+ print(f" {status} {txt}")
169
+
170
+
171
+ def main():
172
+ if len(sys.argv) >= 2:
173
+ cmd = sys.argv[1].strip().lower()
174
+ if cmd == "list":
175
+ cmd_list()
176
+ return 0
177
+ fn = PHASES.get(cmd)
178
+ if fn:
179
+ return 0 if fn() else 1
180
+ print(f"❌ Unknown: {cmd}\n")
181
+ print(__doc__)
182
+ return 1
183
+ return 0 if run_auto() else 1
184
+
185
+
186
+ if __name__ == "__main__":
187
+ sys.exit(main())
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: task-lifecycle-edge-cases
3
+ description: "Edge-case operations for task lifecycle — TASK.md recovery after loss, task resurrection from artifacts, conflict resolution when phase directories diverge from checklist."
4
+ version: 1.0.0
5
+ author: Hauzer S. Lee
6
+ license: MIT
7
+ category: software-development
8
+ platforms: [linux, macos]
9
+ metadata:
10
+ hermes:
11
+ tags: ['task', 'lifecycle', 'recovery', 'edge-case']
12
+ related_skills: ['task-framework', 'browser-screen-record-task']
13
+ ---
14
+
15
+ # Task Lifecycle Edge Cases
16
+
17
+ Recurring edge cases in task lifecycle management that the standard `task-framework` workflow doesn't explicitly cover.
18
+
19
+ ## TASK.md Recovery
20
+
21
+ When a task directory exists but `TASK.md` is missing (deleted, never created, or corrupted), reconstruct it from surrounding artifacts.
22
+
23
+ ### Step 1: Gather evidence
24
+
25
+ | Source | What it tells you |
26
+ |--------|------------------|
27
+ | `.hermes-task.json` | hash, name, outputs, dependencies |
28
+ | `TASK_MEMORY.md` | last session's state, what was done, what broke, what's next |
29
+ | `input/REQUIREMENTS.md` | original task spec |
30
+ | `output/` | all generated files |
31
+ | `.hermes-task.json` → `outputs` | what was produced and where |
32
+ | Root index (`tasks/index.md`) | aggregated status from last index run |
33
+
34
+ ### Step 2: Identify task type and load its governing skill
35
+
36
+ **Critical step.** Do NOT guess phase structure from memory or from other similar tasks.
37
+
38
+ 1. Scan directory for type-signature files — `REQUIREMENTS.md` + `RECORDING.md` + `COMPOSITING.md` → video-production task
39
+ 2. Load the relevant skill that defines this task type:
40
+ - Video production → `browser-screen-record-task`
41
+ - Document analysis → `task-framework`'s `references/task-types/`
42
+ - Other → the skill used to create the task (check `.hermes-task.json` or TASK_MEMORY.md)
43
+ 3. Read the skill's phase/流程/Checklist structure carefully before writing
44
+
45
+ ### Step 3: Map evidence to skill's phase structure
46
+
47
+ Cross-reference:
48
+ - Phase directories in `output/` → confirm each matches a skill-defined phase
49
+ - Outputs in `.hermes-task.json` → map each to the right phase's product (note: paths may be `output/...` prefixed for post-migration tasks)
50
+ - TASK_MEMORY.md execution notes → confirm sequence matches skill's defined order
51
+ - Parallel deps → check `和 X 同步进行` annotations match skill's flow table
52
+
53
+ ### Step 4: Write TASK.md
54
+
55
+ Follow the skill's template for:
56
+ - `## Skills` — list all skills the task type requires
57
+ - `## Data Flow` — map skill's phase table to actual directory hashes
58
+ - `## Checklist` — use skill's standard phase names and dependency annotations
59
+ - Mark all verified-completed items `[x]`
60
+ - Add `## Notes` for task-specific context
61
+
62
+ Key formatting:
63
+ - Phase dirs use `<short-name>-<hash6>/` (from actual dirs or .hermes-task.json)
64
+ - Checklist `()` uses descriptive phase names only, no hashes
65
+ - `和 Phase X 同步进行` for parallel phases
66
+ - `等待 Phase X 完成` for dependency phases
67
+
68
+ ### Step 5: Verify before marking done
69
+
70
+ Only mark phases `[x]` if the output artifact exists and can be verified (stat the file). If a phase was in-progress but incomplete, mark `[ ]` and note in `## Notes`.
71
+
72
+ ### Step 6: Update indexes
73
+
74
+ ```bash
75
+ python3 ~/.hermes/skills/software-development/task-framework/scripts/update-index.py
76
+ ```
77
+
78
+ ## Pitfalls
79
+
80
+ - 🔴 **Do NOT infer phase structure from prior conversation** — load the domain skill that governs this task type and use its defined phases
81
+ - 🔴 **Do NOT invent phases that don't match the skill's template** — subtitle-compositing and timeline-chart-preview are NOT separate phases in the standard video-production skill; they are subsumed by composite
82
+ - 🔴 **Do NOT reorder phases from the skill's defined sequence** — the skill encodes the correct dependency graph (e.g., timeline-composer must run after TTS to know audio durations, but before recording)
83
+ - 🔴 **Always verify material existence** — directory existing ≠ phase completed; check for the actual output file
84
+ - 🔴 **BREAK placement** — keep BREAKs exactly where the skill template places them, not where you guess they should be
@@ -0,0 +1,67 @@
1
+ # Health Sales Demo (5d5a1a) Recovery
2
+
3
+ Task: `20260605-233355.health-sales-demo-5d5a1a` — 主动健康销售管理系统演示视频
4
+
5
+ ## How TASK.md was lost (historical)
6
+
7
+ 1. Original TASK.md existed on June 7 with full 76-line checklist
8
+ 2. During pipeline bug fixing, exclusion-based cleanup was used (instead of `rm -rf output/`)
9
+ 3. TASK.md was accidentally caught in the cleanup
10
+ 4. Discovered missing on June 10 — agent noted it was gone but did NOT regenerate
11
+ 5. Remained missing until June 11 when user explicitly asked for it
12
+
13
+ ## Recovery process (June 11)
14
+
15
+ 1. Searched filesystem — no TASK.md found in task directory
16
+ 2. Read REQUIREMENTS.md → extracted timeline, language, viewport
17
+ 3. Read TASK_MEMORY.md (was already a symlink, content preserved) → knew last state (completed)
18
+ 4. Listed directory contents → found all phase dirs (tts-6d3e4c, compositing-6d3e4c, etc.)
19
+ 5. Read `.hermes-task.json` → outputs mapping confirmed all phases done
20
+ 6. Loaded `browser-screen-record-task` skill → got canonical phase decomposition
21
+ 7. Compared first draft against skill's template:
22
+ - Missing Phase 2 (timeline-composer)
23
+ - Wrong phase order (TTS→record→cover→subtitle instead of parallel)
24
+ - Extra phases (subtitle-compositing, timeline-chart-preview are subsumed by composite)
25
+ 8. Fixed TASK.md to match skill's phase structure, all items marked [x]
26
+
27
+ ## Subsequent migration to symlink + output/ model
28
+
29
+ After recovery, the task was migrated to the new structure:
30
+
31
+ ```
32
+ tasks/<ts>.<name>-5d5a1a/
33
+ ├── TASK.md → ~/.hermes/personal/tasks/5d5a1a/task.md
34
+ ├── TASK_MEMORY.md → ~/.hermes/personal/tasks/5d5a1a/memory.md
35
+ ├── .hermes-task.json → ~/.hermes/personal/tasks/5d5a1a/meta.json
36
+ ├── input/ ← REQUIREMENTS.md + images/
37
+ └── output/ ← all generated files
38
+ ```
39
+
40
+ Migration commands:
41
+ ```bash
42
+ # Create per-hash personal dir + symlinks
43
+ python3 manage_task.py init 5d5a1a
44
+
45
+ # Move user source files to input/
46
+ mkdir -p input && mv REQUIREMENTS.md input/ && mv images/ input/
47
+
48
+ # Move generated files to output/
49
+ mkdir -p output && mv RECORDING.md COMPOSITING.md IMAGE_SLIDESHOW.md output/
50
+ mv tts-*/ image-slideshow-*/ subtitle-gen-*/ browser-video-recording-*/ output/
51
+
52
+ # Verify clean worked
53
+ python3 pipeline.py --clean # only removes output/, leaves input/ + symlinks
54
+
55
+ # Re-export (now clean, no output/ in archive)
56
+ python3 manage_task.py export 5d5a1a
57
+ # → tar.gz contains: input/ + personal-tasks/5d5a1a/ only
58
+ ```
59
+
60
+ ## Lessons
61
+
62
+ - When you discover TASK.md is missing: regenerate IMMEDIATELY, don't defer
63
+ - Always verify recovered TASK.md against the governing skill's phase template
64
+ - Symlink for TASK.md + .hermes-task.json prevents permanent loss from cleanup
65
+ - Pipeline cleanup MUST use output/ boundary, never exclusion-based deletion
66
+ - For tasks with a hash, `manage_task.py relink <hash>` is the fastest recovery path
67
+ - `manage_task.py init <hash>` creates all three symlinks in one command
@@ -0,0 +1,128 @@
1
+ ---
2
+ name: task-lifecycle-portability
3
+ description: Task migration, export/import, and symlink-protection model. Covers tar.gz
4
+ snapshots, double-git repos for metadata + execution history, and manage.py lifecycle
5
+ commands (export/import/rebuild/relink).
6
+ version: 1.0.0
7
+ category: software-development
8
+ platforms:
9
+ - linux
10
+ - macos
11
+ author: Hauzer S. Lee
12
+ license: MIT
13
+ metadata:
14
+ hermes:
15
+ tags:
16
+ - migration
17
+ - software-development
18
+ ---
19
+
20
+
21
+ # Task Lifecycle & Portability
22
+
23
+ Manages task portability between machines and protects task metadata from destructive cleanup.
24
+
25
+ ## Symlink Protection Model
26
+
27
+ Three core files in each task directory are symlinks to `~/.hermes/personal/tasks/<hash>/`:
28
+
29
+ | Symlink (in task dir) | Target | Content |
30
+ |----------------------|--------|---------|
31
+ | `TASK.md` | `task.md` | Checklist, status, goal |
32
+ | `TASK_MEMORY.md` | `memory.md` | Decision log, per-session notes |
33
+ | `.hermes-task.json` | `meta.json` | Hash, outputs, dependencies |
34
+
35
+ Personal storage layout:
36
+
37
+ ```
38
+ ~/.hermes/personal/tasks/<hash>/
39
+ ├── .git/ ← tracks task.md, memory.md, meta.json history
40
+ ├── task.md ← TASK.md actual content
41
+ ├── memory.md ← TASK_MEMORY.md actual content
42
+ └── meta.json ← .hermes-task.json actual content
43
+ ```
44
+
45
+ **Protection guarantees:**
46
+ - `rm -rf` entire task dir → symlinks break, actual data in `~/.hermes/personal/tasks/<hash>/` remains
47
+ - Pipeline exclusion-based cleanup can't reach symlinked files
48
+ - `manage.py relink <hash>` restores broken symlinks in seconds
49
+ - Each `<hash>/` has independent git repo for metadata change history
50
+
51
+ ## Cleanup Discipline
52
+
53
+ **Only `output/` is safe to delete:**
54
+ - `task_reset --hard` = `rm -rf output/` + reset checkbox
55
+ - Never use exclusion-based deletion (`find . -not -name 'X' -delete` or positive-listing `rm -rf tts-*/ RECORDING.md ...`) — these always miss something or catch too much
56
+ - All generated files (RECORDING.md, COMPOSITING.md, IMAGE_SLIDESHOW.md, SUBTITLE_SPEC.md, phase directories, logs) live in `output/`
57
+
58
+ ## Directory Boundary
59
+
60
+ ```
61
+ tasks/<ts>.<name>-<hash6>/
62
+ ├── TASK.md (symlink)
63
+ ├── TASK_MEMORY.md (symlink)
64
+ ├── .hermes-task.json (symlink)
65
+ ├── input/ ← SOURCE: user-provided, NEVER delete
66
+ └── output/ ← GENERATED: pipeline owns this, safe to rm -rf
67
+ ```
68
+
69
+ ## Export / Import / Rebuild
70
+
71
+ `manage.py <hash>` commands:
72
+
73
+ | Command | What it does |
74
+ |---------|-------------|
75
+ | `export <hash>` | Follow symlinks, resolve to real content, produce `tasks/<ts>.<name>-<hash>.tar.gz` (excludes `output/`, includes `input/` + symlink targets + both `.git/` dirs) |
76
+ | `import <tar.gz>` | Extract to `tasks/` directory, create `~/.hermes/personal/tasks/<hash>/` if needed, restore all symlinks |
77
+ | `rebuild <hash>` | Find latest `<hash>.tar.gz` in `tasks/`, extract, restore symlinks. Generates semantic directory name from TASK.md title |
78
+ | `relink <hash>` | Recreate broken symlinks for an existing task directory (no tarball needed) |
79
+
80
+ **Actual script path:**
81
+ `~/.hermes/skills/software-development/task-framework/scripts/manage_task.py`
82
+
83
+ Usage: `python3 <path> <command> <arg>`
84
+
85
+ **Export behavior:**
86
+ - `tar --dereference` — follows symlinks, archive contains actual content, not symlink paths
87
+ - Output dir is excluded (it's regenerable via pipeline)
88
+ - Both git repos (`tasks/<dir>/.git/` and `~/.hermes/personal/tasks/<hash>/.git/`) are preserved in the tarball
89
+ - Import restores both git histories independently
90
+
91
+ **Cross-machine strategy:**
92
+ - No automatic merge — each machine's copy is an independent task
93
+ - To combine work from two machines: create a new task referencing both via `ref:<hash>/...`
94
+ - `tar.gz` in git repo acts as backup even if personal `~/.hermes/personal/tasks/` is not pushed
95
+
96
+ ## Old Tasks (Migration)
97
+
98
+ - Tasks already in `input/` + `output/` model: add symlinks via `manage.py init`
99
+ - Legacy flat tasks (REQUIREMENTS.md + images/ at root, no input/output): migrate if feasible; abandon if too old
100
+ - When you discover TASK.md is missing: **regenerate immediately from TASK_MEMORY.md + directory artifacts**, do not skip or defer
101
+
102
+ ## TASK.md Recovery (Edge Cases)
103
+
104
+ See `references/task-recovery-procedure.md` for the full step-by-step TASK.md recovery process when the file is missing or corrupted. Key principles:
105
+
106
+ 1. **Check the symlink target first** — if the hash-based personal backup exists, recovery is instant via `manage_task.py relink <hash>`
107
+ 2. **Identify task type** — scan for signature files (REQUIREMENTS.md + RECORDING.md etc.) and load the task-type's governing skill for its defined phase structure
108
+ 3. **Map evidence to phases** — cross-reference output directories, `.hermes-task.json` outputs, and TASK_MEMORY.md against the skill's phase templates
109
+ 4. **Write TASK.md** following the skill's template — don't invent phases, don't reorder
110
+
111
+ 🔴 Critical: Do NOT guess phase structure from memory. Load the domain skill that governs this task type and use its defined phases. Verify each phase's output file exists before marking complete.
112
+
113
+ **Real-world example:** `references/task-recovery-5d5a1a-example.md` — step-by-step walkthrough of recovering 5d5a1a's TASK.md after it was lost to exclusion-based cleanup.
114
+
115
+ ## Pipeline Output Model (Design)
116
+
117
+ See `references/output-model-design.md` for the full 2026-06-11 design rationale. The core decisions:
118
+
119
+ - **Output isolation**: All generated artifacts in `output/`, user materials in `input/`
120
+ - **Cleanup strategy**: `rm -rf output/` — never exclusion-based deletion
121
+ - **Symlink protection**: Three metadata files symlinked to personal storage `~/.hermes/personal/tasks/<hash>/`
122
+ - **Manage tool**: `manage_task.py` with `init/export/import/rebuild/relink/reindex` commands
123
+
124
+ **Implementation:** `references/pipeline-output-transition.md` — detailed diff of what changed in pipeline.py to adopt the output/ model.
125
+
126
+ ## Pitfalls
127
+ | `ref:` resolution breaks when hash-only (no directory match) | `.hermes-task.json` outputs should use `ref:hash/output_name` format. Directory must contain the hash in its name for `ref:` glob resolution. |
128
+ | Pipeline writes spec files to task root instead of output/ | All generated specs (RECORDING.md, COMPOSITING.md, IMAGE_SLIDESHOW.md, SUBTITLE_SPEC.md) belong in `output/`. Update pipeline scripts if they write to root. |
@@ -0,0 +1,32 @@
1
+ # Session Design Notes: Task Portability
2
+
3
+ From a session with Hauzer on 2026-06-11 discussing TASK.md loss and recovery architecture.
4
+
5
+ ## Problem
6
+
7
+ Pipeline exclusion-based deletion (`rm -rf tts-*/ RECORDING.md ...` or `find . -not -name 'REQUIREMENTS.md' -delete`) destroyed TASK.md because it was a regular file in the task root. User observed: "你那次是排除式删除,把除了 REQUIREMENTS.md 之外的很多有用的文件都删光了."
8
+
9
+ ## Solution Architecture (agreed design)
10
+
11
+ Three-layer protection:
12
+
13
+ 1. **Directory isolation** — input/ (source) + output/ (generated) boundary. Pipeline only touches output/. Never exclusion-based deletion at task root.
14
+
15
+ 2. **Symlink protection** — TASK.md, TASK_MEMORY.md, .hermes-task.json all symlink to `~/.hermes/personal/tasks/<hash>/`. rm -rf task dir only breaks symlinks; actual content survives.
16
+
17
+ 3. **Tar.gz portability** — `manage.py export` creates self-contained snapshot with resolved content (no symlinks in archive), both git repos preserved. `import` restores symlinks on target machine.
18
+
19
+ ## Key Decisions
20
+
21
+ - output/ excluded from tar.gz (regenerable)
22
+ - tar.gz committed to git (storage cost accepted)
23
+ - Cross-machine: no merge, independent tasks. Manual fusion via ref: links.
24
+ - `~/.hermes/personal/tasks/<hash>/` git can bare-run (no upstream). Metadata tracking > remote collaboration.
25
+ - Old tasks: migrate if feasible, abandon if not.
26
+
27
+ ## Manage.py Split
28
+
29
+ | Responsibility | Skill | Commands |
30
+ |---|---|---|
31
+ | Note-taking (observer, file-agnostic) | task-memory | append, read |
32
+ | Lifecycle (orchestrator, manages locations) | task-framework | init, relink, export, import, rebuild, reindex |
@@ -0,0 +1,55 @@
1
+ # Pipeline Output Model Design (resolved 2026-06-11)
2
+
3
+ ## Problem
4
+
5
+ Pipeline cleanup using exclusion-based deletion (`find ... -not -name X -exec rm`) or positive-listing always either misses cleanup targets or accidentally deletes user files. Task-framework metadata files (TASK.md, TASK_MEMORY.md, .hermes-task.json) mixed with pipeline artifacts in the same directory — cleanup couldn't distinguish them.
6
+
7
+ ## Solution
8
+
9
+ ### Directory isolation
10
+
11
+ All generated artifacts go into `output/` subdirectory; `input/` holds user source materials:
12
+
13
+ ```
14
+ tasks/<ts>.<name>-<hash6>/
15
+ ├── TASK.md → symlink to ~/.hermes/personal/tasks/<hash>/task.md
16
+ ├── TASK_MEMORY.md → symlink
17
+ ├── .hermes-task.json → symlink
18
+ ├── input/
19
+ │ ├── REQUIREMENTS.md
20
+ │ └── images/
21
+ └── output/
22
+ ├── tts-<hash6>/
23
+ ├── RECORDING.md
24
+ ├── COMPOSITING.md
25
+ └── compositing-<hash6>/output.mp4
26
+ ```
27
+
28
+ ### Cleanup strategy
29
+
30
+ ```bash
31
+ # pipeline.py --clean
32
+ rm -rf output/
33
+
34
+ # task_reset --hard
35
+ rm -rf output/ + reset checkboxes
36
+ ```
37
+
38
+ Both entry points clean `output/` uniformly, never conflicting.
39
+
40
+ ### Symlink protection
41
+
42
+ Three core files all symlinked to `~/.hermes/personal/tasks/<hash>/`. A `rm -rf` of the entire task directory only removes symlinks — actual data is preserved.
43
+
44
+ ### Manage tool
45
+
46
+ `manage_task.py` commands (in task-framework skill's `scripts/`):
47
+
48
+ | Command | Action |
49
+ |---------|--------|
50
+ | `init <hash>` | Create per-hash directory + three symlinks |
51
+ | `export <hash>` | Package tar.gz (dereference symlinks) |
52
+ | `import <file>` | Restore from tar.gz |
53
+ | `rebuild <hash>` | Find hash tar.gz and import |
54
+ | `relink <hash>` | Rebuild symlinks |
55
+ | `reindex` | Rebuild ~/.hermes/personal/tasks/index.md |
@@ -0,0 +1,41 @@
1
+ # Pipeline Output Model Transition (2026-06-11)
2
+
3
+ ## What Changed
4
+
5
+ `video-production-pipeline/scripts/pipeline.py` was updated to write all generated files to `output/` instead of the task root.
6
+
7
+ | Before | After |
8
+ |--------|-------|
9
+ | RECORDING.md at root | output/RECORDING.md |
10
+ | COMPOSITING.md at root | output/COMPOSITING.md |
11
+ | IMAGE_SLIDESHOW.md at root | output/IMAGE_SLIDESHOW.md |
12
+ | SUBTITLE_SPEC.md at root | output/SUBTITLE_SPEC.md |
13
+ | tts-<hash6>/ at root | output/tts-<hash6>/ |
14
+ | image-slideshow-* at root | output/image-slideshow-*/ |
15
+ | subtitle-gen-* at root | output/subtitle-gen-*/ |
16
+ | browser-video-recording-* at root | output/browser-video-recording-*/ |
17
+ | compositing-* at root | output/compositing-*/ |
18
+ | REQUIREMENTS.md at root | input/REQUIREMENTS.md (fallback to root) |
19
+ | `--clean` positive-list | `rm -rf output/` |
20
+
21
+ ## Why
22
+
23
+ Exclusion-based deletion (`find . -not -name 'REQUIREMENTS.md' -delete` or positive-listing `rm -rf tts-*/ RECORDING.md ...`) destroyed TASK.md because it was a regular file in the task root. The structural fix: put all generated files in a single `output/` directory, then cleaning is simply `rm -rf output/`.
24
+
25
+ ## Migration
26
+
27
+ Existing pipeline tasks were migrated manually:
28
+ 1. Created `input/` + `output/` dirs
29
+ 2. Moved REQUIREMENTS.md + images/ into `input/`
30
+ 3. Moved all generated specs and phase dirs into `output/`
31
+ 4. TASK.md, TASK_MEMORY.md, .hermes-task.json converted to symlinks
32
+
33
+ ## TTS cache location
34
+
35
+ TTS cache scanning now looks in `output/` directory for existing tts-* dirs:
36
+ - Old: `os.listdir(TASK_DIR)` → look for tts-* at root
37
+ - New: `os.listdir(os.path.join(TASK_DIR, OUTPUT_DIR))` → look for tts-* under output/
38
+
39
+ ## script path
40
+
41
+ `~/.hermes/skills/media/video-production-pipeline/scripts/pipeline.py`
@@ -0,0 +1,27 @@
1
+ # TASK.md Recovery: 5d5a1a (2026-06-11)
2
+
3
+ ## Scenario
4
+
5
+ Agent asked to find TASK.md for task `5d5a1a`. It didn't exist — deleted weeks earlier by exclusion-based cleanup. Only TASK_MEMORY.md and the phase directories remained.
6
+
7
+ ## Process
8
+
9
+ 1. **Identify task type** — scanned task directory. Found REQUIREMENTS.md + RECORDING.md + COMPOSITING.md → video production pipeline task.
10
+ 2. **Load governing skill** — `skill_view('browser-screen-record-task')` for the phase template.
11
+ 3. **Map evidence to phases** — cross-referenced phase directories (tts-6d3e4c/, browser-video-recording-6d3e4c/, compositing-6d3e4c/) against the skill's phase table.
12
+ 4. **Read TASK_MEMORY.md** — confirmed final output: 174.1s / 5.8MB, all phases complete.
13
+ 5. **Write TASK.md** following skill's template — used the correct phase decomposition (1a/b/c parallel → 2 timeline-composer → 3 recording → 4 composite), matching `browser-screen-record-task`'s defined phases.
14
+ 6. **Verify** — checked output files exist, status = completed.
15
+
16
+ ## Key Lesson
17
+
18
+ Phase structure must come from the domain skill, not guessed from memory or prior conversation. When I initially wrote the TASK.md, I used my own phase order (missing timeline-composer, wrong parallel grouping). The user corrected: "你可以参考 browser-screen-record-task 这个 skill,看看你的 phases 分解的对不对".
19
+
20
+ ## Recovery from symlink protection (future)
21
+
22
+ If TASK.md was a symlink and the personal backup exists:
23
+ ```bash
24
+ # Instant recovery:
25
+ manage_task.py relink 5d5a1a
26
+ ```
27
+ No content reconstruction needed — the symlink target `~/.hermes/personal/tasks/5d5a1a/task.md` still has the content.