@zalom/plastic 2.0.0-alpha.9 → 2.0.1

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 (322) hide show
  1. package/PLASTIC.md +13 -136
  2. package/README.md +357 -133
  3. package/agents/plastic-enforcer.md +20 -15
  4. package/agents/plastic-executor.md +15 -4
  5. package/agents/plastic-node-research.md +30 -0
  6. package/agents/plastic-node-verify.md +28 -0
  7. package/agents/plastic-node-work.md +33 -0
  8. package/agents/{plastic-advisor.md → plastic-primary-advisor.md} +7 -9
  9. package/agents/{plastic-faux-advisor.md → plastic-secondary-advisor.md} +9 -12
  10. package/assets/plastic-logo.svg +1 -0
  11. package/bin/crap +4 -0
  12. package/bin/lib/context_budget.rb +43 -6
  13. package/bin/lib/skill_census.rb +839 -0
  14. package/bin/plastic +6 -0
  15. package/bin/plastic-skill-census +114 -0
  16. package/bin/test +24 -4
  17. package/bin/verify-change +345 -0
  18. package/config_asks.yml +4 -4
  19. package/deprecations.yml +1 -1
  20. package/{skills/agent-advisor/references → docs/help}/advisor-protocol.md +19 -24
  21. package/{skills/auto/references → docs/help}/agent-architecture.md +16 -14
  22. package/{skills/conventions/references → docs/help}/completion-and-done.md +15 -16
  23. package/docs/help/human-report-contract.md +152 -0
  24. package/{skills/conventions/references → docs/help}/knowledge-graph.md +9 -0
  25. package/{skills/conventions/references → docs/help}/locks-and-worktrees.md +11 -13
  26. package/{skills/conventions/references → docs/help}/maintenance-and-revisions.md +1 -1
  27. package/{skills/conventions/references → docs/help}/roadmaps.md +2 -2
  28. package/{skills/tutorial/references → docs/help}/track-1-guided.md +28 -47
  29. package/{skills/tutorial/references → docs/help}/track-2-auto.md +8 -8
  30. package/{skills/tutorial/references → docs/help}/track-3-projects-and-roadmaps.md +24 -17
  31. package/hooks/call-budget +4 -0
  32. package/hooks/hooks.json +24 -0
  33. package/hooks/message-display +55 -2
  34. package/hooks/session-start +5 -1
  35. package/hooks/statusline +32 -27
  36. package/hooks/stop +5 -0
  37. package/package.json +5 -3
  38. package/scripts/append-ledger +2 -1
  39. package/scripts/dashboard.rb +267 -16
  40. package/scripts/day-summary +2 -1
  41. package/scripts/doctor.rb +680 -39
  42. package/scripts/end-intent +153 -30
  43. package/scripts/exec-worktree +5 -5
  44. package/scripts/file-session-intent +2 -1
  45. package/scripts/graph-measure +249 -0
  46. package/scripts/hook-call-budget +222 -0
  47. package/scripts/hook-capture +24 -123
  48. package/scripts/hook-close +2 -1
  49. package/scripts/hook-message-display +7 -0
  50. package/scripts/hook-record +24 -16
  51. package/scripts/hook-savepoint +27 -3
  52. package/scripts/hook-session-start +359 -321
  53. package/scripts/hook-stop +58 -0
  54. package/scripts/index-projection +74 -0
  55. package/scripts/insight-append +17 -4
  56. package/scripts/install.rb +9 -7
  57. package/scripts/lib/action_graph_shim.rb +279 -0
  58. package/scripts/lib/active_delivery.rb +105 -0
  59. package/scripts/lib/agent_models.rb +63 -25
  60. package/scripts/lib/arm.rb +48 -83
  61. package/scripts/lib/atomic_write.rb +31 -0
  62. package/scripts/lib/backup.rb +65 -0
  63. package/scripts/lib/cli/command.rb +92 -0
  64. package/scripts/lib/cli/commands/auto.rb +18 -0
  65. package/scripts/lib/cli/commands/auto_brief.rb +44 -0
  66. package/scripts/lib/cli/commands/auto_lock.rb +99 -0
  67. package/scripts/lib/cli/commands/auto_report.rb +50 -0
  68. package/scripts/lib/cli/commands/auto_take.rb +31 -0
  69. package/scripts/lib/cli/commands/backup.rb +43 -0
  70. package/scripts/lib/cli/commands/checkout.rb +25 -0
  71. package/scripts/lib/cli/commands/continue.rb +66 -0
  72. package/scripts/lib/cli/commands/doctor.rb +81 -0
  73. package/scripts/lib/cli/commands/feedback.rb +40 -0
  74. package/scripts/lib/cli/commands/help.rb +69 -0
  75. package/scripts/lib/cli/commands/hook.rb +32 -0
  76. package/scripts/lib/cli/commands/index.rb +23 -0
  77. package/scripts/lib/cli/commands/install.rb +21 -0
  78. package/scripts/lib/cli/commands/installer_verb.rb +37 -0
  79. package/scripts/lib/cli/commands/intent.rb +19 -0
  80. package/scripts/lib/cli/commands/intent_answer.rb +37 -0
  81. package/scripts/lib/cli/commands/intent_command.rb +53 -0
  82. package/scripts/lib/cli/commands/intent_end.rb +62 -0
  83. package/scripts/lib/cli/commands/intent_new.rb +62 -0
  84. package/scripts/lib/cli/commands/intent_note.rb +43 -0
  85. package/scripts/lib/cli/commands/intent_rule.rb +36 -0
  86. package/scripts/lib/cli/commands/intent_show.rb +32 -0
  87. package/scripts/lib/cli/commands/intent_spec.rb +44 -0
  88. package/scripts/lib/cli/commands/intent_step.rb +71 -0
  89. package/scripts/lib/cli/commands/intent_verify.rb +26 -0
  90. package/scripts/lib/cli/commands/migrate.rb +16 -0
  91. package/scripts/lib/cli/commands/migrate_stores.rb +31 -0
  92. package/scripts/lib/cli/commands/next.rb +54 -0
  93. package/scripts/lib/cli/commands/project.rb +19 -0
  94. package/scripts/lib/cli/commands/project_links.rb +42 -0
  95. package/scripts/lib/cli/commands/project_list.rb +20 -0
  96. package/scripts/lib/cli/commands/project_new.rb +72 -0
  97. package/scripts/lib/cli/commands/query.rb +31 -0
  98. package/scripts/lib/cli/commands/render.rb +33 -0
  99. package/scripts/lib/cli/commands/roadmap.rb +19 -0
  100. package/scripts/lib/cli/commands/roadmap_check.rb +54 -0
  101. package/scripts/lib/cli/commands/roadmap_log.rb +54 -0
  102. package/scripts/lib/cli/commands/roadmap_migrate.rb +53 -0
  103. package/scripts/lib/cli/commands/roadmap_next.rb +70 -0
  104. package/scripts/lib/cli/commands/roadmap_show.rb +45 -0
  105. package/scripts/lib/cli/commands/rollback.rb +20 -0
  106. package/scripts/lib/cli/commands/search.rb +60 -0
  107. package/scripts/lib/cli/commands/session.rb +18 -0
  108. package/scripts/lib/cli/commands/session_commit.rb +42 -0
  109. package/scripts/lib/cli/commands/session_handoff.rb +34 -0
  110. package/scripts/lib/cli/commands/session_summary.rb +35 -0
  111. package/scripts/lib/cli/commands/status.rb +68 -0
  112. package/scripts/lib/cli/commands/subcommand_list.rb +36 -0
  113. package/scripts/lib/cli/commands/sync.rb +46 -0
  114. package/scripts/lib/cli/commands/uninstall.rb +20 -0
  115. package/scripts/lib/cli/commands/update.rb +20 -0
  116. package/scripts/lib/cli/commands/version.rb +53 -0
  117. package/scripts/lib/cli/frontier.rb +86 -0
  118. package/scripts/lib/cli/intent_progress.rb +36 -0
  119. package/scripts/lib/cli/legacy.rb +80 -0
  120. package/scripts/lib/cli/output.rb +137 -0
  121. package/scripts/lib/cli/scope.rb +134 -0
  122. package/scripts/lib/cli/table.rb +65 -0
  123. package/scripts/lib/cli.rb +94 -0
  124. package/scripts/lib/codex_adapter.rb +198 -0
  125. package/scripts/lib/compact_instructions.rb +13 -5
  126. package/scripts/lib/core_integrity.rb +71 -0
  127. package/scripts/lib/dashboard_screen.rb +40 -0
  128. package/scripts/lib/data_boundary.rb +132 -0
  129. package/scripts/lib/day_summary.rb +23 -14
  130. package/scripts/lib/doctor_core.rb +114 -38
  131. package/scripts/lib/doctor_session_ledger.rb +5 -53
  132. package/scripts/lib/engine_permissions.rb +88 -0
  133. package/scripts/lib/exec_worktree.rb +24 -21
  134. package/scripts/lib/feedback_report.rb +1 -1
  135. package/scripts/lib/graph_edges.rb +137 -0
  136. package/scripts/lib/graph_file.rb +246 -0
  137. package/scripts/lib/graph_measure.rb +645 -0
  138. package/scripts/lib/graph_measure_budget.rb +409 -0
  139. package/scripts/lib/graph_measure_cohorts.rb +487 -0
  140. package/scripts/lib/graph_measure_models.rb +413 -0
  141. package/scripts/lib/graph_measure_report.rb +532 -0
  142. package/scripts/lib/graph_tree.rb +98 -0
  143. package/scripts/lib/guarded_append.rb +155 -0
  144. package/scripts/lib/handoff.rb +40 -13
  145. package/scripts/lib/harness_adapter.rb +184 -0
  146. package/scripts/lib/hook_registry.rb +27 -3
  147. package/scripts/lib/hook_replay.rb +229 -0
  148. package/scripts/lib/index_entry.rb +62 -0
  149. package/scripts/lib/index_projection.rb +201 -0
  150. package/scripts/lib/insights.rb +1 -1
  151. package/scripts/lib/installer_core.rb +531 -71
  152. package/scripts/lib/intent_screen.rb +4 -4
  153. package/scripts/lib/intent_screen_ansi.rb +73 -12
  154. package/scripts/lib/intent_validator.rb +2 -2
  155. package/scripts/lib/lock.rb +10 -11
  156. package/scripts/lib/message_display.rb +350 -54
  157. package/scripts/lib/meter_watch.rb +185 -0
  158. package/scripts/lib/node_file.rb +234 -0
  159. package/scripts/lib/node_ids.rb +99 -0
  160. package/scripts/lib/node_input.rb +913 -0
  161. package/scripts/lib/node_input_compatibility.rb +62 -0
  162. package/scripts/lib/node_ledger.rb +386 -0
  163. package/scripts/lib/node_progress.rb +153 -0
  164. package/scripts/lib/node_return.rb +204 -0
  165. package/scripts/lib/node_worktree.rb +337 -0
  166. package/scripts/lib/outcome_report.rb +440 -0
  167. package/scripts/lib/preflight.rb +4 -6
  168. package/scripts/lib/project_config.rb +46 -0
  169. package/scripts/lib/project_validator.rb +3 -2
  170. package/scripts/lib/qmd_sync.rb +8 -7
  171. package/scripts/lib/ready_set.rb +462 -0
  172. package/scripts/lib/reference_archive.rb +45 -0
  173. package/scripts/lib/release_guard.rb +18 -0
  174. package/scripts/lib/report_screen.rb +1371 -47
  175. package/scripts/lib/rlm/corpus.rb +13 -0
  176. package/scripts/lib/rlm/probe.rb +29 -0
  177. package/scripts/lib/rlm/query.rb +22 -0
  178. package/scripts/lib/roadmap_graph.rb +210 -0
  179. package/scripts/lib/roadmap_migration.rb +95 -0
  180. package/scripts/lib/roadmap_queue.rb +158 -8
  181. package/scripts/lib/roadmap_render.rb +150 -0
  182. package/scripts/lib/roadmap_savepoint.rb +64 -14
  183. package/scripts/lib/runner_absorb.rb +703 -0
  184. package/scripts/lib/runner_answer.rb +206 -0
  185. package/scripts/lib/runner_core.rb +194 -0
  186. package/scripts/lib/runner_dispatch.rb +525 -0
  187. package/scripts/lib/runner_policy.rb +191 -0
  188. package/scripts/lib/runner_proposals.rb +275 -0
  189. package/scripts/lib/runner_rewind.rb +201 -0
  190. package/scripts/lib/runner_sweep.rb +231 -0
  191. package/scripts/lib/runner_until_empty.rb +252 -0
  192. package/scripts/lib/runner_watch.rb +389 -0
  193. package/scripts/lib/savepoint.rb +141 -19
  194. package/scripts/lib/scaffold_intent.rb +6 -3
  195. package/scripts/lib/screen_paint.rb +365 -28
  196. package/scripts/lib/screens/dashboard.rb +20 -0
  197. package/scripts/lib/screens/plan.rb +18 -0
  198. package/scripts/lib/screens/roadmap.rb +15 -0
  199. package/scripts/lib/search_index.rb +55 -0
  200. package/scripts/lib/session_close.rb +30 -28
  201. package/scripts/lib/session_git.rb +25 -18
  202. package/scripts/lib/session_ledger.rb +48 -4
  203. package/scripts/lib/session_usage.rb +190 -0
  204. package/scripts/lib/sqlite.rb +22 -0
  205. package/scripts/lib/stop_gate.rb +95 -0
  206. package/scripts/lib/store_discovery.rb +7 -6
  207. package/scripts/lib/store_layout.rb +54 -0
  208. package/scripts/lib/store_provisioning.rb +2 -1
  209. package/scripts/lib/store_sync.rb +85 -0
  210. package/scripts/lib/stores_move.rb +93 -0
  211. package/scripts/lib/verify_intent.rb +36 -8
  212. package/scripts/lib/version_number.rb +48 -0
  213. package/scripts/lib/work_graph.rb +59 -0
  214. package/scripts/lib/work_graph_validator.rb +201 -0
  215. package/scripts/lib/worktree.rb +27 -32
  216. package/scripts/lib/worktree_sweep.rb +6 -5
  217. package/scripts/link-suggest +2 -1
  218. package/scripts/meter-watch +57 -0
  219. package/scripts/migrate-to-global +1 -1
  220. package/scripts/new-intent +4 -13
  221. package/scripts/node-input +92 -0
  222. package/scripts/node-run +225 -0
  223. package/scripts/node-transition +291 -0
  224. package/scripts/outcome-report +74 -0
  225. package/scripts/plastic-lock +42 -33
  226. package/scripts/promote-session-item +3 -2
  227. package/scripts/read-config +53 -9
  228. package/scripts/ready-set +126 -0
  229. package/scripts/release-check +123 -0
  230. package/scripts/report-screen +177 -16
  231. package/scripts/roadmap-graph +119 -0
  232. package/scripts/roadmap-savepoint +7 -0
  233. package/scripts/runner +581 -0
  234. package/scripts/savepoint-note +11 -9
  235. package/scripts/session-commit +2 -1
  236. package/scripts/session-usage +56 -0
  237. package/scripts/skill-lint +115 -6
  238. package/scripts/spawn-preamble +2 -2
  239. package/scripts/update.rb +25 -4
  240. package/scripts/validate-work-graph +39 -0
  241. package/scripts/verify-intent +3 -2
  242. package/scripts/write-handoff +2 -1
  243. package/templates/agents.md +7 -7
  244. package/templates/config.yml +16 -9
  245. package/templates/dashboard-screen.md +22 -0
  246. package/templates/display-fixture.md +21 -0
  247. package/templates/graph.md +16 -0
  248. package/templates/index.md +1 -1
  249. package/templates/intent-screen.md +1 -1
  250. package/templates/node-decision.md +11 -0
  251. package/templates/node-research.md +13 -0
  252. package/templates/node-verify.md +13 -0
  253. package/templates/node-work.md +22 -0
  254. package/templates/outcome.md +8 -3
  255. package/templates/project.yml +1 -1
  256. package/templates/render.css +10 -0
  257. package/templates/report-plan.md +15 -0
  258. package/templates/report-roadmap-delivered.md +10 -0
  259. package/templates/report-roadmap-plan.md +9 -0
  260. package/templates/report-roadmap-state.md +9 -0
  261. package/templates/report-state.md +1 -1
  262. package/templates/roadmap.md +13 -0
  263. package/bin/plastic.js +0 -70
  264. package/scripts/lib/bridge.rb +0 -116
  265. package/skills/agent-advisor/SKILL.md +0 -92
  266. package/skills/auto/SKILL.md +0 -296
  267. package/skills/auto/evals/evals.json +0 -255
  268. package/skills/auto/references/end-tail.md +0 -66
  269. package/skills/auto/references/human-report-contract.md +0 -78
  270. package/skills/conventions/SKILL.md +0 -29
  271. package/skills/dashboard/SKILL.md +0 -169
  272. package/skills/dashboard/evals/evals.json +0 -38
  273. package/skills/dashboard/references/classification.md +0 -22
  274. package/skills/dashboard/templates/dashboard-global.md +0 -20
  275. package/skills/dashboard/templates/dashboard-project.md +0 -19
  276. package/skills/direct/SKILL.md +0 -66
  277. package/skills/direct/references/request-signals.md +0 -59
  278. package/skills/doctor/SKILL.md +0 -299
  279. package/skills/doctor/report.md +0 -102
  280. package/skills/feedback/SKILL.md +0 -98
  281. package/skills/feedback/references/transport-and-privacy.md +0 -65
  282. package/skills/feedback/report.md +0 -36
  283. package/skills/install/SKILL.md +0 -217
  284. package/skills/intent-continuing/SKILL.md +0 -154
  285. package/skills/intent-continuing/references/board-fill.md +0 -43
  286. package/skills/intent-continuing/references/boarding-matrix.md +0 -34
  287. package/skills/intent-continuing/references/context-management.md +0 -28
  288. package/skills/intent-continuing/references/liveness-ranking.md +0 -57
  289. package/skills/intent-creating/SKILL.md +0 -164
  290. package/skills/intent-creating/evals/evals.json +0 -72
  291. package/skills/intent-creating/references/lifecycle.md +0 -81
  292. package/skills/intent-creating/references/wikilinks.md +0 -8
  293. package/skills/intent-ending/SKILL.md +0 -176
  294. package/skills/intent-ending/evals/evals.json +0 -74
  295. package/skills/intent-executing/SKILL.md +0 -170
  296. package/skills/intent-executing/evals/evals.json +0 -66
  297. package/skills/intent-executing/implementer-prompt.md +0 -42
  298. package/skills/intent-executing/spec-reviewer-prompt.md +0 -27
  299. package/skills/intent-speccing/SKILL.md +0 -130
  300. package/skills/intent-speccing/evals/evals.json +0 -126
  301. package/skills/intent-speccing/references/design-principles.md +0 -44
  302. package/skills/intent-speccing/references/per-section-fill-rules.md +0 -92
  303. package/skills/intent-speccing/references/self-verify-checklist.md +0 -37
  304. package/skills/project-creating/SKILL.md +0 -162
  305. package/skills/project-creating/references/hubs-projects.md +0 -55
  306. package/skills/project-creating/references/project-scaffolding.md +0 -97
  307. package/skills/releasing/SKILL.md +0 -337
  308. package/skills/releasing/references/deprecations.md +0 -60
  309. package/skills/releasing/references/promotion-and-tagging.md +0 -66
  310. package/skills/releasing/references/release-lines.md +0 -105
  311. package/skills/roadmap/SKILL.md +0 -64
  312. package/skills/roadmap/references/file-format.md +0 -124
  313. package/skills/roadmap/references/operations.md +0 -112
  314. package/skills/rollback/SKILL.md +0 -91
  315. package/skills/tutorial/SKILL.md +0 -65
  316. package/skills/tutorial/evals/evals.json +0 -186
  317. package/skills/uninstall/SKILL.md +0 -75
  318. package/skills/update/SKILL.md +0 -126
  319. /package/{skills/auto/references → docs/help}/agent-report-contract.md +0 -0
  320. /package/{skills/intent-executing → docs/help}/code-quality-reviewer-prompt.md +0 -0
  321. /package/{skills/conventions/references → docs/help}/lifecycle-and-savepoints.md +0 -0
  322. /package/{skills/intent-executing → docs/help}/plan-reviewer-prompt.md +0 -0
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ # session-usage (intent 355, D10): read the harness transcripts since a cutoff
6
+ # and report per session the model, calls, boot context, last context, median
7
+ # step, steps over 5k, and cache read. Broken records are counted and named.
8
+ #
9
+ # Usage:
10
+ # session-usage [--since <iso8601>] [--format text|json] [--root <dir>] [--rate-limits <file>]
11
+ #
12
+ # Defaults: the root is ~/.claude/projects, the rate-limit cache is
13
+ # ~/.plastic/.cache/rate-limits.json, and the cutoff is that cache's reset
14
+ # time minus five hours, else the last five hours.
15
+ #
16
+ # Exit codes: 0 reported (unavailable included); 2 usage error.
17
+
18
+ require "json"
19
+ require "time"
20
+ require_relative "lib/session_usage"
21
+
22
+ FLAGS = %w[--since --format --root --rate-limits].freeze
23
+ FORMATS = %w[text json].freeze
24
+
25
+ def usage_abort(message)
26
+ warn "session-usage: #{message}"
27
+ warn "Usage: session-usage [--since <iso8601>] [--format text|json] [--root <dir>] [--rate-limits <file>]"
28
+ exit 2
29
+ end
30
+
31
+ def parse_args(argv)
32
+ usage_abort("every flag takes a value") if argv.length.odd?
33
+ opts = argv.each_slice(2).to_h
34
+ unknown = opts.keys - FLAGS
35
+ usage_abort("unknown flag #{unknown.first.inspect}") unless unknown.empty?
36
+ usage_abort("unknown format #{opts['--format'].inspect}") if opts["--format"] && !FORMATS.include?(opts["--format"])
37
+ opts
38
+ end
39
+
40
+ def parse_since(value)
41
+ value && Time.iso8601(value)
42
+ rescue ArgumentError
43
+ usage_abort("--since #{value.inspect} is not an ISO 8601 time")
44
+ end
45
+
46
+ opts = parse_args(ARGV)
47
+ usage = SessionUsage.new(
48
+ transcripts_root: File.expand_path(opts.fetch("--root", File.join(Dir.home, ".claude", "projects"))),
49
+ rate_limits_path: File.expand_path(opts.fetch("--rate-limits", File.join(Dir.home, ".plastic", ".cache", "rate-limits.json")))
50
+ )
51
+ report = usage.report(since: parse_since(opts["--since"]))
52
+ if opts["--format"] == "json"
53
+ puts JSON.pretty_generate(report)
54
+ else
55
+ print SessionUsage.render_text(report)
56
+ end
@@ -2,11 +2,13 @@
2
2
  # encoding: UTF-8
3
3
  # frozen_string_literal: true
4
4
 
5
- # skill-lint: deterministic CLI over SkillLint (intent 85b).
5
+ # skill-lint: deterministic CLI over SkillLint (intent 85b), plus one CLI-local
6
+ # check (intent 341, G8, n1, C35).
6
7
  #
7
- # Runs the five structural skill checks (body-budget, frontmatter-validity,
8
- # bare-pointer, orphan-files, references-depth) over a directory of Agent
9
- # Skills and reports every violation. Mirrors `scripts/validate-intent`'s
8
+ # Runs the five structural checks (body-budget, frontmatter-validity,
9
+ # bare-pointer, orphan-files, references-depth) via SkillLint, then this
10
+ # script's own refusal-restatement check, over a directory of Agent Skills,
11
+ # and reports every violation. Mirrors `scripts/validate-intent`'s
10
12
  # CLI-over-lib shape and exit-code contract.
11
13
  #
12
14
  # Usage:
@@ -17,6 +19,112 @@
17
19
 
18
20
  require_relative "lib/skill_lint"
19
21
 
22
+ # RefusalRestatementCheck (C35): a skill body must not restate, past a short
23
+ # run of words, a refusal rule the conventions chapter already carries; it
24
+ # must link that chapter instead. No-op when <skills_dir>/conventions/references
25
+ # does not exist, so an older tree or a fixture dir with no conventions chapter
26
+ # is unaffected.
27
+ #
28
+ # Deliberately lives in this CLI, not in scripts/lib/skill_lint.rb: C35 is a
29
+ # doctrine-duplication check, one level removed from SkillLint's five
30
+ # structural checks, and keeping it here means adding it touches only the
31
+ # files this change is scoped to.
32
+ class RefusalRestatementCheck
33
+ REFUSAL_KEYWORD_RE = /\brefus(e|es|ed|ing|al)\b/i
34
+ CONVENTIONS_LINK_RE = %r{conventions/references/|plastic-conventions}i
35
+
36
+ # How many consecutive normalized words must match, verbatim, between a
37
+ # skill's refusal paragraph and the doctrine text before it counts as a
38
+ # restatement rather than a coincidental shared phrase.
39
+ NGRAM = 6
40
+
41
+ def initialize(skills_dir)
42
+ @skills_dir = skills_dir
43
+ end
44
+
45
+ def run
46
+ doctrine = doctrine_blob
47
+ return [] unless doctrine
48
+
49
+ skill_md_paths.flat_map do |skill_md|
50
+ skill_dir = File.dirname(skill_md)
51
+ next [] if File.basename(skill_dir) == "conventions" # the source never restates itself
52
+
53
+ check_skill(skill_dir, skill_md, File.read(skill_md), doctrine)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def skill_md_paths
60
+ Dir.glob(File.join(@skills_dir, "*", "SKILL.md")).sort
61
+ end
62
+
63
+ def doctrine_blob
64
+ chapters = Dir.glob(File.join(@skills_dir, "conventions", "references", "*.md")).sort
65
+ return nil if chapters.empty?
66
+
67
+ text = chapters.map { |f| File.read(f) }.join(" ")
68
+ " #{normalize_words(text).join(" ")} "
69
+ end
70
+
71
+ def normalize_words(text)
72
+ text.downcase.gsub("`", "").gsub(/[^a-z0-9\s-]/, " ").split(/\s+/).reject(&:empty?)
73
+ end
74
+
75
+ # Same split as SkillLint's own frontmatter/body divide: `content.split("---", 3)`.
76
+ def body_and_offset(content)
77
+ parts = content.split("---", 3)
78
+ return [content, 0] if parts.length < 3
79
+
80
+ prefix_len = parts[0].length + 3 + parts[1].length + 3
81
+ [parts[2], content[0...prefix_len].count("\n")]
82
+ end
83
+
84
+ # Blank-line-delimited paragraph blocks, so a refusal keyword and its
85
+ # doctrine echo are compared across the whole paragraph, not one line.
86
+ def paragraph_blocks(lines)
87
+ blocks = []
88
+ start = nil
89
+ lines.each_with_index do |line, i|
90
+ if line.strip.empty?
91
+ blocks << { start: start, text: lines[start..(i - 1)].join } if start
92
+ start = nil
93
+ else
94
+ start ||= i
95
+ end
96
+ end
97
+ blocks << { start: start, text: lines[start..].join } if start
98
+ blocks
99
+ end
100
+
101
+ def restated?(block_text, doctrine)
102
+ words = normalize_words(block_text)
103
+ return false if words.length < NGRAM
104
+
105
+ (0..(words.length - NGRAM)).any? do |i|
106
+ doctrine.include?(" #{words[i, NGRAM].join(" ")} ")
107
+ end
108
+ end
109
+
110
+ def check_skill(skill_dir, skill_md, content, doctrine)
111
+ name = File.basename(skill_dir)
112
+ body, offset = body_and_offset(content)
113
+
114
+ paragraph_blocks(body.lines).filter_map do |block|
115
+ next unless block[:text].match?(REFUSAL_KEYWORD_RE)
116
+ next if block[:text].match?(CONVENTIONS_LINK_RE) # links the chapter instead of restating
117
+ next unless restated?(block[:text], doctrine)
118
+
119
+ {
120
+ check: "refusal-restatement", skill: name, file: skill_md, line: offset + block[:start] + 1,
121
+ message: "this paragraph restates a refusal rule word-for-word from " \
122
+ "skills/conventions/references/; link the chapter instead of repeating its text",
123
+ }
124
+ end
125
+ end
126
+ end
127
+
20
128
  def resolve_skills_dir(args)
21
129
  if (i = args.index("--skills-dir"))
22
130
  args[i + 1]
@@ -37,14 +145,15 @@ end
37
145
 
38
146
  dir = File.expand_path(resolve_skills_dir(ARGV))
39
147
  result = SkillLint.new(skills_dir: dir).run
148
+ violations = result.violations + RefusalRestatementCheck.new(dir).run
40
149
 
41
- if result.ok?
150
+ if violations.empty?
42
151
  puts "OK: #{dir}"
43
152
  exit 0
44
153
  end
45
154
 
46
155
  warn "VIOLATIONS: #{dir}"
47
- result.violations.each do |v|
156
+ violations.each do |v|
48
157
  warn "#{v[:check]} #{v[:skill]} #{v[:file]}:#{v[:line].nil? ? "-" : v[:line]} #{v[:message]}"
49
158
  end
50
159
  exit 1
@@ -44,7 +44,7 @@ WORKTREE_FALLBACK_INSTRUCTION =
44
44
  "directory, cd directly to the code worktree path above before editing project code."
45
45
 
46
46
  # Verbatim completion-report contract (intent 74). Kept as one constant so the
47
- # contract doc (skills/auto/references/agent-report-contract.md), the role prompts,
47
+ # contract doc (docs/help/agent-report-contract.md), the role prompts,
48
48
  # and the test assert against the exact same string. SINGLE SOURCE OF TRUTH for the
49
49
  # report wording: the work output is lifecycle artifacts, the final message is a
50
50
  # structured report about them. Both are required and they do not contradict.
@@ -64,7 +64,7 @@ REPORT_CONTRACT =
64
64
  "depends on the discovering session's file-write access. Keep the report " \
65
65
  "prose-stripped: the envelope and payload only, no greeting, no preamble, " \
66
66
  "no end-recap, no restating of the task; reasoning stays in the thinking channel. " \
67
- "See skills/auto/references/agent-report-contract.md for the per-role format."
67
+ "See docs/help/agent-report-contract.md for the per-role format."
68
68
 
69
69
  def parse_args(argv)
70
70
  role = nil
package/scripts/update.rb CHANGED
@@ -231,12 +231,33 @@ class Update < InstallerCore
231
231
  ($stdin.gets&.strip || "").downcase.start_with?("y")
232
232
  end
233
233
 
234
- # Thin npx-exec glue (not unit-tested; the decision above is). Delegates the file-sync to
235
- # the target version's install verb, recording the ledger action as `update`.
236
- def perform_switch(target, agent_flags)
234
+ # Thin npx-exec glue (the decision above is unit-tested). Delegates the file-sync to
235
+ # the target version's install verb, recording the ledger action as `update`. On
236
+ # success, commits the re-synced core files and clears the update-check cache
237
+ # (former update skill, lines 124-125).
238
+ def perform_switch(target, agent_flags, switch_runner: ->(cmd) { system(*cmd) })
237
239
  cmd = ["npx", "#{PKG}@#{target}", "install", "--reinstall", "--ledger-action", "update", *agent_flags]
238
240
  puts " $ #{cmd.join(" ")}"
239
- system(*cmd) ? 0 : 1
241
+ return 1 unless switch_runner.call(cmd)
242
+
243
+ commit_core_files(target)
244
+ clear_update_check_cache
245
+ 0
246
+ end
247
+
248
+ # Intent 372 (former update skill, lines 124-125): `~/.plastic` is its own git
249
+ # repository (install.rb's git_init_if_absent), so a successful update commits the
250
+ # core files it just re-synced. Empty commits are allowed: a same-version repair
251
+ # re-syncs nothing new, and that is still worth a ledger-adjacent commit.
252
+ def commit_core_files(target, runner: ->(cmd) { system(*cmd) })
253
+ runner.call(["git", "-C", plastic_home, "add", "PLASTIC.md", "scripts", "AGENTS.md", "VERSION",
254
+ "versions.json", "deprecations.yml", "config_asks.yml"])
255
+ runner.call(["git", "-C", plastic_home, "commit", "-m", "chore: update Plastic to #{target}",
256
+ "--allow-empty"])
257
+ end
258
+
259
+ def clear_update_check_cache
260
+ FileUtils.rm_f(File.join(plastic_home, ".cache", "update-check.json"))
240
261
  end
241
262
 
242
263
  def show_help
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ # validate-work-graph - deterministic CLI over WorkGraphValidator (intent 334, n4).
6
+ #
7
+ # Checks whether one intent directory's graph.md and nodes/ form a valid work
8
+ # graph: needs targets resolve, node files reconcile with the declared graph,
9
+ # per-kind body sections are present, and (above the trivial bar) a verify
10
+ # node gates two or more work nodes with a failure-mode matrix per work node.
11
+ # Modelled on scripts/validate-intent: errors to stderr, same exit-code shape.
12
+ #
13
+ # Usage:
14
+ # validate-work-graph <intent_dir>
15
+ #
16
+ # Exit codes: 0 (valid), 1 (invalid or unreadable; report on stderr),
17
+ # 2 (usage - no argument given).
18
+
19
+ require_relative "lib/work_graph_validator"
20
+
21
+ intent_dir = ARGV.find { |a| !a.start_with?("--") }
22
+
23
+ if intent_dir.nil?
24
+ warn "usage: validate-work-graph <intent_dir>"
25
+ exit 2
26
+ end
27
+
28
+ dir = File.expand_path(intent_dir)
29
+ result = WorkGraphValidator.validate(dir)
30
+
31
+ if result[:ok]
32
+ puts "OK: #{dir}"
33
+ exit 0
34
+ end
35
+
36
+ warn "INVALID: #{dir}"
37
+ result[:missing].each { |m| warn "missing: #{m}" }
38
+ result[:errors].each { |e| warn e }
39
+ exit 1
@@ -11,11 +11,12 @@
11
11
  #
12
12
  # --base overrides the auto-detected diff base (default: the merge base with the repo's
13
13
  # detected default branch) for repos where detection is ambiguous. --suite is an optional
14
- # caller-supplied command to run (in the repo directory) and fold into the verdict. No
14
+ # caller-supplied command to run (in the repo directory) and merge into the verdict. No
15
15
  # other flags exist.
16
16
  #
17
17
  # Checks, all run every invocation (the fourth only when --suite is given):
18
- # 1. doctor - Doctor#run_intent_check(id, store: scope), fail-open on a crash
18
+ # 1. doctor - Doctor#run_intent_check(id, store: scope), fail-open on a crash; the doctor
19
+ # scan includes the intent_ticks_lag warning (intent 329)
19
20
  # 2. em-dash - added lines only of `git diff <base>...HEAD`, never the whole tree
20
21
  # 3. diffstat - `git diff --stat <base>...HEAD`, never a failure on its own
21
22
  # 4. suite - the supplied --suite command, run with RUBYOPT cleared
@@ -16,6 +16,7 @@
16
16
  #
17
17
  # Exit codes: 0 done; 2 usage error.
18
18
 
19
+ require_relative "lib/store_layout"
19
20
  require_relative "lib/session_ledger"
20
21
  require_relative "lib/handoff"
21
22
 
@@ -48,7 +49,7 @@ usage_abort("--trigger is required (#{Handoff::TRIGGERS.join(', ')})") unless op
48
49
  usage_abort("--trigger must be one of #{Handoff::TRIGGERS.join(', ')}") unless Handoff::TRIGGERS.include?(opts[:trigger])
49
50
 
50
51
  plastic_home = expand(ENV.fetch("PLASTIC_HOME", "~/.plastic"))
51
- store = opts[:store] ? expand(opts[:store]) : File.join(plastic_home, "store")
52
+ store = opts[:store] ? expand(opts[:store]) : Plastic::StoreLayout.global_store(plastic_home)
52
53
  templates = opts[:templates] ? expand(opts[:templates]) : File.expand_path("../templates", __dir__)
53
54
  usage_abort("templates dir not found: #{templates}") unless Dir.exist?(templates)
54
55
 
@@ -42,7 +42,7 @@ Active/Future/Completed placement is managed in INDEX.md, not in frontmatter.
42
42
 
43
43
  ## Creating Tactical Intents
44
44
 
45
- Create through the `plastic-intent-creating` skill, which scaffolds with one call:
45
+ Create through the `plastic intent new` command, which scaffolds with one call:
46
46
  `ruby ~/.plastic/scripts/new-intent --store .plastic/store --intent "<one-line>" --slug <slug> [--sources <governing-id>]`.
47
47
  It allocates the Folgezettel ID, creates `.plastic/store/ID--slug/ID--slug.md` born
48
48
  complete, and wires the links. Never hand-author the files: `new-intent` validates the
@@ -54,14 +54,14 @@ Plastic has its own lifecycle skills. When a Plastic skill exists for the curren
54
54
 
55
55
  | Phase | Skill | Produces |
56
56
  |-------|-------|----------|
57
- | What | `plastic-intent-creating` | Intent file |
58
- | Why | `plastic-intent-speccing` | Rulings as insights, `resources/*.md`, `spec.md` |
59
- | How | `plastic-intent-speccing` | `actions/`, `plan.md`, `checklist.md` |
60
- | Exec | `plastic-intent-executing` | Code + `outcome.md` |
61
- | Done | `plastic-intent-ending` | Lifecycle transition |
57
+ | What | `plastic intent new` | Intent file |
58
+ | Why | `plastic intent spec` | Rulings as insights, `resources/*.md`, `spec.md` |
59
+ | How | `plastic intent spec` | `actions/`, `plan.md`, `checklist.md` |
60
+ | Exec | `plastic intent step` | Code + `outcome.md` |
61
+ | End | `plastic intent end` | Lifecycle transition |
62
62
 
63
63
  **Artifact convention:** ALL lifecycle artifacts go to the active intent directory (`store/{id}--{slug}/`). Never write specs to `docs/superpowers/specs/` or plans to `docs/superpowers/plans/`.
64
64
 
65
- ## When You're Done
65
+ ## When the Project Wraps
66
66
 
67
67
  When this project satisfies the governing intent's goal, report back. The orchestrator will complete the strategic intent.
@@ -2,11 +2,11 @@ version: 3
2
2
  project_roots:
3
3
  - ~/.plastic/projects
4
4
  stale_threshold_days: 3
5
- # When to compact. Absolute token counts for a 1M window (35 and 50 percent), not
5
+ # When to compact. Absolute token counts for a 1M window (15 and 25 percent), not
6
6
  # percentages: models are reliable only to roughly 50 to 65 percent of advertised
7
7
  # context, so a percentage that is right at 200k floats to an untested size at 1M.
8
- context_offer_tokens: 350000
9
- context_insist_tokens: 500000
8
+ context_offer_tokens: 150000
9
+ context_insist_tokens: 250000
10
10
  execution_mode: subagent-driven
11
11
  hash_length: 6
12
12
  hash_algorithm: sha256-base36
@@ -34,18 +34,25 @@ architect:
34
34
  # plastic-enforcer: opus
35
35
  # codex:
36
36
  # plastic-executor: gpt-5.6-terra
37
+ # efforts:
38
+ # claude:
39
+ # plastic-executor: medium
40
+ # codex:
41
+ # plastic-executor: medium
42
+ # Every shipped agent defaults to medium reasoning effort on both harnesses.
43
+ # An agents.efforts.<harness>.<agent> entry is an explicit per-agent override.
37
44
 
38
- # The advisor (intent 185): two consultation agents, plastic-advisor (the real
39
- # advisor, expensive, model fable by default) and plastic-faux-advisor (the
40
- # cheaper imitation, model opus by default, carrying the same reasoning
41
- # discipline inline). advisor.enabled defaults to enabled; missing or
45
+ # The advisors: Primary Advisor and Secondary Advisor. Both use Fable on Claude
46
+ # Code and gpt-6-astra on Codex. Primary uses medium effort; Secondary uses high.
47
+ # advisor.enabled defaults to enabled; missing or
42
48
  # unreadable counts as enabled (fail-open). The claude.default value is an
43
49
  # AGENT NAME, never a model name, so it can point at
44
50
  # a locally registered agent instead. Set at install time via --no-advisor /
45
51
  # --advisor, or uncomment here directly. Each agent's actual model is a plain
46
- # agents.models.claude.<name> override, same mechanism as any other agent.
52
+ # agents.models.claude.<name> override, same mechanism as any other agent. Codex
53
+ # generates both advisors with their role-specific effort.
47
54
  # advisor:
48
55
  # enabled: false # skip installing both advisor agents and the
49
56
  # # agent-advisor skill entirely
50
57
  # claude:
51
- # default: plastic-advisor # which agent the advisor skill routes to
58
+ # default: plastic-primary-advisor # which agent the advisor skill routes to
@@ -0,0 +1,22 @@
1
+ ## ▶ {{scope}} · dashboard
2
+
3
+ | | | |
4
+ | --- | --- | --- |
5
+ | **Active** | {{active}} | intents |
6
+ | **In delivery** | {{in_delivery}} | with a fresh lock |
7
+ | **Delivered** | {{delivered}} | in the last 7 days |
8
+ | **Roadmap** | {{roadmap}} | frontier batch |
9
+ | **Sessions** | {{sessions}} | alive |
10
+ | **Changed** | {{changed}} | newest savepoint |
11
+
12
+ **Where we are**
13
+
14
+ | Graph ID | Intent | Stage | Progress | Lead |
15
+ | --- | --- | --- | --- | --- |
16
+ {{where_we_are.rows}}
17
+
18
+ **Where we go next**
19
+
20
+ | Rank | Graph ID | Intent | Reason |
21
+ | --- | --- | --- | --- |
22
+ {{where_we_go_next.rows}}
@@ -0,0 +1,21 @@
1
+ <!-- Doctor's display self-test fixture (intent 331e). Replayed through the
2
+ installed MessageDisplay hook by `display_hook_paints` to prove painting
3
+ still works; this is NOT a report-screen scaffold (no {{...}} mustache
4
+ placeholders) and ships no data of its own. -->
5
+
6
+ ## ▶ 331e · Doctor display check
7
+
8
+ | | | |
9
+ | --- | --- | --- |
10
+ | **Store** | project:plastic | the plastic project store |
11
+ | **Status** | Active | listed under ## Active in INDEX.md |
12
+ | **Stage** | Exec | What, Why, How, Exec delivered; the work is open |
13
+ | **Progress** | ██████████░░░░░░░░░░ 3 / 6 | 3 steps open |
14
+
15
+ **Steps**
16
+
17
+ | Step | Status | What |
18
+ | --- | --- | --- |
19
+ | S1 | done | Tests red |
20
+ | S2 | done | check_display_registration in doctor_core.rb |
21
+ | S3 | open | The three full-run checks in doctor.rb |
@@ -0,0 +1,16 @@
1
+ # Graph: <intent name>
2
+
3
+ ## Goal
4
+ <What this intent's graph delivers once every node reaches done.>
5
+
6
+ ## Decisions
7
+ - D1 <first ruling made while building this graph>
8
+
9
+ ## Graph
10
+ Edges, `needs` only; the head needs the tail done. The literal target `nothing` declares a root.
11
+ - n1 needs nothing
12
+
13
+ ## Status
14
+ | Node | State | Detail |
15
+ | --- | --- | --- |
16
+ | n1 | planned | |
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Active
4
4
  <!-- Line shape: `- [ID — Title](path)`. Writes emit the em-dash (U+2014) between
5
- id and title; readers (Bridge.index_entry_match) accept the em-dash or a plain
5
+ id and title; readers (IndexEntry.match) accept the em-dash or a plain
6
6
  hyphen, so either form parses (see https://github.com/zalom/plastic/blob/main/docs/internals.md). -->
7
7
  (no active intents)
8
8
 
@@ -12,6 +12,6 @@
12
12
 
13
13
  **Steps**
14
14
 
15
- | Step | Status | What |
15
+ | Step | Status | Detail |
16
16
  | --- | --- | --- |
17
17
  {{steps.rows}}
@@ -0,0 +1,11 @@
1
+ ---
2
+ node: d1
3
+ kind: decision
4
+ files: []
5
+ budget: 20000
6
+ ---
7
+ # d1 - <the decision to make>
8
+
9
+ ## Question
10
+ <The question needing an owner ruling, framed so a yes/no answer or a pick
11
+ from a short list settles it.>
@@ -0,0 +1,13 @@
1
+ ---
2
+ node: r1
3
+ kind: research
4
+ files: []
5
+ budget: 60000
6
+ # Optional. When present, use one relative Markdown path under resources/.
7
+ # report: resources/report--topic.md
8
+ ---
9
+ # r1 - <what to find out>
10
+
11
+ ## Deposit
12
+ <Where the finding lands: declare report: above for a resources/ Markdown file,
13
+ or name an artifact URL or a ruling recorded in the intent's ## Decisions.>
@@ -0,0 +1,13 @@
1
+ ---
2
+ node: v1
3
+ kind: verify
4
+ files: []
5
+ budget: 40000
6
+ ---
7
+ # v1 - <what this node verifies>
8
+
9
+ <What this node checks, and why it gates the work nodes it needs.>
10
+
11
+ ## Criteria
12
+ - <acceptance criterion one>
13
+ - <acceptance criterion two>
@@ -0,0 +1,22 @@
1
+ ---
2
+ node: n1
3
+ kind: work
4
+ files: [path/to/file.rb, test/path_to_file_test.rb]
5
+ budget: 100000
6
+ ---
7
+ # n1 - <one-line description of what this node builds>
8
+
9
+ <Why this node exists and what it changes, in a sentence or two.>
10
+
11
+ ## n1 failure-mode matrix
12
+ | Operation | Failure mode | Test |
13
+ | --- | --- | --- |
14
+ | <operation> | <what goes wrong without this code, and its consequence> | `some_test#test_name` |
15
+
16
+ ## Steps
17
+ 1. Red: the matrix's tests above, committed before any code.
18
+ 2. Write the code that makes them pass.
19
+ 3. Green, then the whole suite at its baseline.
20
+
21
+ ## Proven by
22
+ (filled at close from the ledger: commit, suite counts, review verdict)
@@ -9,9 +9,14 @@ disposition: delivered|abandoned
9
9
  ## Delivered
10
10
  <!-- One row per thing delivered, in plain wording a reader recognizes, not
11
11
  an implementation summary; the technical detail belongs in ## Summary. Each
12
- row's label must appear as a standalone token in an actions/*.md heading
13
- (for example "### S1 - ..." proves row S1): that heading's matrix rows become
14
- the row's Proven-by cell on the delivered screen (intent 317 D19, 317a). -->
12
+ row's label must appear as a standalone token in an actions/*.md OR
13
+ nodes/*.md heading that owns the matrix table (for example "### S1 - ..."
14
+ with a table beneath it proves row S1, or "## n1 failure-mode matrix" proves
15
+ row n1); that heading's matrix rows become the row's Proven-by cell on the
16
+ delivered screen (intent 317 D19, 317a, 322 D1r, 334 D10r). Readers resolve
17
+ actions/ first, then nodes/ (334 D15r). A label with no owning heading falls
18
+ back to a matrix row cell that carries it, when one under a heading named
19
+ "matrix" exists (322 D3r). -->
15
20
  | Row | What |
16
21
  | --- | --- |
17
22
  | S1 | ... |
@@ -8,5 +8,5 @@ release:
8
8
  # mode: direct # direct | pull_request
9
9
  # base: main # defaults to origin/HEAD, then main, then master
10
10
  # branch_template: "session/{{day}}" # {{day}}, {{ticket}}, {{slug}} tokens
11
- # ticket_source: intent_id # intent_id (the session pointer's intent id, else the day id)
11
+ # ticket_source: intent_id # intent_id (the delivering intent's id from its delivery lock, else the day id)
12
12
  # workspace: checkout # checkout | worktree (worktree applies to direct mode only)
@@ -0,0 +1,10 @@
1
+ body { max-width: 46rem; margin: 2rem auto; padding: 0 1rem; font: 16px/1.6 system-ui, sans-serif; color: #1f2933; background: #f4f5f7; }
2
+ h1, h2, h3 { line-height: 1.25; }
3
+ table { border-collapse: collapse; display: block; overflow-x: auto; }
4
+ th, td { border: 1px solid #9aa5b1; padding: 0.3rem 0.6rem; text-align: left; }
5
+ pre { background: #e4e7eb; padding: 0.8rem; overflow-x: auto; }
6
+ code { font-family: ui-monospace, monospace; }
7
+ @media (prefers-color-scheme: dark) {
8
+ body { color: #e4e7eb; background: #1f2933; }
9
+ pre { background: #323f4b; }
10
+ }
@@ -0,0 +1,15 @@
1
+ ## ▶ {{id}} · {{name}} · plan
2
+
3
+ | | | |
4
+ | --- | --- | --- |
5
+ {{fields.rows}}
6
+
7
+ **Steps**
8
+
9
+ | Step | Action | Detail |
10
+ | --- | --- | --- |
11
+ {{steps.rows}}
12
+
13
+ **Risks**
14
+
15
+ {{risks.block}}
@@ -0,0 +1,10 @@
1
+ ## ✔ {{slug}} · roadmap · delivered
2
+ {{meta}}
3
+
4
+ **Delivered**
5
+
6
+ {{delivered.table}}
7
+
8
+ **Log**
9
+
10
+ {{log.table}}
@@ -0,0 +1,9 @@
1
+ ## ▶ {{slug}} · roadmap · plan
2
+
3
+ | | | |
4
+ | --- | --- | --- |
5
+ {{fields.rows}}
6
+
7
+ **Batches**
8
+
9
+ {{entries.table}}{{tree}}
@@ -0,0 +1,9 @@
1
+ ## ▶ {{slug}} · roadmap
2
+
3
+ | | | |
4
+ | --- | --- | --- |
5
+ {{fields.rows}}
6
+
7
+ **Batches**
8
+
9
+ {{entries.table}}
@@ -6,6 +6,6 @@
6
6
 
7
7
  **Steps**
8
8
 
9
- | Step | Status | What |
9
+ | Step | Status | Detail |
10
10
  | --- | --- | --- |
11
11
  {{steps.rows}}