hermes-task-framework 1.2.0__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/PKG-INFO +1 -1
  2. hermes_task_framework-1.3.0/hermes_task_framework/skills/compact-directory-memory/SKILL.md +167 -0
  3. hermes_task_framework-1.3.0/hermes_task_framework/skills/compact-directory-memory/scripts/manage_directory_context.py +127 -0
  4. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-archaeology/SKILL.md +41 -0
  5. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-artifact-integrity/SKILL.md +72 -0
  6. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-artifact-integrity/references/task-root-relocation.md +31 -0
  7. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-artifact-integrity/scripts/task_integrity.py +177 -0
  8. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-aware-project-work/SKILL.md +42 -0
  9. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-context-storage/SKILL.md +88 -0
  10. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-cross-machine-sync/SKILL.md +67 -0
  11. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-cross-machine-sync/scripts/task_git_sync.py +118 -0
  12. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/SKILL.md +102 -16
  13. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/scripts/manage_task.py +82 -70
  14. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-framework/scripts/task_api.py +195 -0
  15. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/scripts/task_ref.py +2 -2
  16. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/scripts/update-index.py +3 -3
  17. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-framework/templates/MEMORY.md +9 -0
  18. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/templates/TASK.md +3 -0
  19. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/templates/run.py +13 -13
  20. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-lifecycle-discipline/SKILL.md +78 -0
  21. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-lifecycle-edge-cases/references/task-5d5a1a-recovery-example.md +19 -0
  22. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-lifecycle-portability/SKILL.md +66 -0
  23. hermes_task_framework-1.3.0/hermes_task_framework/skills/task-lifecycle-portability/references/output-model-design.md +26 -0
  24. hermes_task_framework-1.3.0/hermes_task_framework/tests/test_directory_context.py +58 -0
  25. hermes_task_framework-1.3.0/hermes_task_framework/tests/test_skill_ownership.py +62 -0
  26. hermes_task_framework-1.3.0/hermes_task_framework/tests/test_task_api.py +84 -0
  27. hermes_task_framework-1.3.0/hermes_task_framework/tests/test_task_git_sync.py +50 -0
  28. hermes_task_framework-1.3.0/hermes_task_framework/tests/test_task_integrity.py +70 -0
  29. hermes_task_framework-1.3.0/hermes_task_framework/tests/test_task_root_resolution.py +149 -0
  30. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework.egg-info/PKG-INFO +1 -1
  31. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework.egg-info/SOURCES.txt +20 -5
  32. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/pyproject.toml +1 -1
  33. hermes_task_framework-1.2.0/hermes_task_framework/skills/task-lifecycle-edge-cases/references/task-5d5a1a-recovery-example.md +0 -66
  34. hermes_task_framework-1.2.0/hermes_task_framework/skills/task-lifecycle-portability/SKILL.md +0 -115
  35. hermes_task_framework-1.2.0/hermes_task_framework/skills/task-lifecycle-portability/references/design-session-20260611.md +0 -31
  36. hermes_task_framework-1.2.0/hermes_task_framework/skills/task-lifecycle-portability/references/output-model-design.md +0 -55
  37. hermes_task_framework-1.2.0/hermes_task_framework/skills/task-lifecycle-portability/references/pipeline-output-transition.md +0 -41
  38. hermes_task_framework-1.2.0/hermes_task_framework/skills/task-lifecycle-portability/references/task-recovery-5d5a1a-example.md +0 -27
  39. hermes_task_framework-1.2.0/hermes_task_framework/skills/task-lifecycle-portability/references/task-recovery-procedure.md +0 -58
  40. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/LICENSE +0 -0
  41. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/README.md +0 -0
  42. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/__init__.py +0 -0
  43. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-external-repos-pattern/SKILL.md +0 -0
  44. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/CHANGELOG.md +0 -0
  45. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/docs/TASKS.md +0 -0
  46. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/docs/architecture.dot +0 -0
  47. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/docs/architecture.svg +0 -0
  48. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/docs/product-requirements.md +0 -0
  49. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/auto-runner.md +0 -0
  50. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/composites/code-review-session.md +0 -0
  51. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/composites/research.md +0 -0
  52. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/composites/software-dev.md +0 -0
  53. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/document-analysis-workflow.md +0 -0
  54. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/file-safety-lesson.md +0 -0
  55. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/generating-output-documents.md +0 -0
  56. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/operations/code-write.md +0 -0
  57. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/operations/document-write.md +0 -0
  58. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/operations/info-search.md +0 -0
  59. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/operations/web-research.md +0 -0
  60. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/policy-time-metadata.md +0 -0
  61. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/research-workflow.md +0 -0
  62. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/task-format-validation.md +0 -0
  63. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/task-hash-naming.md +0 -0
  64. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/task-lifecycle-example.md +0 -0
  65. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/task-overview-discovery.md +0 -0
  66. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/task-types/analysis.md +0 -0
  67. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/task-types/external-audit.md +0 -0
  68. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/references/task-types/video-production-pipeline.md +0 -0
  69. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/scripts/__init__.py +0 -0
  70. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/scripts/convert_md_to_pdf.py +0 -0
  71. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/scripts/task-runner.sh +0 -0
  72. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-framework/templates/CHANGELOG.md +0 -0
  73. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-lifecycle-edge-cases/SKILL.md +0 -0
  74. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-timestamp-convention/SKILL.md +0 -0
  75. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework/skills/task-tracker/SKILL.md +0 -0
  76. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework.egg-info/dependency_links.txt +0 -0
  77. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/hermes_task_framework.egg-info/top_level.txt +0 -0
  78. {hermes_task_framework-1.2.0 → hermes_task_framework-1.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hermes-task-framework
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: Structured task management skills for Hermes Agent — task creation, decomposition, stage gates
5
5
  Project-URL: Source, https://github.com/nuffin/hermes-task-framework-pip
6
6
  Requires-Python: >=3.11
@@ -0,0 +1,167 @@
1
+ ---
2
+ author: Hauzer S. Lee
3
+ category: software-development
4
+ description: Manage paired MEMORY.md/CHANGELOG.md in flat or nested directory contexts.
5
+ license: MIT
6
+ metadata:
7
+ hermes:
8
+ scenes:
9
+ - hermes
10
+ - coding
11
+ tags:
12
+ - memory
13
+ - changelog
14
+ - directory-context
15
+ - hierarchical-memory
16
+ - task-framework
17
+ relations:
18
+ - type: complemented_by
19
+ target: task-context-storage
20
+ properties:
21
+ reason: task-context-storage defines which persistence layer owns each fact
22
+ strength: strong
23
+ name: compact-directory-memory
24
+ platforms:
25
+ - linux
26
+ - macos
27
+ version: 3.0.0
28
+ ---
29
+
30
+ # Compact Directory Memory
31
+
32
+ The authoritative format and maintenance skill for paired `MEMORY.md` and `CHANGELOG.md` files inside projects, tasks, and other directory-managed entities.
33
+
34
+ `task-framework` decides when task context must be loaded. This skill owns how directory context is structured, formatted, created, read, updated, and verified.
35
+
36
+ ## Context pair
37
+
38
+ | File | Meaning | Update mode |
39
+ |------|---------|-------------|
40
+ | `MEMORY.md` | Stable expected-state facts, constraints, paths, interfaces, and conventions | Replace stale facts; keep compact |
41
+ | `CHANGELOG.md` | Chronological operations, decisions, verification, failures, and next steps | Append; never rewrite history |
42
+
43
+ Transient runtime status never belongs in `MEMORY.md`. Record observed execution results in `CHANGELOG.md`.
44
+
45
+ ## MEMORY.md format
46
+
47
+ ```text
48
+ <one declarative fact paragraph>
49
+
50
+ §
51
+
52
+ <another declarative fact paragraph>
53
+
54
+ §
55
+
56
+ 🔴 <critical invariant>
57
+ ```
58
+
59
+ Rules:
60
+
61
+ - One fact per paragraph, separated by `§` on its own line.
62
+ - No headings, tables, tags, or frontmatter.
63
+ - Use declarative facts, not instructions.
64
+ - Use `🔴` only for enforced invariants.
65
+ - Remove or replace stale facts instead of retaining historical versions.
66
+ - Prefer expected configuration over transient observations.
67
+ - Keep reusable procedures in skills, not MEMORY.md.
68
+
69
+ ## CHANGELOG.md format
70
+
71
+ Use chronological entries with the newest entry appended at the bottom:
72
+
73
+ ```markdown
74
+ ## YYYY-MM-DD HH:MM:SS
75
+
76
+ **Operation:** What happened.
77
+ **Reason:** Why this approach was selected.
78
+ **Artifacts:** Files, repositories, or outputs changed.
79
+ **Verification:** Commands/checks and real results.
80
+ **Blockers:** Unresolved problems, if any.
81
+ **Next step:** Exact continuation point for another session.
82
+ ```
83
+
84
+ Raw command output belongs in `output/logs/` or another log directory, not in CHANGELOG.md.
85
+
86
+ ## Flat layout
87
+
88
+ ```text
89
+ <entity>/
90
+ ├── MEMORY.md
91
+ └── CHANGELOG.md
92
+ ```
93
+
94
+ Use for one project, one task, or one cohesive entity.
95
+
96
+ ## Hierarchical layout
97
+
98
+ Use when multiple sessions modify distinct subsystems under one long-running task or project:
99
+
100
+ ```text
101
+ <entity>/
102
+ ├── MEMORY.md # root index and cross-subsystem facts
103
+ ├── CHANGELOG.md # cross-subsystem chronological summaries
104
+ └── memories/
105
+ └── <sub-system>/
106
+ ├── MEMORY.md # subsystem-owned stable facts
107
+ └── CHANGELOG.md # subsystem operations and verification
108
+ ```
109
+
110
+ Subsystem names are lowercase kebab-case. Every subsystem directory must contain both files.
111
+
112
+ ### Root versus subsystem ownership
113
+
114
+ - Root `MEMORY.md`: entity identity, subsystem index, cross-subsystem invariants, shared interfaces.
115
+ - Root `CHANGELOG.md`: concise cross-subsystem summary with references to affected subsystem logs.
116
+ - Subsystem `MEMORY.md`: facts owned only by that subsystem.
117
+ - Subsystem `CHANGELOG.md`: detailed work history for that subsystem.
118
+
119
+ Root files are indexes and syntheses, not copies of subsystem files.
120
+
121
+ ## Read protocol
122
+
123
+ Before changing a hierarchical entity:
124
+
125
+ 1. Read root `MEMORY.md` completely.
126
+ 2. Read recent relevant root `CHANGELOG.md` entries.
127
+ 3. Identify the target subsystem.
128
+ 4. Read its `MEMORY.md` completely.
129
+ 5. Read recent relevant entries from its `CHANGELOG.md`.
130
+
131
+ ## Write protocol
132
+
133
+ After a verified change:
134
+
135
+ 1. Update subsystem `MEMORY.md` only if stable facts changed.
136
+ 2. Append subsystem `CHANGELOG.md` with operation, reason, artifacts, verification, blockers, and next step.
137
+ 3. Update root `MEMORY.md` only if the subsystem index or cross-subsystem facts changed.
138
+ 4. Append a concise root `CHANGELOG.md` summary naming affected subsystem logs.
139
+
140
+ ## Tooling
141
+
142
+ Create or extend a hierarchical context:
143
+
144
+ ```bash
145
+ python3 scripts/manage_directory_context.py init <entity-dir> <sub-system> [<sub-system> ...]
146
+ ```
147
+
148
+ Verify required files and naming:
149
+
150
+ ```bash
151
+ python3 scripts/manage_directory_context.py verify <entity-dir>
152
+ ```
153
+
154
+ The script never overwrites existing context files.
155
+
156
+ ## Relationship to task-framework
157
+
158
+ `task-framework` owns task creation, status, checklist, indexes, and lifecycle. For task context it must:
159
+
160
+ 1. Create root `MEMORY.md` and `CHANGELOG.md`.
161
+ 2. Load this skill when hierarchical directory context is requested or detected.
162
+ 3. Delegate nested creation, format rules, and validation to this skill.
163
+ 4. Preserve `MEMORY.md`, `CHANGELOG.md`, and `memories/` during reset and cleanup.
164
+
165
+ ## Relationship to changelog skill
166
+
167
+ The continuous `CHANGELOG.md` in this skill preserves cross-session context. The separate `changelog` skill creates immutable `changelog/<timestamp>.<topic>.md` delivery records. They are complementary and must not replace each other.
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env python3
2
+ """Create and verify flat or hierarchical directory context."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import re
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ SUBSYSTEM_RE = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
12
+
13
+ ROOT_MEMORY = """Entity context is managed by compact-directory-memory.
14
+
15
+ §
16
+
17
+ Subsystem context index is stored under `memories/`.
18
+ """
19
+
20
+ ROOT_CHANGELOG = """# CHANGELOG.md
21
+
22
+ Append chronological cross-session context entries.
23
+ """
24
+
25
+ SUBSYSTEM_MEMORY = """Subsystem: `{subsystem}`.
26
+
27
+ §
28
+
29
+ Repository/path: <fill when known>.
30
+
31
+ §
32
+
33
+ Responsibilities and boundaries: <fill when known>.
34
+ """
35
+
36
+ SUBSYSTEM_CHANGELOG = """# {subsystem} — CHANGELOG.md
37
+
38
+ Append chronological subsystem operations, decisions, verification, blockers, and next steps.
39
+ """
40
+
41
+
42
+ def ensure_file(path: Path, content: str) -> bool:
43
+ if path.exists():
44
+ return False
45
+ path.write_text(content, encoding="utf-8")
46
+ return True
47
+
48
+
49
+ def validate_subsystem(name: str) -> None:
50
+ if not SUBSYSTEM_RE.fullmatch(name):
51
+ raise ValueError(f"invalid subsystem name: {name!r}; use lowercase kebab-case")
52
+
53
+
54
+ def init(entity_dir: Path, subsystems: list[str]) -> int:
55
+ if not entity_dir.is_dir():
56
+ print(f"ERROR: entity directory not found: {entity_dir}", file=sys.stderr)
57
+ return 2
58
+ created: list[Path] = []
59
+ if ensure_file(entity_dir / "MEMORY.md", ROOT_MEMORY):
60
+ created.append(entity_dir / "MEMORY.md")
61
+ if ensure_file(entity_dir / "CHANGELOG.md", ROOT_CHANGELOG):
62
+ created.append(entity_dir / "CHANGELOG.md")
63
+ memories = entity_dir / "memories"
64
+ memories.mkdir(exist_ok=True)
65
+ for subsystem in subsystems:
66
+ validate_subsystem(subsystem)
67
+ directory = memories / subsystem
68
+ directory.mkdir(exist_ok=True)
69
+ memory_file = directory / "MEMORY.md"
70
+ changelog_file = directory / "CHANGELOG.md"
71
+ if ensure_file(memory_file, SUBSYSTEM_MEMORY.format(subsystem=subsystem)):
72
+ created.append(memory_file)
73
+ if ensure_file(changelog_file, SUBSYSTEM_CHANGELOG.format(subsystem=subsystem)):
74
+ created.append(changelog_file)
75
+ for path in created:
76
+ print(f"created {path.relative_to(entity_dir)}")
77
+ print(f"initialized directory context: subsystems={len(subsystems)}")
78
+ return verify(entity_dir)
79
+
80
+
81
+ def verify(entity_dir: Path) -> int:
82
+ errors: list[str] = []
83
+ for required in ("MEMORY.md", "CHANGELOG.md"):
84
+ if not (entity_dir / required).is_file():
85
+ errors.append(f"missing root file: {required}")
86
+ memories = entity_dir / "memories"
87
+ if not memories.is_dir():
88
+ errors.append("missing directory: memories/")
89
+ else:
90
+ for directory in sorted(path for path in memories.iterdir() if path.is_dir()):
91
+ try:
92
+ validate_subsystem(directory.name)
93
+ except ValueError as exc:
94
+ errors.append(str(exc))
95
+ for required in ("MEMORY.md", "CHANGELOG.md"):
96
+ if not (directory / required).is_file():
97
+ errors.append(f"missing subsystem file: memories/{directory.name}/{required}")
98
+ if errors:
99
+ for error in errors:
100
+ print(f"ERROR: {error}", file=sys.stderr)
101
+ return 1
102
+ subsystem_count = sum(1 for path in memories.iterdir() if path.is_dir())
103
+ print(f"verified directory context: root files OK, subsystems={subsystem_count}")
104
+ return 0
105
+
106
+
107
+ def main() -> int:
108
+ parser = argparse.ArgumentParser(description=__doc__)
109
+ commands = parser.add_subparsers(dest="command", required=True)
110
+ init_parser = commands.add_parser("init")
111
+ init_parser.add_argument("entity_dir", type=Path)
112
+ init_parser.add_argument("subsystems", nargs="*")
113
+ verify_parser = commands.add_parser("verify")
114
+ verify_parser.add_argument("entity_dir", type=Path)
115
+ args = parser.parse_args()
116
+ entity_dir = args.entity_dir.expanduser().resolve()
117
+ try:
118
+ if args.command == "init":
119
+ return init(entity_dir, args.subsystems)
120
+ return verify(entity_dir)
121
+ except ValueError as exc:
122
+ print(f"ERROR: {exc}", file=sys.stderr)
123
+ return 2
124
+
125
+
126
+ if __name__ == "__main__":
127
+ raise SystemExit(main())
@@ -0,0 +1,41 @@
1
+ ---
2
+ author: Hermes Agent
3
+ category: software-development
4
+ description: Reconstruct missing session context from canonical task artifacts and repository history.
5
+ license: MIT
6
+ metadata:
7
+ hermes:
8
+ scenes: [hermes, research]
9
+ tags: [task-framework, archaeology, session-recovery, task-recovery, forensics]
10
+ relations:
11
+ - type: depends_on
12
+ target: task-aware-project-work
13
+ properties: {reason: canonical task context must be read in order, strength: strong}
14
+ - type: complemented_by
15
+ target: task-artifact-integrity
16
+ properties: {reason: validates recovered artifact closure, strength: strong}
17
+ name: task-archaeology
18
+ platforms: [linux, macos]
19
+ version: 2.0.0
20
+ ---
21
+
22
+ # Task Archaeology
23
+
24
+ Use when session history is missing or incomplete but the user provides a task name, hash, or directory.
25
+
26
+ ## Recovery order
27
+
28
+ 1. Resolve the task with `task_api.py describe <identifier>`; do not pass task directory names as session IDs.
29
+ 2. Read `TASK.md`, root `MEMORY.md`, and recent root `CHANGELOG.md`.
30
+ 3. When hierarchical, read each relevant subsystem MEMORY and recent CHANGELOG.
31
+ 4. Read `README.md` and `.hermes-task.json` for creation time, outputs, and relationships.
32
+ 5. Resolve dependencies, related tasks, superseded tasks, and named outputs.
33
+ 6. Inventory `input/`, `output/docs/`, `output/logs/`, and scripts.
34
+ 7. Cross-reference repository branches and commits by timestamps and artifact paths.
35
+ 8. State what is directly evidenced, inferred, missing, and still blocked.
36
+
37
+ Task artifacts are evidence of task state, not a verbatim transcript. Never invent user statements from file outcomes.
38
+
39
+ ## Result
40
+
41
+ Return the reconstructed goal, decisions, produced artifacts, verification, unresolved issues, and exact continuation point, with file paths for every claim.
@@ -0,0 +1,72 @@
1
+ ---
2
+ author: Hermes Agent
3
+ category: software-development
4
+ description: Validate task context closure, artifacts, references, and safe relocation before continuation or deletion.
5
+ license: MIT
6
+ metadata:
7
+ hermes:
8
+ scenes: [hermes, coding, research]
9
+ tags: [task-framework, artifact-integrity, relocation, audit, task-recovery]
10
+ relations:
11
+ - type: depends_on
12
+ target: task-framework
13
+ properties: {reason: task-framework defines canonical task files and references, strength: strong}
14
+ - type: complemented_by
15
+ target: compact-directory-memory
16
+ properties: {reason: hierarchical context files are part of task closure, strength: strong}
17
+ name: task-artifact-integrity
18
+ platforms: [linux, macos]
19
+ version: 2.0.0
20
+ ---
21
+
22
+ # Task Artifact Integrity
23
+
24
+ Use when relocating a task root, consolidating related tasks, diagnosing an apparently empty task, or validating that another session can continue safely.
25
+
26
+ ## Context closure
27
+
28
+ A complete task closure includes:
29
+
30
+ - `TASK.md`, `README.md`, `MEMORY.md`, `CHANGELOG.md`, `.hermes-task.json`;
31
+ - `memories/<sub-system>/MEMORY.md` and `CHANGELOG.md` pairs when hierarchical;
32
+ - `input/`, `output/`, and `scripts/` inventories;
33
+ - named outputs, dependencies, related/superseded tasks, ticket/project extension fields;
34
+ - absolute paths and cross-task references.
35
+
36
+ ## Inspection
37
+
38
+ 1. Resolve the task through `task_api.py describe`.
39
+ 2. Read root and target subsystem context.
40
+ 3. Inventory source inputs separately from generated output.
41
+ 4. Resolve every related task and named output.
42
+ 5. Report missing, empty, stale, or external references before mutation.
43
+
44
+ ## Safe relocation
45
+
46
+ 1. Confirm exact source and destination roots.
47
+ 2. Refuse overwrite when destination exists.
48
+ 3. Copy metadata-preserving content without `--delete`.
49
+ 4. Compare relative path, type, size, and SHA-256 manifests.
50
+ 5. Rewrite absolute references only after copy verification.
51
+ 6. Append relocation entries to affected CHANGELOG files.
52
+ 7. Regenerate both roots' indexes.
53
+ 8. Remove source only after equality and reference verification.
54
+
55
+ Same-machine relocation needs no archive unless requested. Cross-machine transfer or explicit rollback may retain an archive.
56
+
57
+ ## Completion evidence
58
+
59
+ Report task hashes, roots, input/output inventories, manifest equality, context-pair verification, rewritten references, index regeneration, and source/archive status.
60
+
61
+ See `references/task-root-relocation.md` for the checklist.
62
+
63
+ ## Permanent tooling
64
+
65
+ ```bash
66
+ python3 scripts/task_integrity.py audit <hash-or-dir>
67
+ python3 scripts/task_integrity.py closure <hash-or-dir>
68
+ python3 scripts/task_integrity.py manifest <hash-or-dir> --output <manifest.json>
69
+ python3 scripts/task_integrity.py compare <source-dir> <destination-dir>
70
+ ```
71
+
72
+ All commands emit JSON and return nonzero when integrity or equality fails.
@@ -0,0 +1,31 @@
1
+ # Task root relocation checklist
2
+
3
+ ## Invariant
4
+
5
+ After relocation, canonical files, root and subsystem context, source inputs, generated evidence, named outputs, and related-task references remain resolvable without an undeclared old root.
6
+
7
+ ## Required checks
8
+
9
+ | Check | Evidence | Failure response |
10
+ |---|---|---|
11
+ | Canonical files | TASK, README, MEMORY, CHANGELOG, metadata are nonempty | Restore/report before source deletion |
12
+ | Hierarchical context | Every subsystem directory has both context files | Repair complete pair before relocation |
13
+ | Source input | `input/` inventory | Locate source owners; never infer emptiness is acceptable |
14
+ | Generated evidence | `output/` and review/log inventory | Preserve evidence or owning task |
15
+ | Related closure | metadata and document references resolve | Move closure or rewrite verified references |
16
+ | Named outputs | every registered output resolves | Repair metadata/path before completion |
17
+ | Copy equality | relative path/type/size/SHA-256 manifests match | Retain source and fail relocation |
18
+ | Indexes | destination and source indexes regenerated | Do not report completion |
19
+
20
+ ## Record
21
+
22
+ ```markdown
23
+ ## YYYY-MM-DD HH:MM:SS TZ
24
+
25
+ **Operation:** Relocated task `<hash>` from `<old-root>` to `<new-root>`.
26
+ **Context closure:** `<related hashes and subsystems>`.
27
+ **Verification:** `<file count and manifest equality>`.
28
+ **References:** `<updated paths or none>`.
29
+ **Indexes:** `<old/new regeneration result>`.
30
+ **Source status:** `<removed after verification / retained>`.
31
+ ```
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env python3
2
+ """Audit task closure and compare deterministic task manifests."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import hashlib
8
+ import json
9
+ import os
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ TASK_SCRIPTS = Path(__file__).resolve().parents[2] / "task-framework" / "scripts"
14
+ sys.path.insert(0, str(TASK_SCRIPTS))
15
+ import task_api # pyright: ignore[reportMissingImports] # noqa: E402
16
+
17
+ CANONICAL = ("TASK.md", "README.md", "MEMORY.md", "CHANGELOG.md", ".hermes-task.json")
18
+ RELATION_KEYS = ("dependencies", "related", "supersedes", "requires", "required_by")
19
+
20
+
21
+ def file_hash(path: Path) -> str:
22
+ digest = hashlib.sha256()
23
+ with path.open("rb") as handle:
24
+ for chunk in iter(lambda: handle.read(1024 * 1024), b""):
25
+ digest.update(chunk)
26
+ return digest.hexdigest()
27
+
28
+
29
+ def build_manifest(root: Path) -> list[dict]:
30
+ entries: list[dict] = []
31
+ for path in sorted(root.rglob("*")):
32
+ relative = path.relative_to(root).as_posix()
33
+ if relative == ".git" or relative.startswith(".git/"):
34
+ continue
35
+ if path.is_symlink():
36
+ entries.append({"path": relative, "type": "symlink", "target": os.readlink(path)})
37
+ elif path.is_dir():
38
+ entries.append({"path": relative, "type": "directory"})
39
+ elif path.is_file():
40
+ entries.append(
41
+ {"path": relative, "type": "file", "size": path.stat().st_size, "sha256": file_hash(path)}
42
+ )
43
+ return entries
44
+
45
+
46
+ def relation_hashes(metadata: dict) -> list[str]:
47
+ values: list[str] = []
48
+ for key in RELATION_KEYS:
49
+ raw = metadata.get(key, [])
50
+ if isinstance(raw, list):
51
+ values.extend(str(item) for item in raw if item)
52
+ return sorted(set(values))
53
+
54
+
55
+ def audit(identifier: str) -> dict:
56
+ description = task_api.command_describe(identifier)
57
+ root = Path(description["path"])
58
+ metadata = description["metadata"]
59
+ errors: list[str] = []
60
+ warnings: list[str] = []
61
+ for name in CANONICAL:
62
+ path = root / name
63
+ if not path.is_file():
64
+ errors.append(f"missing canonical file: {name}")
65
+ elif path.stat().st_size == 0:
66
+ errors.append(f"empty canonical file: {name}")
67
+ memories = root / "memories"
68
+ hierarchical = metadata.get("memory_layout") == "hierarchical" or memories.is_dir()
69
+ subsystems: list[str] = []
70
+ if hierarchical:
71
+ if not memories.is_dir():
72
+ errors.append("hierarchical metadata set but memories/ is missing")
73
+ else:
74
+ for directory in sorted(path for path in memories.iterdir() if path.is_dir()):
75
+ subsystems.append(directory.name)
76
+ for name in ("MEMORY.md", "CHANGELOG.md"):
77
+ if not (directory / name).is_file():
78
+ errors.append(f"incomplete subsystem context: memories/{directory.name}/{name}")
79
+ outputs = metadata.get("outputs", {})
80
+ if isinstance(outputs, dict):
81
+ for name, raw_path in outputs.items():
82
+ candidate = root / str(raw_path)
83
+ if not candidate.exists():
84
+ errors.append(f"named output does not resolve: {name} -> {raw_path}")
85
+ unresolved: list[str] = []
86
+ for task_hash in relation_hashes(metadata):
87
+ try:
88
+ task_api.command_describe(task_hash)
89
+ except FileNotFoundError:
90
+ unresolved.append(task_hash)
91
+ if unresolved:
92
+ errors.append(f"unresolved related task hashes: {', '.join(unresolved)}")
93
+ for dirname in ("input", "output", "scripts"):
94
+ if not (root / dirname).is_dir():
95
+ warnings.append(f"missing standard directory: {dirname}/")
96
+ return {
97
+ "task": description,
98
+ "ok": not errors,
99
+ "errors": errors,
100
+ "warnings": warnings,
101
+ "subsystems": subsystems,
102
+ "relations": relation_hashes(metadata),
103
+ "manifest_entries": len(build_manifest(root)),
104
+ }
105
+
106
+
107
+ def closure(identifier: str) -> dict:
108
+ root = task_api.command_describe(identifier)
109
+ queue = [root["hash"]]
110
+ seen: dict[str, dict] = {}
111
+ unresolved: list[str] = []
112
+ while queue:
113
+ current = queue.pop(0)
114
+ if current in seen:
115
+ continue
116
+ try:
117
+ item = task_api.command_describe(current)
118
+ except FileNotFoundError:
119
+ unresolved.append(current)
120
+ continue
121
+ seen[current] = item
122
+ queue.extend(task_hash for task_hash in relation_hashes(item["metadata"]) if task_hash not in seen)
123
+ return {"root": root["hash"], "tasks": list(seen.values()), "unresolved": sorted(set(unresolved))}
124
+
125
+
126
+ def compare(source: Path, destination: Path) -> dict:
127
+ source_manifest = build_manifest(source.resolve())
128
+ destination_manifest = build_manifest(destination.resolve())
129
+ source_map = {entry["path"]: entry for entry in source_manifest}
130
+ destination_map = {entry["path"]: entry for entry in destination_manifest}
131
+ missing = sorted(set(source_map) - set(destination_map))
132
+ extra = sorted(set(destination_map) - set(source_map))
133
+ changed = sorted(
134
+ path for path in set(source_map) & set(destination_map) if source_map[path] != destination_map[path]
135
+ )
136
+ return {"equal": not missing and not extra and not changed, "missing": missing, "extra": extra, "changed": changed}
137
+
138
+
139
+ def main() -> int:
140
+ parser = argparse.ArgumentParser(description=__doc__)
141
+ commands = parser.add_subparsers(dest="command", required=True)
142
+ audit_parser = commands.add_parser("audit")
143
+ audit_parser.add_argument("identifier")
144
+ closure_parser = commands.add_parser("closure")
145
+ closure_parser.add_argument("identifier")
146
+ manifest_parser = commands.add_parser("manifest")
147
+ manifest_parser.add_argument("identifier")
148
+ manifest_parser.add_argument("--output", type=Path)
149
+ compare_parser = commands.add_parser("compare")
150
+ compare_parser.add_argument("source", type=Path)
151
+ compare_parser.add_argument("destination", type=Path)
152
+ args = parser.parse_args()
153
+ try:
154
+ if args.command == "audit":
155
+ result = audit(args.identifier)
156
+ code = 0 if result["ok"] else 1
157
+ elif args.command == "closure":
158
+ result = closure(args.identifier)
159
+ code = 0 if not result["unresolved"] else 1
160
+ elif args.command == "manifest":
161
+ root = Path(task_api.command_describe(args.identifier)["path"])
162
+ result = build_manifest(root)
163
+ if args.output:
164
+ args.output.write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
165
+ code = 0
166
+ else:
167
+ result = compare(args.source, args.destination)
168
+ code = 0 if result["equal"] else 1
169
+ print(json.dumps(result, ensure_ascii=False, indent=2))
170
+ return code
171
+ except (FileNotFoundError, json.JSONDecodeError, OSError) as exc:
172
+ print(json.dumps({"error": str(exc)}, ensure_ascii=False), file=sys.stderr)
173
+ return 2
174
+
175
+
176
+ if __name__ == "__main__":
177
+ raise SystemExit(main())
@@ -0,0 +1,42 @@
1
+ ---
2
+ author: Hermes Agent
3
+ category: software-development
4
+ description: Load canonical root and subsystem task context before continuing project work.
5
+ license: MIT
6
+ metadata:
7
+ hermes:
8
+ scenes: [hermes, coding]
9
+ tags: [task-framework, task-context, discovery, continuation, project-management]
10
+ relations:
11
+ - type: depends_on
12
+ target: task-context-storage
13
+ properties: {reason: defines context ownership, strength: strong}
14
+ - type: depends_on
15
+ target: compact-directory-memory
16
+ properties: {reason: defines hierarchical read protocol, strength: strong}
17
+ name: task-aware-project-work
18
+ platforms: [linux, macos]
19
+ version: 2.0.0
20
+ ---
21
+
22
+ # Task-Aware Project Work
23
+
24
+ Use when continuing a task by name/hash, returning to project work tied to a task, or before creating project artifacts that may already exist.
25
+
26
+ ## Protocol
27
+
28
+ 1. Resolve the task with `task_api.py describe <identifier>`.
29
+ 2. Read `TASK.md`, root `MEMORY.md`, and recent root `CHANGELOG.md`.
30
+ 3. Detect `.hermes-task.json.memory_layout` or `memories/`.
31
+ 4. Identify the target subsystem and read its full MEMORY plus recent CHANGELOG.
32
+ 5. Resolve project/repository paths from task context and verify existing artifacts before creating anything.
33
+ 6. If a hierarchical subsystem is missing, load `compact-directory-memory` and create the complete pair before source changes.
34
+
35
+ Legacy `TASK_MEMORY.md` is not canonical. Use it only as archaeological evidence when canonical files are absent.
36
+
37
+ ## Pitfalls
38
+
39
+ - A ticket is not a task-framework task.
40
+ - Never start implementation before loading task context.
41
+ - Search actual repositories before concluding an artifact was deleted.
42
+ - Do not duplicate a project or subsystem because another session used a different path.