@pennyfarthing/core 8.0.4 → 9.0.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 (141) hide show
  1. package/README.md +3 -3
  2. package/package.json +3 -3
  3. package/pennyfarthing-dist/agents/README.md +1 -1
  4. package/pennyfarthing-dist/agents/dev.md +1 -1
  5. package/pennyfarthing-dist/agents/handoff.md +1 -1
  6. package/pennyfarthing-dist/agents/reviewer-preflight.md +1 -1
  7. package/pennyfarthing-dist/agents/reviewer.md +21 -4
  8. package/pennyfarthing-dist/agents/sm-setup.md +3 -3
  9. package/pennyfarthing-dist/agents/sm.md +11 -1
  10. package/pennyfarthing-dist/agents/tea.md +1 -1
  11. package/pennyfarthing-dist/agents/testing-runner.md +3 -3
  12. package/pennyfarthing-dist/commands/architect.md +3 -1
  13. package/pennyfarthing-dist/commands/continue-session.md +2 -2
  14. package/pennyfarthing-dist/commands/dev.md +3 -1
  15. package/pennyfarthing-dist/commands/devops.md +3 -1
  16. package/pennyfarthing-dist/commands/health-check.md +3 -1
  17. package/pennyfarthing-dist/commands/new-work.md +23 -0
  18. package/pennyfarthing-dist/commands/orchestrator.md +3 -1
  19. package/pennyfarthing-dist/commands/parallel-work.md +6 -4
  20. package/pennyfarthing-dist/commands/pm.md +3 -1
  21. package/pennyfarthing-dist/commands/prime.md +18 -22
  22. package/pennyfarthing-dist/commands/reviewer.md +3 -1
  23. package/pennyfarthing-dist/commands/set-theme.md +1 -1
  24. package/pennyfarthing-dist/commands/sm.md +3 -1
  25. package/pennyfarthing-dist/commands/sprint.md +13 -4
  26. package/pennyfarthing-dist/commands/tea.md +3 -1
  27. package/pennyfarthing-dist/commands/tech-writer.md +3 -1
  28. package/pennyfarthing-dist/commands/ux-designer.md +3 -1
  29. package/pennyfarthing-dist/commands/work.md +4 -2
  30. package/pennyfarthing-dist/guides/agent-behavior.md +36 -257
  31. package/pennyfarthing-dist/personas/themes/rome.yaml +11 -11
  32. package/pennyfarthing-dist/scripts/core/agent-session.sh +7 -0
  33. package/pennyfarthing-dist/scripts/core/check-context.sh +140 -226
  34. package/pennyfarthing-dist/scripts/core/handoff-marker.sh +13 -2
  35. package/pennyfarthing-dist/scripts/git/worktree-manager.sh +4 -1
  36. package/pennyfarthing-dist/scripts/health/drift-detection.sh +1 -7
  37. package/pennyfarthing-dist/scripts/hooks/post-merge.sh +4 -11
  38. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +3 -8
  39. package/pennyfarthing-dist/scripts/hooks/pre-push.sh +3 -3
  40. package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +1 -7
  41. package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +2 -8
  42. package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +2 -8
  43. package/pennyfarthing-dist/scripts/lib/find-root.sh +17 -45
  44. package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +1 -7
  45. package/pennyfarthing-dist/scripts/sprint/archive-story.sh +2 -8
  46. package/pennyfarthing-dist/scripts/sprint/available-stories.sh +2 -8
  47. package/pennyfarthing-dist/scripts/sprint/check-story.sh +2 -8
  48. package/pennyfarthing-dist/scripts/sprint/get-epic-field.sh +2 -8
  49. package/pennyfarthing-dist/scripts/sprint/get-story-field.sh +2 -8
  50. package/pennyfarthing-dist/scripts/sprint/list-future.sh +2 -8
  51. package/pennyfarthing-dist/scripts/sprint/new-sprint.sh +2 -8
  52. package/pennyfarthing-dist/scripts/sprint/promote-epic.sh +2 -8
  53. package/pennyfarthing-dist/scripts/sprint/sprint-info.sh +2 -8
  54. package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +2 -1
  55. package/pennyfarthing-dist/scripts/workflow/finish-story.sh +4 -9
  56. package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +2 -8
  57. package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +2 -8
  58. package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +1 -7
  59. package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +2 -8
  60. package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +2 -8
  61. package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +2 -8
  62. package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +2 -8
  63. package/pennyfarthing-dist/skills/dev-patterns/SKILL.md +1 -1
  64. package/pennyfarthing-dist/skills/jira/SKILL.md +48 -24
  65. package/pennyfarthing-dist/skills/sprint/scripts/sync-epic-jira.sh +7 -0
  66. package/pennyfarthing-dist/skills/sprint/skill.md +30 -30
  67. package/pennyfarthing-dist/workflows/patch.yaml +68 -0
  68. package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
  69. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  70. package/pennyfarthing_scripts/cli.py +168 -0
  71. package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
  72. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  73. package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
  74. package/pennyfarthing_scripts/context.py +414 -0
  75. package/pennyfarthing_scripts/patch_mode.py +449 -0
  76. package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
  77. package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
  78. package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
  79. package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
  80. package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
  81. package/pennyfarthing_scripts/prime/__pycache__/session.cpython-314.pyc +0 -0
  82. package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
  83. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  84. package/pennyfarthing_scripts/prime/cli.py +209 -1
  85. package/pennyfarthing_scripts/prime/models.py +9 -0
  86. package/pennyfarthing_scripts/prime/persona.py +41 -0
  87. package/pennyfarthing_scripts/prime/tiers.py +201 -0
  88. package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
  89. package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
  90. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  91. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  92. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  93. package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
  94. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
  95. package/pennyfarthing_scripts/sprint/cli.py +144 -84
  96. package/pennyfarthing_scripts/tests/test_patch_mode.py +830 -0
  97. package/pennyfarthing_scripts/tests/test_tiers.py +1090 -0
  98. package/pennyfarthing_scripts/tests/test_token_counting.py +559 -0
  99. package/pennyfarthing_scripts/tests/test_workflow_check.py +341 -0
  100. package/pennyfarthing_scripts/workflow.py +104 -0
  101. package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
  102. package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  103. package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
  104. package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
  105. package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
  106. package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
  107. package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
  108. package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
  109. package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
  110. package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
  111. package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
  112. package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
  113. package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
  114. package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
  115. package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
  116. package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
  117. package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
  118. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  119. package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
  120. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
  121. package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
  122. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
  123. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
  124. package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
  125. package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
  126. package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
  127. package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
  128. package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
  129. package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
  130. package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
  131. package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
  132. package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
  133. package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
  134. package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
  135. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  136. package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
  137. package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
  138. package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
  139. package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
  140. package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
  141. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
@@ -21,7 +21,7 @@ Never manually edit `sprint/current-sprint.yaml`. Use the scripts below for dete
21
21
  Show current sprint status with story counts and points.
22
22
 
23
23
  <run>
24
- .pennyfarthing/scripts sprint/sprint-status.sh [filter]
24
+ .pennyfarthing/scripts/sprint/sprint-status.sh [filter]
25
25
  </run>
26
26
 
27
27
  <args>
@@ -31,10 +31,10 @@ Show current sprint status with story counts and points.
31
31
  </args>
32
32
 
33
33
  <example>
34
- .pennyfarthing/scripts sprint/sprint-status.sh # All stories
35
- .pennyfarthing/scripts sprint/sprint-status.sh todo # Backlog only
36
- .pennyfarthing/scripts sprint/sprint-status.sh in-progress # WIP only
37
- .pennyfarthing/scripts sprint/sprint-status.sh done # Completed only
34
+ .pennyfarthing/scripts/sprint/sprint-status.sh # All stories
35
+ .pennyfarthing/scripts/sprint/sprint-status.sh todo # Backlog only
36
+ .pennyfarthing/scripts/sprint/sprint-status.sh in-progress # WIP only
37
+ .pennyfarthing/scripts/sprint/sprint-status.sh done # Completed only
38
38
  </example>
39
39
 
40
40
  <output>
@@ -49,7 +49,7 @@ When filtered, only shows epics with matching stories.
49
49
  Show available stories grouped by epic with Jira context.
50
50
 
51
51
  <run>
52
- .pennyfarthing/scripts sprint/available-stories.sh
52
+ .pennyfarthing/scripts/sprint/available-stories.sh
53
53
  </run>
54
54
 
55
55
  <output>
@@ -82,7 +82,7 @@ Shows backlog, user selects story, then proceeds to setup.
82
82
  #### With story ID: Direct start
83
83
 
84
84
  <run>
85
- .pennyfarthing/scripts sprint/check-story.sh <story-id>
85
+ .pennyfarthing/scripts/sprint/check-story.sh <story-id>
86
86
  </run>
87
87
 
88
88
  <args>
@@ -97,14 +97,14 @@ Shows backlog, user selects story, then proceeds to setup.
97
97
  </output>
98
98
 
99
99
  <example>
100
- .pennyfarthing/scripts sprint/check-story.sh MSSCI-12038
100
+ .pennyfarthing/scripts/sprint/check-story.sh MSSCI-12038
101
101
  # Returns: {"type": "story", "available": true, "title": "...", ...}
102
102
  </example>
103
103
 
104
104
  #### With epic ID: Start first available story in epic
105
105
 
106
106
  <run>
107
- .pennyfarthing/scripts sprint/check-story.sh <epic-id>
107
+ .pennyfarthing/scripts/sprint/check-story.sh <epic-id>
108
108
  </run>
109
109
 
110
110
  <output>
@@ -113,14 +113,14 @@ Action: Automatically start work on `first_story` if available.
113
113
  </output>
114
114
 
115
115
  <example>
116
- .pennyfarthing/scripts sprint/check-story.sh MSSCI-11952
116
+ .pennyfarthing/scripts/sprint/check-story.sh MSSCI-11952
117
117
  # Returns: {"type": "epic", "first_story": {"id": "MSSCI-11954", ...}, ...}
118
118
  </example>
119
119
 
120
120
  #### With `next`: Auto-select highest priority story
121
121
 
122
122
  <run>
123
- .pennyfarthing/scripts sprint/check-story.sh next
123
+ .pennyfarthing/scripts/sprint/check-story.sh next
124
124
  </run>
125
125
 
126
126
  <output>
@@ -129,7 +129,7 @@ Action: Automatically start work on returned story.
129
129
  </output>
130
130
 
131
131
  <example>
132
- .pennyfarthing/scripts sprint/check-story.sh next
132
+ .pennyfarthing/scripts/sprint/check-story.sh next
133
133
  # Returns: {"type": "next", "story": {"id": "MSSCI-11950", "priority": "P1", ...}}
134
134
  </example>
135
135
 
@@ -140,7 +140,7 @@ Action: Automatically start work on returned story.
140
140
  Archive a completed story to the sprint archive file.
141
141
 
142
142
  <run>
143
- .pennyfarthing/scripts sprint/archive-story.sh <story-id> [pr-number] [--apply]
143
+ .pennyfarthing/scripts/sprint/archive-story.sh <story-id> [pr-number] [--apply]
144
144
  </run>
145
145
 
146
146
  <args>
@@ -153,10 +153,10 @@ Archive a completed story to the sprint archive file.
153
153
 
154
154
  <example>
155
155
  # Archive only (manual removal needed)
156
- .pennyfarthing/scripts sprint/archive-story.sh 35-2 368
156
+ .pennyfarthing/scripts/sprint/archive-story.sh 35-2 368
157
157
 
158
158
  # Archive and remove atomically (recommended)
159
- .pennyfarthing/scripts sprint/archive-story.sh 35-2 368 --apply
159
+ .pennyfarthing/scripts/sprint/archive-story.sh 35-2 368 --apply
160
160
  </example>
161
161
 
162
162
  <output>
@@ -173,7 +173,7 @@ Archive a completed story to the sprint archive file.
173
173
  Initialize a new sprint from template.
174
174
 
175
175
  <run>
176
- .pennyfarthing/scripts sprint/new-sprint.sh <yyww> <jira-id> <start> <end> "<goal>"
176
+ .pennyfarthing/scripts/sprint/new-sprint.sh <yyww> <jira-id> <start> <end> "<goal>"
177
177
  </run>
178
178
 
179
179
  <args>
@@ -187,7 +187,7 @@ Initialize a new sprint from template.
187
187
  </args>
188
188
 
189
189
  <example>
190
- .pennyfarthing/scripts sprint/new-sprint.sh 2605 277 2026-02-03 2026-02-16 "Polish and stabilization"
190
+ .pennyfarthing/scripts/sprint/new-sprint.sh 2605 277 2026-02-03 2026-02-16 "Polish and stabilization"
191
191
  </example>
192
192
 
193
193
  <output>
@@ -205,7 +205,7 @@ Warning: Prompts for confirmation if current sprint is still active.
205
205
  Show future work initiatives and epics available for promotion.
206
206
 
207
207
  <run>
208
- .pennyfarthing/scripts sprint/list-future.sh [--epic EPIC_ID]
208
+ .pennyfarthing/scripts/sprint/list-future.sh [--epic EPIC_ID]
209
209
  </run>
210
210
 
211
211
  <args>
@@ -229,10 +229,10 @@ With `--epic`:
229
229
 
230
230
  <example>
231
231
  # Show all future work
232
- .pennyfarthing/scripts sprint/list-future.sh
232
+ .pennyfarthing/scripts/sprint/list-future.sh
233
233
 
234
234
  # Show details for specific epic
235
- .pennyfarthing/scripts sprint/list-future.sh --epic epic-55
235
+ .pennyfarthing/scripts/sprint/list-future.sh --epic epic-55
236
236
  </example>
237
237
 
238
238
  ---
@@ -242,7 +242,7 @@ With `--epic`:
242
242
  Move an epic from `future.yaml` to `current-sprint.yaml`.
243
243
 
244
244
  <run>
245
- .pennyfarthing/scripts sprint/promote-epic.sh <epic-id>
245
+ .pennyfarthing/scripts/sprint/promote-epic.sh <epic-id>
246
246
  </run>
247
247
 
248
248
  <args>
@@ -252,7 +252,7 @@ Move an epic from `future.yaml` to `current-sprint.yaml`.
252
252
  </args>
253
253
 
254
254
  <example>
255
- .pennyfarthing/scripts sprint/promote-epic.sh epic-41
255
+ .pennyfarthing/scripts/sprint/promote-epic.sh epic-41
256
256
  </example>
257
257
 
258
258
  <output>
@@ -278,7 +278,7 @@ These scripts read sprint YAML without modifying it. Use these instead of direct
278
278
  ### Get Story Field
279
279
 
280
280
  <run>
281
- .pennyfarthing/scripts sprint/get-story-field.sh <story-id> <field>
281
+ .pennyfarthing/scripts/sprint/get-story-field.sh <story-id> <field>
282
282
  </run>
283
283
 
284
284
  <args>
@@ -289,9 +289,9 @@ These scripts read sprint YAML without modifying it. Use these instead of direct
289
289
  </args>
290
290
 
291
291
  <example>
292
- .pennyfarthing/scripts sprint/get-story-field.sh 35-2 workflow # Returns: tdd
293
- .pennyfarthing/scripts sprint/get-story-field.sh 35-2 jira # Returns: MSSCI-12345
294
- .pennyfarthing/scripts sprint/get-story-field.sh 35-2 status # Returns: in_progress
292
+ .pennyfarthing/scripts/sprint/get-story-field.sh 35-2 workflow # Returns: tdd
293
+ .pennyfarthing/scripts/sprint/get-story-field.sh 35-2 jira # Returns: MSSCI-12345
294
+ .pennyfarthing/scripts/sprint/get-story-field.sh 35-2 status # Returns: in_progress
295
295
  </example>
296
296
 
297
297
  <output>
@@ -303,7 +303,7 @@ Field value or "null" if not found. Common fields: `workflow`, `status`, `jira`,
303
303
  ### Get Epic Field
304
304
 
305
305
  <run>
306
- .pennyfarthing/scripts sprint/get-epic-field.sh <epic-id> <field>
306
+ .pennyfarthing/scripts/sprint/get-epic-field.sh <epic-id> <field>
307
307
  </run>
308
308
 
309
309
  <args>
@@ -314,8 +314,8 @@ Field value or "null" if not found. Common fields: `workflow`, `status`, `jira`,
314
314
  </args>
315
315
 
316
316
  <example>
317
- .pennyfarthing/scripts sprint/get-epic-field.sh epic-35 jira # Returns: MSSCI-11234
318
- .pennyfarthing/scripts sprint/get-epic-field.sh 35 title # Returns: Epic title
317
+ .pennyfarthing/scripts/sprint/get-epic-field.sh epic-35 jira # Returns: MSSCI-11234
318
+ .pennyfarthing/scripts/sprint/get-epic-field.sh 35 title # Returns: Epic title
319
319
  </example>
320
320
 
321
321
  <output>
@@ -347,7 +347,7 @@ When `/sprint work` (or `/new-work`) starts a story:
347
347
  <agent-activation>
348
348
  Load SM persona first:
349
349
  ```bash
350
- d="$PWD"; while [[ ! -d "$d/.claude" ]] && [[ "$d" != "/" ]]; do d="$(dirname "$d")"; done; "$d/.pennyfarthing/scripts" core/agent-session.sh start "sm"
350
+ d="$PWD"; while [[ ! -d "$d/.claude" ]] && [[ "$d" != "/" ]]; do d="$(dirname "$d")"; done; "$d/.pennyfarthing/scripts/core/agent-session.sh" start "sm"
351
351
  ```
352
352
  </agent-activation>
353
353
 
@@ -0,0 +1,68 @@
1
+ # Patch Mode Workflow - Interrupt-Driven Bug Fix
2
+ # For quick fixes during active story work
3
+ #
4
+ # Story: 74-1
5
+ # Epic: epic-74 (Patch Mode Workflow)
6
+ #
7
+ # Flow: Dev only (no TEA, no review)
8
+ # Use for: Blocking bugs, script errors, path fixes, urgent UI fixes
9
+ #
10
+ # Key difference from trivial:
11
+ # - Branches from FEATURE branch, not develop
12
+ # - Merges back to FEATURE branch
13
+ # - Preserves and restores workflow state
14
+ # - Supports nested patches (stack-based)
15
+
16
+ workflow:
17
+ name: patch
18
+ description: Interrupt-driven bug fix during active story work
19
+ version: "1.0.0"
20
+
21
+ # Patch mode is NOT a full workflow - it's an interrupt
22
+ # It doesn't have phases in the traditional sense
23
+ type: interrupt
24
+
25
+ phases:
26
+ - name: fix
27
+ agent: dev
28
+ description: Fix the blocking issue
29
+ output: [fix_commit]
30
+ gate:
31
+ type: manual
32
+ condition: Fix verified working
33
+
34
+ # Branch naming
35
+ branch:
36
+ prefix: "patch/"
37
+ format: "{prefix}{description}-{timestamp}"
38
+
39
+ # Commit format
40
+ commit:
41
+ format: "fix(patch): {description} [from:{story_id}]"
42
+ coauthor: true
43
+
44
+ # State management
45
+ state:
46
+ file: ".session/patch-stack.yaml"
47
+ preserved_fields:
48
+ - story_id
49
+ - workflow
50
+ - phase
51
+ - agent
52
+ - feature_branch
53
+
54
+ # Integration
55
+ tirepump:
56
+ auto_restore: true
57
+ handoff_on_complete: true
58
+
59
+ triggers:
60
+ # Manual triggers
61
+ commands:
62
+ - "/patch"
63
+ - "/fix-blocker"
64
+ # Automatic triggers (future)
65
+ # error_patterns:
66
+ # - "No such file or directory"
67
+ # - "ModuleNotFoundError"
68
+ # - "command not found"
@@ -0,0 +1,168 @@
1
+ """
2
+ Pennyfarthing CLI - Command line interface for agent orchestration.
3
+
4
+ Usage:
5
+ python -m pennyfarthing_scripts.cli [OPTIONS] COMMAND [ARGS]...
6
+ pf [OPTIONS] COMMAND [ARGS]...
7
+
8
+ This module uses lazy loading to keep startup time under 200ms.
9
+ Heavy imports (httpx, workflow modules) are deferred until needed.
10
+ """
11
+
12
+ import click
13
+
14
+ # Get version from package - this is a fast import
15
+ from pennyfarthing_scripts import __version__
16
+
17
+
18
+ @click.group()
19
+ @click.version_option(version=__version__, prog_name="pf")
20
+ def cli():
21
+ """Pennyfarthing CLI - Agent orchestration utilities.
22
+
23
+ Commands are organized into groups:
24
+
25
+ \b
26
+ workflow - Workflow state and phase management
27
+ agent - Agent session management
28
+ sprint - Sprint status and story operations
29
+ """
30
+ pass
31
+
32
+
33
+ # Import and register sprint group (lazy registration preserves startup time)
34
+ from pennyfarthing_scripts.sprint.cli import sprint
35
+
36
+ cli.add_command(sprint)
37
+
38
+
39
+ @cli.group()
40
+ def agent():
41
+ """Agent session management.
42
+
43
+ \b
44
+ Commands:
45
+ start - Start an agent session with context
46
+ """
47
+ pass
48
+
49
+
50
+ @agent.command("start")
51
+ @click.argument("name")
52
+ @click.option("--session-id", help="Use explicit session ID")
53
+ @click.option("--no-persona", is_flag=True, help="Skip persona loading")
54
+ @click.option("--json", "json_output", is_flag=True, help="Output as JSON")
55
+ @click.option("--minimal", is_flag=True, help="Skip all context (fastest)")
56
+ @click.option("--full", is_flag=True, help="Include domain docs")
57
+ def agent_start(
58
+ name: str,
59
+ session_id: str | None,
60
+ no_persona: bool,
61
+ json_output: bool,
62
+ minimal: bool,
63
+ full: bool,
64
+ ):
65
+ """Start an agent session with full context.
66
+
67
+ Loads agent definition, persona, behavior guide, sprint context,
68
+ session context, and sidecar memory.
69
+
70
+ \b
71
+ Arguments:
72
+ NAME - Agent name (sm, tea, dev, reviewer, etc.)
73
+ """
74
+ # Lazy import - only load when command is actually invoked
75
+ from pennyfarthing_scripts.prime import prime
76
+
77
+ exit_code = prime(
78
+ agent_name=name,
79
+ session_id=session_id,
80
+ no_persona=no_persona,
81
+ json_output=json_output,
82
+ minimal=minimal,
83
+ full=full,
84
+ )
85
+ raise SystemExit(exit_code)
86
+
87
+
88
+ @cli.group()
89
+ def workflow():
90
+ """Workflow state and phase management.
91
+
92
+ \b
93
+ Commands:
94
+ check - Check current workflow state
95
+ phase-check - Verify phase ownership
96
+ handoff - Emit handoff marker
97
+ """
98
+ pass
99
+
100
+
101
+ @workflow.command("check")
102
+ @click.option("--json", "output_json", is_flag=True, help="Output as JSON")
103
+ def workflow_check(output_json: bool):
104
+ """Check current workflow state.
105
+
106
+ Returns the current story ID, phase, and workflow state.
107
+ """
108
+ # Lazy import - only load when command is actually invoked
109
+ from pennyfarthing_scripts.workflow import get_workflow_state
110
+
111
+ state = get_workflow_state()
112
+
113
+ if output_json:
114
+ import json
115
+
116
+ click.echo(json.dumps(state, indent=2))
117
+ else:
118
+ click.echo(f"State: {state.get('state', 'unknown')}")
119
+ if state.get("story_id"):
120
+ click.echo(f"Story: {state['story_id']}")
121
+ if state.get("workflow"):
122
+ click.echo(f"Workflow: {state['workflow']}")
123
+ if state.get("phase"):
124
+ click.echo(f"Phase: {state['phase']}")
125
+
126
+
127
+ @workflow.command("phase-check")
128
+ @click.argument("workflow_name")
129
+ @click.argument("phase")
130
+ def workflow_phase_check(workflow_name: str, phase: str):
131
+ """Check which agent owns a workflow phase.
132
+
133
+ \b
134
+ Arguments:
135
+ WORKFLOW_NAME - The workflow type (tdd, trivial, etc.)
136
+ PHASE - The phase to check (red, implement, review, etc.)
137
+ """
138
+ # Lazy import
139
+ from pennyfarthing_scripts.workflow import get_phase_owner
140
+
141
+ owner = get_phase_owner(workflow_name, phase)
142
+ click.echo(owner)
143
+
144
+
145
+ @workflow.command("handoff")
146
+ @click.argument("next_agent")
147
+ def workflow_handoff(next_agent: str):
148
+ """Emit a handoff marker for Cyclist.
149
+
150
+ \b
151
+ Arguments:
152
+ NEXT_AGENT - The agent to hand off to (tea, dev, reviewer, etc.)
153
+ """
154
+ # Output the marker format expected by Cyclist
155
+ click.echo("---")
156
+ click.echo("AGENT_COMMAND:")
157
+ click.echo(f' marker: "<!-- CYCLIST:HANDOFF:/{next_agent} -->"')
158
+ click.echo(f' fallback: "Run `/{next_agent}` to continue"')
159
+ click.echo("---")
160
+
161
+
162
+ def main():
163
+ """Entry point for the CLI."""
164
+ cli()
165
+
166
+
167
+ if __name__ == "__main__":
168
+ main()