claudecode-omc 5.6.8 → 5.11.0

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 (216) hide show
  1. package/.local/settings/settings.json +8 -0
  2. package/.local/skills/prompt-optimizer/SKILL.md +262 -19
  3. package/.omc-curation/ecc-selection.json +80 -0
  4. package/.omc-curation/governance.json +116 -0
  5. package/.omc-curation/sources.lock.json +30 -0
  6. package/README.md +78 -4
  7. package/bundled/manifest.json +6 -5
  8. package/bundled/upstream/anthropic-skills/.omc-source/bundle.json +18 -0
  9. package/bundled/upstream/anthropic-skills/.omc-source/provenance.json +399 -0
  10. package/bundled/upstream/anthropic-skills/skills/claude-api/SKILL.md +18 -17
  11. package/bundled/upstream/anthropic-skills/skills/claude-api/curl/examples.md +9 -9
  12. package/bundled/upstream/anthropic-skills/skills/claude-api/curl/managed-agents.md +4 -4
  13. package/bundled/upstream/anthropic-skills/skills/claude-api/go/managed-agents/README.md +2 -2
  14. package/bundled/upstream/anthropic-skills/skills/claude-api/java/claude-api.md +2 -2
  15. package/bundled/upstream/anthropic-skills/skills/claude-api/java/managed-agents/README.md +2 -2
  16. package/bundled/upstream/anthropic-skills/skills/claude-api/php/claude-api.md +10 -10
  17. package/bundled/upstream/anthropic-skills/skills/claude-api/php/managed-agents/README.md +2 -2
  18. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/README.md +16 -16
  19. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/batches.md +3 -3
  20. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/files-api.md +3 -3
  21. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/streaming.md +7 -7
  22. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/tool-use.md +19 -19
  23. package/bundled/upstream/anthropic-skills/skills/claude-api/python/managed-agents/README.md +3 -3
  24. package/bundled/upstream/anthropic-skills/skills/claude-api/ruby/claude-api.md +4 -4
  25. package/bundled/upstream/anthropic-skills/skills/claude-api/ruby/managed-agents/README.md +2 -2
  26. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/error-codes.md +5 -5
  27. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/live-sources.md +3 -1
  28. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-api-reference.md +10 -4
  29. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-core.md +19 -1
  30. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-environments.md +6 -2
  31. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-multiagent.md +1 -1
  32. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-onboarding.md +3 -3
  33. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-overview.md +3 -2
  34. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +173 -0
  35. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-tools.md +10 -4
  36. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/model-migration.md +113 -13
  37. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/models.md +14 -11
  38. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/prompt-caching.md +2 -2
  39. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/tool-use-concepts.md +4 -4
  40. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/README.md +15 -15
  41. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/batches.md +2 -2
  42. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/files-api.md +1 -1
  43. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/streaming.md +5 -5
  44. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/tool-use.md +15 -15
  45. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/managed-agents/README.md +3 -3
  46. package/bundled/upstream/ecc/.omc-source/bundle.json +2 -1
  47. package/bundled/upstream/ecc/.omc-source/last-plan-apply.json +108 -24
  48. package/bundled/upstream/ecc/.omc-source/manifests/.claude-plugin/marketplace.json +3 -3
  49. package/bundled/upstream/ecc/.omc-source/provenance.json +563 -0
  50. package/bundled/upstream/ecc/agents/marketing-agent.md +159 -0
  51. package/bundled/upstream/ecc/agents/react-build-resolver.md +215 -0
  52. package/bundled/upstream/ecc/agents/react-reviewer.md +167 -0
  53. package/bundled/upstream/ecc/agents/typescript-reviewer.md +3 -0
  54. package/bundled/upstream/ecc/commands/harness-audit.md +17 -10
  55. package/bundled/upstream/ecc/commands/marketing-campaign.md +129 -0
  56. package/bundled/upstream/ecc/commands/react-build.md +187 -0
  57. package/bundled/upstream/ecc/commands/react-review.md +170 -0
  58. package/bundled/upstream/ecc/commands/react-test.md +265 -0
  59. package/bundled/upstream/ecc/skills/benchmark-optimization-loop/SKILL.md +69 -0
  60. package/bundled/upstream/ecc/skills/blender-motion-state-inspection/SKILL.md +164 -0
  61. package/bundled/upstream/ecc/skills/canary-watch/SKILL.md +9 -1
  62. package/bundled/upstream/ecc/skills/continuous-learning-v2/hooks/observe.sh +31 -9
  63. package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/detect-project.sh +38 -4
  64. package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/instinct-cli.py +319 -12
  65. package/bundled/upstream/ecc/skills/data-throughput-accelerator/SKILL.md +72 -0
  66. package/bundled/upstream/ecc/skills/dynamic-workflow-mode/SKILL.md +123 -0
  67. package/bundled/upstream/ecc/skills/frontend-a11y/SKILL.md +446 -0
  68. package/bundled/upstream/ecc/skills/ito-basket-compare/SKILL.md +63 -0
  69. package/bundled/upstream/ecc/skills/ito-data-atlas-agent/SKILL.md +63 -0
  70. package/bundled/upstream/ecc/skills/ito-market-intelligence/SKILL.md +60 -0
  71. package/bundled/upstream/ecc/skills/ito-trade-planner/SKILL.md +67 -0
  72. package/bundled/upstream/ecc/skills/latency-critical-systems/SKILL.md +73 -0
  73. package/bundled/upstream/ecc/skills/marketing-campaign/SKILL.md +113 -0
  74. package/bundled/upstream/ecc/skills/nextjs-turbopack/SKILL.md +13 -0
  75. package/bundled/upstream/ecc/skills/parallel-execution-optimizer/SKILL.md +72 -0
  76. package/bundled/upstream/ecc/skills/prediction-market-oracle-research/SKILL.md +63 -0
  77. package/bundled/upstream/ecc/skills/prediction-market-risk-review/SKILL.md +60 -0
  78. package/bundled/upstream/ecc/skills/react-patterns/SKILL.md +341 -0
  79. package/bundled/upstream/ecc/skills/react-performance/SKILL.md +574 -0
  80. package/bundled/upstream/ecc/skills/react-testing/SKILL.md +423 -0
  81. package/bundled/upstream/ecc/skills/recsys-pipeline-architect/SKILL.md +114 -0
  82. package/bundled/upstream/ecc/skills/recursive-decision-ledger/SKILL.md +79 -0
  83. package/bundled/upstream/ecc/skills/social-publisher/SKILL.md +115 -0
  84. package/bundled/upstream/ecc/skills/team-agent-orchestration/SKILL.md +110 -0
  85. package/bundled/upstream/ecc/skills/uncloud/SKILL.md +343 -0
  86. package/bundled/upstream/ecc/skills/windows-desktop-e2e/SKILL.md +99 -0
  87. package/bundled/upstream/impeccable/.omc-source/bundle.json +20 -0
  88. package/bundled/upstream/impeccable/.omc-source/provenance.json +105 -0
  89. package/bundled/upstream/impeccable/agents/impeccable-manual-edit-applier.md +97 -0
  90. package/bundled/upstream/impeccable/skills/impeccable/SKILL.md +168 -0
  91. package/bundled/upstream/impeccable/skills/impeccable/reference/adapt.md +311 -0
  92. package/bundled/upstream/impeccable/skills/impeccable/reference/animate.md +201 -0
  93. package/bundled/upstream/impeccable/skills/impeccable/reference/audit.md +133 -0
  94. package/bundled/upstream/impeccable/skills/impeccable/reference/bolder.md +113 -0
  95. package/bundled/upstream/impeccable/skills/impeccable/reference/brand.md +108 -0
  96. package/bundled/upstream/impeccable/skills/impeccable/reference/clarify.md +288 -0
  97. package/bundled/upstream/impeccable/skills/impeccable/reference/codex.md +105 -0
  98. package/bundled/upstream/impeccable/skills/impeccable/reference/colorize.md +257 -0
  99. package/bundled/upstream/impeccable/skills/impeccable/reference/craft.md +123 -0
  100. package/bundled/upstream/impeccable/skills/impeccable/reference/critique.md +767 -0
  101. package/bundled/upstream/impeccable/skills/impeccable/reference/delight.md +302 -0
  102. package/bundled/upstream/impeccable/skills/impeccable/reference/distill.md +111 -0
  103. package/bundled/upstream/impeccable/skills/impeccable/reference/document.md +429 -0
  104. package/bundled/upstream/impeccable/skills/impeccable/reference/extract.md +69 -0
  105. package/bundled/upstream/impeccable/skills/impeccable/reference/harden.md +347 -0
  106. package/bundled/upstream/impeccable/skills/impeccable/reference/hooks.md +88 -0
  107. package/bundled/upstream/impeccable/skills/impeccable/reference/init.md +172 -0
  108. package/bundled/upstream/impeccable/skills/impeccable/reference/interaction-design.md +189 -0
  109. package/bundled/upstream/impeccable/skills/impeccable/reference/layout.md +161 -0
  110. package/bundled/upstream/impeccable/skills/impeccable/reference/live.md +718 -0
  111. package/bundled/upstream/impeccable/skills/impeccable/reference/onboard.md +234 -0
  112. package/bundled/upstream/impeccable/skills/impeccable/reference/optimize.md +258 -0
  113. package/bundled/upstream/impeccable/skills/impeccable/reference/overdrive.md +130 -0
  114. package/bundled/upstream/impeccable/skills/impeccable/reference/polish.md +241 -0
  115. package/bundled/upstream/impeccable/skills/impeccable/reference/product.md +60 -0
  116. package/bundled/upstream/impeccable/skills/impeccable/reference/quieter.md +99 -0
  117. package/bundled/upstream/impeccable/skills/impeccable/reference/shape.md +165 -0
  118. package/bundled/upstream/impeccable/skills/impeccable/reference/typeset.md +279 -0
  119. package/bundled/upstream/impeccable/skills/impeccable/scripts/command-metadata.json +94 -0
  120. package/bundled/upstream/impeccable/skills/impeccable/scripts/context-signals.mjs +225 -0
  121. package/bundled/upstream/impeccable/skills/impeccable/scripts/context.mjs +280 -0
  122. package/bundled/upstream/impeccable/skills/impeccable/scripts/critique-storage.mjs +242 -0
  123. package/bundled/upstream/impeccable/skills/impeccable/scripts/detect-csp.mjs +198 -0
  124. package/bundled/upstream/impeccable/skills/impeccable/scripts/detect.mjs +21 -0
  125. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/browser/injected/index.mjs +1735 -0
  126. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/cli/main.mjs +244 -0
  127. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +4907 -0
  128. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/detect-antipatterns.mjs +43 -0
  129. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/engines/browser/detect-url.mjs +252 -0
  130. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +552 -0
  131. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +1013 -0
  132. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +208 -0
  133. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/engines/visual/screenshot-contrast.mjs +189 -0
  134. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/findings.mjs +12 -0
  135. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/node/file-system.mjs +198 -0
  136. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/profile/profiler.mjs +166 -0
  137. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/registry/antipatterns.mjs +419 -0
  138. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/rules/checks.mjs +2671 -0
  139. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/shared/color.mjs +124 -0
  140. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/shared/constants.mjs +101 -0
  141. package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/shared/page.mjs +7 -0
  142. package/bundled/upstream/impeccable/skills/impeccable/scripts/hook-admin.mjs +574 -0
  143. package/bundled/upstream/impeccable/skills/impeccable/scripts/hook-before-edit.mjs +473 -0
  144. package/bundled/upstream/impeccable/skills/impeccable/scripts/hook-lib.mjs +1286 -0
  145. package/bundled/upstream/impeccable/skills/impeccable/scripts/hook.mjs +61 -0
  146. package/bundled/upstream/impeccable/skills/impeccable/scripts/lib/design-parser.mjs +835 -0
  147. package/bundled/upstream/impeccable/skills/impeccable/scripts/lib/impeccable-paths.mjs +126 -0
  148. package/bundled/upstream/impeccable/skills/impeccable/scripts/lib/is-generated.mjs +69 -0
  149. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/browser-script-parts.mjs +49 -0
  150. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/completion.mjs +19 -0
  151. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/event-validation.mjs +137 -0
  152. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/insert-ui.mjs +458 -0
  153. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/manual-apply.mjs +939 -0
  154. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/manual-edit-routes.mjs +357 -0
  155. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/manual-edits-buffer.mjs +152 -0
  156. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/session-store.mjs +289 -0
  157. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/svelte-component.mjs +826 -0
  158. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/sveltekit-adapter.mjs +274 -0
  159. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/ui-core.mjs +180 -0
  160. package/bundled/upstream/impeccable/skills/impeccable/scripts/live/vocabulary.mjs +36 -0
  161. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-accept.mjs +812 -0
  162. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-browser-dom.js +146 -0
  163. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-browser-session.js +123 -0
  164. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-browser.js +11086 -0
  165. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-commit-manual-edits.mjs +1241 -0
  166. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-complete.mjs +75 -0
  167. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-copy-edit-agent.mjs +683 -0
  168. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-discard-manual-edits.mjs +51 -0
  169. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-inject.mjs +583 -0
  170. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-insert.mjs +272 -0
  171. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-manual-edit-evidence.mjs +363 -0
  172. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-poll.mjs +379 -0
  173. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-resume.mjs +94 -0
  174. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-server.mjs +1134 -0
  175. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-status.mjs +61 -0
  176. package/bundled/upstream/impeccable/skills/impeccable/scripts/live-wrap.mjs +894 -0
  177. package/bundled/upstream/impeccable/skills/impeccable/scripts/live.mjs +246 -0
  178. package/bundled/upstream/impeccable/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
  179. package/bundled/upstream/impeccable/skills/impeccable/scripts/palette.mjs +633 -0
  180. package/bundled/upstream/impeccable/skills/impeccable/scripts/pin.mjs +214 -0
  181. package/bundled/upstream/oh-my-claudecode/.omc-source/bundle.json +2 -1
  182. package/bundled/upstream/oh-my-claudecode/.omc-source/provenance.json +116 -0
  183. package/bundled/upstream/oh-my-claudecode/skills/autopilot/SKILL.md +7 -0
  184. package/bundled/upstream/oh-my-claudecode/skills/cancel/SKILL.md +1 -0
  185. package/bundled/upstream/oh-my-claudecode/skills/deep-interview/SKILL.md +39 -5
  186. package/bundled/upstream/oh-my-claudecode/skills/hud/SKILL.md +1 -0
  187. package/bundled/upstream/oh-my-claudecode/skills/local-build-reminder/SKILL.md +78 -0
  188. package/bundled/upstream/oh-my-claudecode/skills/omc-doctor/SKILL.md +1 -1
  189. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/SKILL.md +26 -10
  190. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/01-install-claude-md.md +3 -3
  191. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/02-configure.md +6 -4
  192. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/03-integrations.md +1 -1
  193. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/04-welcome.md +2 -2
  194. package/bundled/upstream/oh-my-claudecode/skills/omc-teams/SKILL.md +6 -6
  195. package/bundled/upstream/oh-my-claudecode/skills/plan/SKILL.md +44 -32
  196. package/bundled/upstream/oh-my-claudecode/skills/ralph/SKILL.md +45 -21
  197. package/bundled/upstream/oh-my-claudecode/skills/ralplan/SKILL.md +1 -1
  198. package/bundled/upstream/oh-my-claudecode/skills/self-improve/SKILL.md +7 -0
  199. package/bundled/upstream/oh-my-claudecode/skills/self-improve/scripts/resolve-paths.mjs +39 -15
  200. package/bundled/upstream/oh-my-claudecode/skills/team/SKILL.md +132 -90
  201. package/bundled/upstream/oh-my-claudecode/skills/ultragoal/SKILL.md +93 -0
  202. package/bundled/upstream/oh-my-claudecode/skills/ultraqa/SKILL.md +28 -13
  203. package/bundled/upstream/oh-my-claudecode/skills/ultrawork/SKILL.md +7 -0
  204. package/bundled/upstream/superpowers/.omc-source/bundle.json +2 -1
  205. package/bundled/upstream/superpowers/.omc-source/provenance.json +63 -0
  206. package/package.json +2 -1
  207. package/src/catalog/source-catalog.js +10 -4
  208. package/src/cli/index.js +4 -0
  209. package/src/cli/plan.js +14 -2
  210. package/src/cli/setup.js +52 -13
  211. package/src/cli/skill.js +1 -1
  212. package/src/cli/source.js +271 -14
  213. package/src/config/sources.js +82 -1
  214. package/src/merge/content-patch.js +88 -0
  215. package/templates/merge-config.json +1 -8
  216. package/bundled/upstream/ecc/skills/strategic-compact/suggest-compact.sh +0 -54
@@ -75,16 +75,42 @@ _clv2_normalize_remote_url() {
75
75
  fi
76
76
  }
77
77
 
78
+ _clv2_main_worktree_root() {
79
+ local root="$1"
80
+ [ -z "$root" ] && return 0
81
+ command -v git >/dev/null 2>&1 || return 0
82
+
83
+ git -C "$root" worktree list --porcelain 2>/dev/null | while IFS= read -r line; do
84
+ case "$line" in
85
+ worktree\ *)
86
+ printf '%s\n' "${line#worktree }"
87
+ break
88
+ ;;
89
+ esac
90
+ done
91
+ }
92
+
78
93
  _clv2_detect_project() {
79
94
  local project_root=""
80
95
  local project_name=""
81
96
  local project_id=""
82
97
  local source_hint=""
83
98
 
99
+ if [ "${CLV2_NO_PROJECT:-0}" = "1" ]; then
100
+ _CLV2_PROJECT_ID="global"
101
+ _CLV2_PROJECT_NAME="global"
102
+ _CLV2_PROJECT_ROOT=""
103
+ _CLV2_PROJECT_DIR="${_CLV2_HOMUNCULUS_DIR}"
104
+ mkdir -p "$_CLV2_PROJECT_DIR"
105
+ return 0
106
+ fi
107
+
84
108
  # 1. Try CLAUDE_PROJECT_DIR env var
85
- if [ -n "$CLAUDE_PROJECT_DIR" ] && [ -d "$CLAUDE_PROJECT_DIR" ]; then
86
- project_root="$CLAUDE_PROJECT_DIR"
87
- source_hint="env"
109
+ if [ -n "$CLAUDE_PROJECT_DIR" ] && [ -d "$CLAUDE_PROJECT_DIR" ] && command -v git &>/dev/null; then
110
+ project_root=$(git -C "$CLAUDE_PROJECT_DIR" rev-parse --show-toplevel 2>/dev/null || true)
111
+ if [ -n "$project_root" ]; then
112
+ source_hint="env"
113
+ fi
88
114
  fi
89
115
 
90
116
  # 2. Try git repo root from CWD (only if git is available)
@@ -101,6 +127,7 @@ _clv2_detect_project() {
101
127
  _CLV2_PROJECT_NAME="global"
102
128
  _CLV2_PROJECT_ROOT=""
103
129
  _CLV2_PROJECT_DIR="${_CLV2_HOMUNCULUS_DIR}"
130
+ mkdir -p "$_CLV2_PROJECT_DIR"
104
131
  return 0
105
132
  fi
106
133
 
@@ -133,7 +160,14 @@ _clv2_detect_project() {
133
160
  normalized_remote=$(_clv2_normalize_remote_url "$remote_url")
134
161
  fi
135
162
 
136
- local hash_input="${normalized_remote:-${remote_url:-$project_root}}"
163
+ local fallback_root="$project_root"
164
+ if [ -z "$remote_url" ]; then
165
+ local main_worktree_root
166
+ main_worktree_root=$(_clv2_main_worktree_root "$project_root")
167
+ [ -n "$main_worktree_root" ] && fallback_root="$main_worktree_root"
168
+ fi
169
+
170
+ local hash_input="${normalized_remote:-${remote_url:-$fallback_root}}"
137
171
  # Prefer Python for consistent SHA256 behavior across shells/platforms.
138
172
  # Pass the value via env var and encode as UTF-8 inside Python so the hash
139
173
  # is locale-independent (shells vary between UTF-8 / CP932 / CP1252, which
@@ -22,6 +22,7 @@ import os
22
22
  import subprocess
23
23
  import sys
24
24
  import re
25
+ import shutil
25
26
  import urllib.request
26
27
  from pathlib import Path
27
28
  from datetime import datetime, timedelta, timezone
@@ -194,26 +195,64 @@ def _yaml_quote(value: str) -> str:
194
195
  # Project Detection (Python equivalent of detect-project.sh)
195
196
  # ─────────────────────────────────────────────
196
197
 
198
+ def _git_repo_root(cwd: Optional[str] = None) -> Optional[str]:
199
+ args = ["git"]
200
+ if cwd:
201
+ args.extend(["-C", cwd])
202
+ args.extend(["rev-parse", "--show-toplevel"])
203
+ try:
204
+ result = subprocess.run(args, capture_output=True, text=True, timeout=5)
205
+ if result.returncode == 0:
206
+ return result.stdout.strip()
207
+ except (subprocess.TimeoutExpired, FileNotFoundError):
208
+ pass
209
+ return None
210
+
211
+
212
+ def _main_worktree_root(project_root: str) -> str:
213
+ """Return the main worktree root when project_root is a linked worktree."""
214
+ try:
215
+ result = subprocess.run(
216
+ ["git", "-C", project_root, "worktree", "list", "--porcelain"],
217
+ capture_output=True, text=True, timeout=5
218
+ )
219
+ except (subprocess.TimeoutExpired, FileNotFoundError):
220
+ return project_root
221
+
222
+ if result.returncode != 0:
223
+ return project_root
224
+
225
+ for line in result.stdout.splitlines():
226
+ if line.startswith("worktree "):
227
+ main_root = line.split(" ", 1)[1].strip()
228
+ return main_root or project_root
229
+ return project_root
230
+
231
+
197
232
  def detect_project() -> dict:
198
233
  """Detect current project context. Returns dict with id, name, root, project_dir."""
199
234
  project_root = None
200
235
 
236
+ if os.environ.get("CLV2_NO_PROJECT") == "1":
237
+ return {
238
+ "id": "global",
239
+ "name": "global",
240
+ "root": "",
241
+ "project_dir": HOMUNCULUS_DIR,
242
+ "instincts_personal": GLOBAL_PERSONAL_DIR,
243
+ "instincts_inherited": GLOBAL_INHERITED_DIR,
244
+ "evolved_dir": GLOBAL_EVOLVED_DIR,
245
+ "observations_file": GLOBAL_OBSERVATIONS_FILE,
246
+ }
247
+
201
248
  # 1. CLAUDE_PROJECT_DIR env var
202
249
  env_dir = os.environ.get("CLAUDE_PROJECT_DIR")
203
250
  if env_dir and os.path.isdir(env_dir):
204
- project_root = env_dir
251
+ project_root = _git_repo_root(env_dir)
205
252
 
206
253
  # 2. git repo root
207
254
  if not project_root:
208
- try:
209
- result = subprocess.run(
210
- ["git", "rev-parse", "--show-toplevel"],
211
- capture_output=True, text=True, timeout=5
212
- )
213
- if result.returncode == 0:
214
- project_root = result.stdout.strip()
215
- except (subprocess.TimeoutExpired, FileNotFoundError):
216
- pass
255
+ project_root = _git_repo_root()
217
256
 
218
257
  # Normalize: strip trailing slashes to keep basename and hash stable
219
258
  if project_root:
@@ -250,9 +289,10 @@ def detect_project() -> dict:
250
289
  if remote_url:
251
290
  remote_url = _strip_remote_credentials(remote_url)
252
291
 
292
+ fallback_root = _main_worktree_root(project_root) if not remote_url else project_root
253
293
  legacy_hash_source = remote_url if remote_url else project_root
254
294
  normalized_remote = _normalize_remote_url(remote_url) if remote_url else ""
255
- hash_source = normalized_remote if normalized_remote else legacy_hash_source
295
+ hash_source = normalized_remote if normalized_remote else (remote_url if remote_url else fallback_root)
256
296
  project_id = _project_hash(hash_source)
257
297
 
258
298
  project_dir = PROJECTS_DIR / project_id
@@ -352,6 +392,26 @@ def load_registry() -> dict:
352
392
  return {}
353
393
 
354
394
 
395
+ def _write_registry(registry: dict) -> None:
396
+ """Write the project registry atomically."""
397
+ REGISTRY_FILE.parent.mkdir(parents=True, exist_ok=True)
398
+ tmp_file = REGISTRY_FILE.parent / f".{REGISTRY_FILE.name}.tmp.{os.getpid()}"
399
+ with open(tmp_file, "w", encoding="utf-8") as f:
400
+ json.dump(registry, f, indent=2)
401
+ f.write("\n")
402
+ f.flush()
403
+ os.fsync(f.fileno())
404
+ os.replace(tmp_file, REGISTRY_FILE)
405
+
406
+
407
+ def _validate_project_id(project_id: str) -> bool:
408
+ if not project_id or len(project_id) > 128:
409
+ return False
410
+ if "/" in project_id or "\\" in project_id or ".." in project_id:
411
+ return False
412
+ return bool(re.match(r"^[A-Za-z0-9][A-Za-z0-9._-]*$", project_id))
413
+
414
+
355
415
  # ─────────────────────────────────────────────
356
416
  # Instinct Parser
357
417
  # ─────────────────────────────────────────────
@@ -436,6 +496,96 @@ def _load_instincts_from_dir(directory: Path, source_type: str, scope_label: str
436
496
  return instincts
437
497
 
438
498
 
499
+ def _project_counts(project_id: str) -> dict:
500
+ project_dir = PROJECTS_DIR / project_id
501
+ personal_dir = project_dir / "instincts" / "personal"
502
+ inherited_dir = project_dir / "instincts" / "inherited"
503
+ observations_file = project_dir / "observations.jsonl"
504
+
505
+ personal_count = len(_load_instincts_from_dir(personal_dir, "personal", "project"))
506
+ inherited_count = len(_load_instincts_from_dir(inherited_dir, "inherited", "project"))
507
+ observations_count = 0
508
+ if observations_file.exists():
509
+ try:
510
+ with open(observations_file, encoding="utf-8") as f:
511
+ observations_count = sum(1 for _ in f)
512
+ except OSError:
513
+ observations_count = 0
514
+
515
+ return {
516
+ "personal": personal_count,
517
+ "inherited": inherited_count,
518
+ "observations": observations_count,
519
+ "total": personal_count + inherited_count + observations_count,
520
+ }
521
+
522
+
523
+ def _remove_project_storage(project_id: str) -> None:
524
+ project_dir = PROJECTS_DIR / project_id
525
+ if project_dir.exists():
526
+ shutil.rmtree(project_dir)
527
+
528
+
529
+ def _project_instinct_ids(project_dir: Path, source_type: str) -> set[str]:
530
+ instinct_dir = project_dir / "instincts" / source_type
531
+ return {
532
+ inst.get("id")
533
+ for inst in _load_instincts_from_dir(instinct_dir, source_type, "project")
534
+ if inst.get("id")
535
+ }
536
+
537
+
538
+ def _merge_instinct_dir(from_dir: Path, into_dir: Path, existing_ids: set[str]) -> tuple[int, int]:
539
+ moved = 0
540
+ skipped = 0
541
+ if not from_dir.exists():
542
+ return moved, skipped
543
+
544
+ into_dir.mkdir(parents=True, exist_ok=True)
545
+ for file_path in sorted(from_dir.iterdir()):
546
+ if not file_path.is_file() or file_path.suffix.lower() not in ALLOWED_INSTINCT_EXTENSIONS:
547
+ continue
548
+ try:
549
+ instincts = parse_instinct_file(file_path.read_text(encoding="utf-8"))
550
+ except (OSError, UnicodeDecodeError):
551
+ instincts = []
552
+ instinct_ids = [inst.get("id") for inst in instincts if inst.get("id")]
553
+ if any(instinct_id in existing_ids for instinct_id in instinct_ids):
554
+ skipped += 1
555
+ continue
556
+
557
+ target_path = into_dir / file_path.name
558
+ if target_path.exists():
559
+ target_path = into_dir / f"{file_path.stem}-{_project_hash(str(file_path))}{file_path.suffix}"
560
+ shutil.copy2(file_path, target_path)
561
+ existing_ids.update(instinct_ids)
562
+ moved += 1
563
+
564
+ return moved, skipped
565
+
566
+
567
+ def _append_observations(from_project_dir: Path, into_project_dir: Path) -> int:
568
+ from_file = from_project_dir / "observations.jsonl"
569
+ if not from_file.exists():
570
+ return 0
571
+
572
+ into_file = into_project_dir / "observations.jsonl"
573
+ into_file.parent.mkdir(parents=True, exist_ok=True)
574
+ try:
575
+ lines = from_file.read_text(encoding="utf-8").splitlines()
576
+ except (OSError, UnicodeDecodeError):
577
+ return 0
578
+
579
+ if not lines:
580
+ return 0
581
+
582
+ with open(into_file, "a", encoding="utf-8") as f:
583
+ for line in lines:
584
+ if line.strip():
585
+ f.write(line.rstrip("\n") + "\n")
586
+ return len([line for line in lines if line.strip()])
587
+
588
+
439
589
  def load_all_instincts(project: dict, include_global: bool = True) -> list[dict]:
440
590
  """Load all instincts: project-scoped + global.
441
591
 
@@ -1180,7 +1330,14 @@ def _promote_auto(project: dict, force: bool, dry_run: bool) -> int:
1180
1330
  # ─────────────────────────────────────────────
1181
1331
 
1182
1332
  def cmd_projects(args) -> int:
1183
- """List all known projects and their instinct counts."""
1333
+ """List or maintain known projects and their instinct counts."""
1334
+ if getattr(args, "project_action", None) == "delete":
1335
+ return _cmd_projects_delete(args)
1336
+ if getattr(args, "project_action", None) == "merge":
1337
+ return _cmd_projects_merge(args)
1338
+ if getattr(args, "project_action", None) == "gc":
1339
+ return _cmd_projects_gc(args)
1340
+
1184
1341
  registry = load_registry()
1185
1342
 
1186
1343
  if not registry:
@@ -1225,6 +1382,143 @@ def cmd_projects(args) -> int:
1225
1382
  return 0
1226
1383
 
1227
1384
 
1385
+ def _cmd_projects_delete(args) -> int:
1386
+ registry = load_registry()
1387
+ project_id = args.project_id
1388
+
1389
+ if not _validate_project_id(project_id):
1390
+ print(f"Invalid project ID: {project_id}", file=sys.stderr)
1391
+ return 1
1392
+ if project_id not in registry and not (PROJECTS_DIR / project_id).exists():
1393
+ print(f"Project '{project_id}' not found.", file=sys.stderr)
1394
+ return 1
1395
+
1396
+ counts = _project_counts(project_id)
1397
+ print(f"Project: {project_id}")
1398
+ print(f" Instincts: {counts['personal']} personal, {counts['inherited']} inherited")
1399
+ print(f" Observations: {counts['observations']} events")
1400
+
1401
+ if args.dry_run:
1402
+ print(f"\n[DRY RUN] Would delete project '{project_id}' from registry and storage.")
1403
+ return 0
1404
+
1405
+ if not args.force:
1406
+ if counts["total"] > 0:
1407
+ print("\nWarning: this project has instincts or observations.")
1408
+ response = input(f"Delete project '{project_id}'? [y/N] ")
1409
+ if response.lower() != "y":
1410
+ print("Cancelled.")
1411
+ return 0
1412
+
1413
+ registry.pop(project_id, None)
1414
+ _write_registry(registry)
1415
+ _remove_project_storage(project_id)
1416
+ print(f"\nDeleted project '{project_id}'.")
1417
+ return 0
1418
+
1419
+
1420
+ def _cmd_projects_gc(args) -> int:
1421
+ registry = load_registry()
1422
+ candidates = [
1423
+ project_id
1424
+ for project_id in sorted(registry)
1425
+ if _validate_project_id(project_id) and _project_counts(project_id)["total"] == 0
1426
+ ]
1427
+
1428
+ if not candidates:
1429
+ print("No zero-value project entries found.")
1430
+ return 0
1431
+
1432
+ print(f"Zero-value project entries: {len(candidates)}")
1433
+ for project_id in candidates:
1434
+ pinfo = registry.get(project_id, {})
1435
+ print(f" - {pinfo.get('name', project_id)} [{project_id}]")
1436
+
1437
+ if args.dry_run:
1438
+ print(f"\n[DRY RUN] Would delete {len(candidates)} project entr{'y' if len(candidates) == 1 else 'ies'}.")
1439
+ return 0
1440
+
1441
+ if not args.force:
1442
+ response = input(f"\nDelete {len(candidates)} zero-value project entr{'y' if len(candidates) == 1 else 'ies'}? [y/N] ")
1443
+ if response.lower() != "y":
1444
+ print("Cancelled.")
1445
+ return 0
1446
+
1447
+ for project_id in candidates:
1448
+ registry.pop(project_id, None)
1449
+ _remove_project_storage(project_id)
1450
+ _write_registry(registry)
1451
+ print(f"\nDeleted {len(candidates)} zero-value project entr{'y' if len(candidates) == 1 else 'ies'}.")
1452
+ return 0
1453
+
1454
+
1455
+ def _cmd_projects_merge(args) -> int:
1456
+ from_id = args.from_id
1457
+ into_id = args.into_id
1458
+
1459
+ if not _validate_project_id(from_id) or not _validate_project_id(into_id):
1460
+ print("Invalid project ID.", file=sys.stderr)
1461
+ return 1
1462
+ if from_id == into_id:
1463
+ print("Cannot merge a project into itself.", file=sys.stderr)
1464
+ return 1
1465
+
1466
+ registry = load_registry()
1467
+ if from_id not in registry:
1468
+ print(f"Source project '{from_id}' not found.", file=sys.stderr)
1469
+ return 1
1470
+ if into_id not in registry:
1471
+ print(f"Destination project '{into_id}' not found.", file=sys.stderr)
1472
+ return 1
1473
+
1474
+ from_counts = _project_counts(from_id)
1475
+ into_counts = _project_counts(into_id)
1476
+ print(f"Merge: {from_id} -> {into_id}")
1477
+ print(f" Source: {from_counts['personal']} personal, {from_counts['inherited']} inherited, {from_counts['observations']} observations")
1478
+ print(f" Destination before merge: {into_counts['personal']} personal, {into_counts['inherited']} inherited, {into_counts['observations']} observations")
1479
+
1480
+ if args.dry_run:
1481
+ print("\n[DRY RUN] Would merge source project into destination and remove source.")
1482
+ return 0
1483
+
1484
+ if not args.force:
1485
+ response = input(f"\nMerge '{from_id}' into '{into_id}' and remove source? [y/N] ")
1486
+ if response.lower() != "y":
1487
+ print("Cancelled.")
1488
+ return 0
1489
+
1490
+ from_project_dir = PROJECTS_DIR / from_id
1491
+ into_project_dir = PROJECTS_DIR / into_id
1492
+ into_project_dir.mkdir(parents=True, exist_ok=True)
1493
+
1494
+ personal_existing = _project_instinct_ids(into_project_dir, "personal")
1495
+ inherited_existing = _project_instinct_ids(into_project_dir, "inherited")
1496
+ personal_moved, personal_skipped = _merge_instinct_dir(
1497
+ from_project_dir / "instincts" / "personal",
1498
+ into_project_dir / "instincts" / "personal",
1499
+ personal_existing,
1500
+ )
1501
+ inherited_moved, inherited_skipped = _merge_instinct_dir(
1502
+ from_project_dir / "instincts" / "inherited",
1503
+ into_project_dir / "instincts" / "inherited",
1504
+ inherited_existing,
1505
+ )
1506
+ observations_moved = _append_observations(from_project_dir, into_project_dir)
1507
+
1508
+ registry.pop(from_id, None)
1509
+ destination = registry.get(into_id, {})
1510
+ destination["last_seen"] = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
1511
+ registry[into_id] = destination
1512
+ _write_registry(registry)
1513
+ _remove_project_storage(from_id)
1514
+
1515
+ print("\nMerged project registry entry.")
1516
+ print(f" Moved instincts: {personal_moved + inherited_moved}")
1517
+ print(f" Skipped duplicate instincts: {personal_skipped + inherited_skipped}")
1518
+ print(f" Appended observations: {observations_moved}")
1519
+ return 0
1520
+
1521
+
1228
1522
  # ─────────────────────────────────────────────
1229
1523
  # Generate Evolved Structures
1230
1524
  # ─────────────────────────────────────────────
@@ -1486,6 +1780,19 @@ def main() -> int:
1486
1780
 
1487
1781
  # Projects (new in v2.1)
1488
1782
  projects_parser = subparsers.add_parser('projects', help='List known projects and instinct counts')
1783
+ projects_subparsers = projects_parser.add_subparsers(dest='project_action')
1784
+ projects_delete = projects_subparsers.add_parser('delete', help='Delete a project registry entry')
1785
+ projects_delete.add_argument('project_id', help='Project ID to delete')
1786
+ projects_delete.add_argument('--dry-run', action='store_true', help='Preview without deleting')
1787
+ projects_delete.add_argument('--force', action='store_true', help='Skip confirmation')
1788
+ projects_merge = projects_subparsers.add_parser('merge', help='Merge one project registry entry into another')
1789
+ projects_merge.add_argument('from_id', help='Source project ID')
1790
+ projects_merge.add_argument('into_id', help='Destination project ID')
1791
+ projects_merge.add_argument('--dry-run', action='store_true', help='Preview without merging')
1792
+ projects_merge.add_argument('--force', action='store_true', help='Skip confirmation')
1793
+ projects_gc = projects_subparsers.add_parser('gc', help='Delete zero-value project registry entries')
1794
+ projects_gc.add_argument('--dry-run', action='store_true', help='Preview without deleting')
1795
+ projects_gc.add_argument('--force', action='store_true', help='Skip confirmation')
1489
1796
 
1490
1797
  # Prune (pending instinct TTL)
1491
1798
  prune_parser = subparsers.add_parser('prune', help='Delete pending instincts older than TTL')
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: data-throughput-accelerator
3
+ description: Use when large data ingestion, backfill, export, ETL, warehouse loading, manifest catch-up, or table synchronization needs to become much faster while preserving data correctness.
4
+ origin: ECC
5
+ tools: Read, Write, Edit, Bash, Grep, Glob
6
+ ---
7
+
8
+ # Data Throughput Accelerator
9
+
10
+ Use this skill when the bottleneck is moving, transforming, or saving lots of
11
+ data. The goal is not just speed. The goal is faster correct data landing in the
12
+ right place with proof.
13
+
14
+ ## First Distinction
15
+
16
+ Separate these before optimizing:
17
+
18
+ - source extraction speed;
19
+ - network transfer speed;
20
+ - warehouse/load speed;
21
+ - transform speed;
22
+ - serving-table freshness;
23
+ - live tail growth while the job runs.
24
+
25
+ A pipeline can be "fast" and still appear behind if new data arrives faster
26
+ than the final catch-up window.
27
+
28
+ ## Fast Path Heuristics
29
+
30
+ - Move compute to where the data already is.
31
+ - Prefer warehouse-native scans, joins, and appends for large landed files.
32
+ - Use manifests or checkpoints so completed files/partitions are skipped.
33
+ - Use partitioning and clustering that match the read and append pattern.
34
+ - Batch small files, requests, and writes.
35
+ - Make writes idempotent through unique keys, manifests, or replaceable staging.
36
+ - Keep raw, derived, and serving tables separately accountable.
37
+
38
+ ## Workflow
39
+
40
+ 1. Read the current source, target, and manifest contracts.
41
+ 2. Measure backlog: external files, manifest rows, raw rows, derived rows,
42
+ min/max timestamps, and unprocessed counts.
43
+ 3. Run a safe catch-up or sample benchmark.
44
+ 4. Compare variants: batch size, worker count, warehouse SQL, file grouping,
45
+ staging shape, and manifest update method.
46
+ 5. Promote only the fastest path that keeps counts and timestamps coherent.
47
+ 6. Codify the path as a CLI, scheduled job, workflow, or runbook.
48
+ 7. Rerun final accounting after the codified path executes.
49
+
50
+ ## Accounting Output
51
+
52
+ Use a hard accounting block:
53
+
54
+ ```text
55
+ Data throughput result:
56
+ - Source files discovered: 294
57
+ - Files processed this run: 294
58
+ - Raw rows added: 9,683,598
59
+ - Derived rows added: 8,917,585
60
+ - Remaining tail: 24 files at readback time
61
+ - Runtime: 38.7s
62
+ - Correctness gate: manifest counts and table max timestamps match
63
+ ```
64
+
65
+ ## Guardrails
66
+
67
+ - Do not delete raw data to make a metric look better.
68
+ - Do not skip failed files silently.
69
+ - Do not mix historical backfill status with live-tail freshness.
70
+ - Do not call a pipeline complete until the target tables and manifest agree.
71
+ - For finance, healthcare, regulated, or customer-impacting data, preserve
72
+ replay evidence and approval gates.
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: dynamic-workflow-mode
3
+ description: "Design task-local harnesses, eval gates, and reusable skill extraction for Claude dynamic workflow mode and other adaptive agent harnesses."
4
+ origin: ECC
5
+ ---
6
+
7
+ # Dynamic Workflow Mode
8
+
9
+ Use this skill when a coding agent can generate or adapt a task-local harness instead of only following a static command flow. The goal is to turn dynamic workflow mode into a disciplined system: temporary harnesses for one-off work, shared skill extraction for repeated work, and observable control pane checkpoints for teams.
10
+
11
+ ## When To Activate
12
+
13
+ - The user mentions dynamic workflows, custom harnesses, harness-per-task, adaptive workflows, or Claude Code dynamic workflow mode.
14
+ - A task needs a custom loop, evaluator, crawler, fixture generator, watcher, or local dashboard.
15
+ - Multiple agents need the same repeatable process but the process is not yet captured as a shared skill.
16
+ - A workflow needs durable handoff artifacts, eval evidence, or operator approval before merge.
17
+
18
+ ## Core Contract
19
+
20
+ Dynamic workflow mode should produce a task-local harness only when the harness is cheaper and safer than manually driving the same steps. The harness must have:
21
+
22
+ - **Objective**: the outcome it owns and the outcome it explicitly does not own.
23
+ - **Inputs**: files, URLs, prompts, data sources, credentials policy, and user-provided constraints.
24
+ - **Outputs**: commits, reports, screenshots, status files, or control pane snapshots.
25
+ - **Eval**: at least one pass/fail check tied to the task, not only "it ran".
26
+ - **Handoff**: a short artifact that tells the next operator what happened, what is blocked, and how to resume.
27
+
28
+ ## Dynamic Harness Decision Tree
29
+
30
+ 1. **One-shot task**: keep it inline. Do not invent a harness.
31
+ 2. **Repeated task with changing inputs**: create a task-local harness and keep it under a temp or project-local working area.
32
+ 3. **Repeated task across teammates or repos**: extract the pattern into a shared skill.
33
+ 4. **Task with external state, queueing, or approvals**: add control pane visibility before adding more automation.
34
+ 5. **Task with safety risk**: add an eval gate and a human merge gate before autonomous execution.
35
+
36
+ ## Task-Local Harness Template
37
+
38
+ Use this structure before writing code:
39
+
40
+ ```markdown
41
+ # Dynamic Workflow Harness
42
+
43
+ Objective:
44
+ - Ship:
45
+ - Do not ship:
46
+
47
+ Inputs:
48
+ - Repo or workspace:
49
+ - External systems:
50
+ - Credentials policy:
51
+
52
+ Loop:
53
+ 1. Discover current state.
54
+ 2. Generate or update the smallest useful artifact.
55
+ 3. Run eval checks.
56
+ 4. Record status and handoff.
57
+ 5. Stop on failed gate, unclear ownership, or unsafe external action.
58
+
59
+ Eval:
60
+ - Command:
61
+ - Expected pass signal:
62
+ - Failure owner:
63
+
64
+ Handoff:
65
+ - Status:
66
+ - Evidence:
67
+ - Next action:
68
+ ```
69
+
70
+ ## Shared Skill Extraction
71
+
72
+ Promote a task-local harness into a shared skill only when at least two of these are true:
73
+
74
+ - The same workflow appears in multiple sessions, repos, teams, or launches.
75
+ - The workflow needs specific language, tool, or safety sequencing.
76
+ - Failures repeat because operators skip a gate or lose context.
77
+ - The workflow has a stable input/output contract.
78
+ - The workflow benefits from a control pane, status board, or team handoff.
79
+
80
+ When extracting, write the skill first in `skills/<name>/SKILL.md`. Add command shims only if a legacy slash-entry surface is still required.
81
+
82
+ ## Control Pane Checkpoints
83
+
84
+ Dynamic workflow mode becomes team-usable when it exposes state. Record these checkpoints whenever the task spans more than one session:
85
+
86
+ - **Plan**: objective, owner, acceptance criteria, and risky external systems.
87
+ - **Queue**: work items, assigned agent role, branch/worktree, and dependency edges.
88
+ - **Run**: active harness, current loop step, recent eval result, and token/cost signal if available.
89
+ - **Gate**: test results, browser screenshots, security review, and merge readiness.
90
+ - **Handoff**: what is done, what failed, what needs a human decision.
91
+
92
+ If the repo has ECC2 state enabled, prefer adding or reading checkpoints through the ECC control pane or state-store-backed scripts instead of scattering untracked notes.
93
+
94
+ ## Eval Gates
95
+
96
+ Every dynamic harness needs a task-specific eval. Pick the cheapest reliable gate:
97
+
98
+ | Work Type | Eval Gate |
99
+ | --- | --- |
100
+ | Code feature | Focused test, lint, coverage, and one integration path |
101
+ | UI/control pane | Browser smoke with screenshot and overflow/error checks |
102
+ | Agent workflow | Fixture transcript or seeded work item with expected routing |
103
+ | Research/content | Source-neutral brief, claim checklist, and publish-ready outline |
104
+ | Integration | Dry-run command, config validation, and no-secret scan |
105
+
106
+ Do not claim a dynamic workflow is reusable until the eval can be rerun by another teammate.
107
+
108
+ ## Anti-Patterns
109
+
110
+ - Generating scripts that hide the real decision logic from the operator.
111
+ - Treating dynamic workflow mode as permission to skip tests.
112
+ - Creating one-off docs when a shared skill or status artifact is the real product.
113
+ - Running multiple agents without ownership, merge gate, or conflict policy.
114
+ - Letting raw private research data leak into public docs.
115
+
116
+ ## Output Standard
117
+
118
+ Finish with:
119
+
120
+ - The harness or skill path.
121
+ - The eval commands and results.
122
+ - The control pane or handoff artifact path.
123
+ - The next reusable extraction candidate.