@techierathore/techieflow 1.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 (151) hide show
  1. package/.claude/commands/TechieFlow/agents/analyst.md +97 -0
  2. package/.claude/commands/TechieFlow/agents/architect.md +84 -0
  3. package/.claude/commands/TechieFlow/agents/flow-master.md +217 -0
  4. package/.claude/commands/TechieFlow/agents/verifier.md +72 -0
  5. package/.claude/commands/TechieFlow/tasks/_metrics-emit-gate.md +138 -0
  6. package/.claude/commands/TechieFlow/tasks/_smoke-test-policy.md +98 -0
  7. package/.claude/commands/TechieFlow/tasks/_status-update-gate.md +78 -0
  8. package/.claude/commands/TechieFlow/tasks/_yolo-mode.md +77 -0
  9. package/.claude/commands/TechieFlow/tasks/advanced-elicitation.md +117 -0
  10. package/.claude/commands/TechieFlow/tasks/amend-docs.md +149 -0
  11. package/.claude/commands/TechieFlow/tasks/author-brd.md +79 -0
  12. package/.claude/commands/TechieFlow/tasks/build-phase.md +231 -0
  13. package/.claude/commands/TechieFlow/tasks/create-deep-research-prompt.md +278 -0
  14. package/.claude/commands/TechieFlow/tasks/create-doc.md +101 -0
  15. package/.claude/commands/TechieFlow/tasks/day1-brownfield.md +507 -0
  16. package/.claude/commands/TechieFlow/tasks/day1-greenfield.md +224 -0
  17. package/.claude/commands/TechieFlow/tasks/devguide.md +224 -0
  18. package/.claude/commands/TechieFlow/tasks/document-project.md +343 -0
  19. package/.claude/commands/TechieFlow/tasks/execute-checklist.md +86 -0
  20. package/.claude/commands/TechieFlow/tasks/facilitate-brainstorming-session.md +136 -0
  21. package/.claude/commands/TechieFlow/tasks/fix-issues.md +134 -0
  22. package/.claude/commands/TechieFlow/tasks/generate-html.md +115 -0
  23. package/.claude/commands/TechieFlow/tasks/handoff-phase.md +126 -0
  24. package/.claude/commands/TechieFlow/tasks/index-docs.md +173 -0
  25. package/.claude/commands/TechieFlow/tasks/kb-mode-interaction.md +75 -0
  26. package/.claude/commands/TechieFlow/tasks/log-miss.md +160 -0
  27. package/.claude/commands/TechieFlow/tasks/metrics-report.md +143 -0
  28. package/.claude/commands/TechieFlow/tasks/mockups.md +122 -0
  29. package/.claude/commands/TechieFlow/tasks/productguide.md +105 -0
  30. package/.claude/commands/TechieFlow/tasks/refresh-status.md +135 -0
  31. package/.claude/commands/TechieFlow/tasks/render-workflow-docs.md +117 -0
  32. package/.claude/commands/TechieFlow/tasks/shard-doc.md +185 -0
  33. package/.claude/commands/TechieFlow/tasks/split-brd.md +131 -0
  34. package/.claude/commands/TechieFlow/tasks/triage-issues.md +157 -0
  35. package/.claude/commands/TechieFlow/tasks/verify-phase.md +579 -0
  36. package/.claude/commands/generate-html.md +124 -0
  37. package/.codex/config.toml +46 -0
  38. package/.codex/hooks.json +63 -0
  39. package/.codex/rules/techieflow.rules +8 -0
  40. package/.opencode/command/generate-html.md +129 -0
  41. package/.opencode/plugin/techieflow.js +350 -0
  42. package/.tfcore/TOKEN-GUIDE.md +59 -0
  43. package/.tfcore/agents/analyst.md +97 -0
  44. package/.tfcore/agents/architect.md +84 -0
  45. package/.tfcore/agents/flow-master.md +217 -0
  46. package/.tfcore/agents/verifier.md +72 -0
  47. package/.tfcore/checklists/architect-checklist.md +438 -0
  48. package/.tfcore/core-config.yaml +47 -0
  49. package/.tfcore/data/brainstorming-techniques.md +36 -0
  50. package/.tfcore/data/elicitation-methods.md +154 -0
  51. package/.tfcore/data/techieflow-kb.md +807 -0
  52. package/.tfcore/data/technical-preferences.md +3 -0
  53. package/.tfcore/enhanced-ide-development-workflow.md +248 -0
  54. package/.tfcore/hooks/block-git.sh +301 -0
  55. package/.tfcore/hooks/codex-adapter.py +248 -0
  56. package/.tfcore/hooks/guard-artifacts.sh +101 -0
  57. package/.tfcore/hooks/guard-status-html.sh +102 -0
  58. package/.tfcore/hooks/guard-status.sh +124 -0
  59. package/.tfcore/hooks/guard-verify.sh +108 -0
  60. package/.tfcore/hooks/metrics-session.sh +129 -0
  61. package/.tfcore/hooks/session-pointer.sh +52 -0
  62. package/.tfcore/hooks/sweep-artifacts.sh +198 -0
  63. package/.tfcore/install-manifest.yaml +231 -0
  64. package/.tfcore/routing.yaml +105 -0
  65. package/.tfcore/tasks/_metrics-emit-gate.md +138 -0
  66. package/.tfcore/tasks/_smoke-test-policy.md +98 -0
  67. package/.tfcore/tasks/_status-update-gate.md +78 -0
  68. package/.tfcore/tasks/_yolo-mode.md +77 -0
  69. package/.tfcore/tasks/advanced-elicitation.md +117 -0
  70. package/.tfcore/tasks/amend-docs.md +149 -0
  71. package/.tfcore/tasks/author-brd.md +79 -0
  72. package/.tfcore/tasks/build-phase.md +231 -0
  73. package/.tfcore/tasks/create-deep-research-prompt.md +278 -0
  74. package/.tfcore/tasks/create-doc.md +101 -0
  75. package/.tfcore/tasks/day1-brownfield.md +507 -0
  76. package/.tfcore/tasks/day1-greenfield.md +224 -0
  77. package/.tfcore/tasks/devguide.md +224 -0
  78. package/.tfcore/tasks/document-project.md +343 -0
  79. package/.tfcore/tasks/execute-checklist.md +86 -0
  80. package/.tfcore/tasks/facilitate-brainstorming-session.md +136 -0
  81. package/.tfcore/tasks/fix-issues.md +134 -0
  82. package/.tfcore/tasks/generate-html.md +115 -0
  83. package/.tfcore/tasks/handoff-phase.md +126 -0
  84. package/.tfcore/tasks/index-docs.md +173 -0
  85. package/.tfcore/tasks/kb-mode-interaction.md +75 -0
  86. package/.tfcore/tasks/log-miss.md +160 -0
  87. package/.tfcore/tasks/metrics-report.md +143 -0
  88. package/.tfcore/tasks/mockups.md +122 -0
  89. package/.tfcore/tasks/productguide.md +105 -0
  90. package/.tfcore/tasks/refresh-status.md +135 -0
  91. package/.tfcore/tasks/render-workflow-docs.md +117 -0
  92. package/.tfcore/tasks/shard-doc.md +185 -0
  93. package/.tfcore/tasks/split-brd.md +131 -0
  94. package/.tfcore/tasks/triage-issues.md +157 -0
  95. package/.tfcore/tasks/verify-phase.md +579 -0
  96. package/.tfcore/telemetry/SCHEMA.md +678 -0
  97. package/.tfcore/telemetry/install-metrics.sh +390 -0
  98. package/.tfcore/telemetry/pre-commit +94 -0
  99. package/.tfcore/telemetry/tf-metrics.sh +1415 -0
  100. package/.tfcore/templates/architecture-tmpl.yaml +650 -0
  101. package/.tfcore/templates/brainstorming-output-tmpl.yaml +156 -0
  102. package/.tfcore/templates/brownfield-architecture-tmpl.yaml +476 -0
  103. package/.tfcore/templates/competitor-analysis-tmpl.yaml +306 -0
  104. package/.tfcore/templates/front-end-architecture-tmpl.yaml +218 -0
  105. package/.tfcore/templates/fullstack-architecture-tmpl.yaml +823 -0
  106. package/.tfcore/templates/market-research-tmpl.yaml +252 -0
  107. package/.tfcore/templates/project-brief-tmpl.yaml +221 -0
  108. package/.tfcore/templates/v4custom/app-agents-md-tmpl.md +61 -0
  109. package/.tfcore/templates/v4custom/app-architecture-tmpl.md +127 -0
  110. package/.tfcore/templates/v4custom/app-brd-tmpl.md +204 -0
  111. package/.tfcore/templates/v4custom/app-checklist-tmpl.md +90 -0
  112. package/.tfcore/templates/v4custom/app-claude-md-tmpl.md +33 -0
  113. package/.tfcore/templates/v4custom/app-devguide-tmpl.md +167 -0
  114. package/.tfcore/templates/v4custom/app-editorconfig-tmpl.editorconfig +44 -0
  115. package/.tfcore/templates/v4custom/app-library-feedback-tmpl.md +31 -0
  116. package/.tfcore/templates/v4custom/app-productguide-tmpl.md +54 -0
  117. package/.tfcore/templates/v4custom/app-project-status-tmpl.md +98 -0
  118. package/.tfcore/templates/v4custom/app-uidesign-tmpl.md +48 -0
  119. package/.tfcore/templates/v4custom/app-usageguide-tmpl.md +67 -0
  120. package/.tfcore/templates/v4custom/build-invocation-ladder.md +190 -0
  121. package/.tfcore/templates/v4custom/html-render-shell.md +502 -0
  122. package/.tfcore/templates/v4custom/metrics-report-template.md +273 -0
  123. package/.tfcore/templates/v4custom/opencode-operating-contract.md +56 -0
  124. package/.tfcore/user-guide.md +633 -0
  125. package/.tfcore/utils/techieflow-doc-template.md +325 -0
  126. package/.tfcore/utils/tf-assets.sh +310 -0
  127. package/.tfcore/utils/tf-codex-bind.py +196 -0
  128. package/.tfcore/utils/tf-codex-telemetry.py +60 -0
  129. package/.tfcore/utils/tf-emit.sh +1075 -0
  130. package/.tfcore/utils/tf-gitignore-audit.sh +281 -0
  131. package/.tfcore/utils/tf-goal.sh +421 -0
  132. package/.tfcore/utils/tf-harness.sh +160 -0
  133. package/.tfcore/utils/tf-mockup-parity.mjs +555 -0
  134. package/.tfcore/utils/tf-mockup-parity.sh +65 -0
  135. package/.tfcore/utils/tf-opencode-audit.py +126 -0
  136. package/.tfcore/utils/tf-perf.sh +241 -0
  137. package/.tfcore/utils/tf-render-html.py +715 -0
  138. package/.tfcore/utils/tf-render-html.sh +28 -0
  139. package/.tfcore/utils/tf-routing-bind.sh +216 -0
  140. package/.tfcore/utils/tf-routing.sh +247 -0
  141. package/.tfcore/utils/tf-yolo.sh +119 -0
  142. package/.tfcore/working-in-the-brownfield.md +606 -0
  143. package/LICENSE +201 -0
  144. package/README.md +1212 -0
  145. package/WORKFLOW.html +1986 -0
  146. package/docs/TechieFlow-Installation.md +299 -0
  147. package/opencode.jsonc +929 -0
  148. package/package.json +60 -0
  149. package/scripts/install.mjs +992 -0
  150. package/scripts/test-install.mjs +505 -0
  151. package/scripts/validate.mjs +155 -0
@@ -0,0 +1,3 @@
1
+ # User-Defined Preferred Patterns and Preferences
2
+
3
+ None Listed
@@ -0,0 +1,248 @@
1
+ # Enhanced IDE Development Workflow
2
+
3
+ This is a simple step-by-step guide to help you efficiently manage your development workflow using the TechieFlow. The workflow integrates the Test Architect (QA agent) throughout the development lifecycle to ensure quality, prevent regressions, and maintain high standards. Refer to the **[<ins>User Guide</ins>](user-guide.md)** for any scenario that is not covered here.
4
+
5
+ ## Create New Branch
6
+
7
+ 1. **Start new branch**
8
+
9
+ ## Story Creation (Scrum Master)
10
+
11
+ 1. **Start new chat/conversation**
12
+ 2. **Load SM agent**
13
+ 3. **Execute**: `*draft` (runs create-next-story task)
14
+ 4. **Review generated story** in `docs/stories/`
15
+ 5. **Update status**: Change from "Draft" to "Approved"
16
+
17
+ ## Story Implementation (Developer)
18
+
19
+ 1. **Start new chat/conversation**
20
+ 2. **Load Dev agent**
21
+ 3. **Execute**: `*develop-story {selected-story}` (runs execute-checklist task)
22
+ 4. **Review generated report** in `{selected-story}`
23
+
24
+ ## Test Architect Integration Throughout Workflow
25
+
26
+ The Test Architect (Quinn) provides comprehensive quality assurance throughout the development lifecycle. Here's how to leverage each capability at the right time.
27
+
28
+ **Command Aliases:** Documentation uses short forms (`*risk`, `*design`, `*nfr`, `*trace`) for the full commands (`*risk-profile`, `*test-design`, `*nfr-assess`, `*trace-requirements`).
29
+
30
+ ### Quick Command Reference
31
+
32
+ | **Stage** | **Command** | **Purpose** | **Output** | **Priority** |
33
+ | ------------------------ | ----------- | --------------------------------------- | --------------------------------------------------------------- | --------------------------- |
34
+ | **After Story Approval** | `*risk` | Identify integration & regression risks | `docs/qa/assessments/{epic}.{story}-risk-{YYYYMMDD}.md` | High for complex/brownfield |
35
+ | | `*design` | Create test strategy for dev | `docs/qa/assessments/{epic}.{story}-test-design-{YYYYMMDD}.md` | High for new features |
36
+ | **During Development** | `*trace` | Verify test coverage | `docs/qa/assessments/{epic}.{story}-trace-{YYYYMMDD}.md` | Medium |
37
+ | | `*nfr` | Validate quality attributes | `docs/qa/assessments/{epic}.{story}-nfr-{YYYYMMDD}.md` | High for critical features |
38
+ | **After Development** | `*review` | Comprehensive assessment | QA Results in story + `docs/qa/gates/{epic}.{story}-{slug}.yml` | **Required** |
39
+ | **Post-Review** | `*gate` | Update quality decision | Updated `docs/qa/gates/{epic}.{story}-{slug}.yml` | As needed |
40
+
41
+ ### Stage 1: After Story Creation (Before Dev Starts)
42
+
43
+ **RECOMMENDED - Set Developer Up for Success:**
44
+
45
+ ```bash
46
+ # 1. RISK ASSESSMENT (Run FIRST for complex stories)
47
+ @qa *risk {approved-story}
48
+ # Identifies:
49
+ # - Technical debt impact
50
+ # - Integration complexity
51
+ # - Regression potential (1-9 scoring)
52
+ # - Mitigation strategies
53
+ # Critical for: Brownfield, API changes, data migrations
54
+
55
+ # 2. TEST DESIGN (Run SECOND to guide implementation)
56
+ @qa *design {approved-story}
57
+ # Provides:
58
+ # - Test scenarios per acceptance criterion
59
+ # - Test level recommendations (unit/integration/E2E)
60
+ # - Risk-based priorities (P0/P1/P2)
61
+ # - Test data requirements
62
+ # Share with Dev: Include in story comments or attach to ticket
63
+ ```
64
+
65
+ ### Stage 2: During Development (Mid-Implementation Checkpoints)
66
+
67
+ **Developer Self-Service Quality Checks:**
68
+
69
+ ```bash
70
+ # 3. REQUIREMENTS TRACING (Verify coverage mid-development)
71
+ @qa *trace {story-in-progress}
72
+ # Validates:
73
+ # - All acceptance criteria have tests
74
+ # - No missing test scenarios
75
+ # - Appropriate test levels
76
+ # - Given-When-Then documentation clarity
77
+ # Run when: After writing initial tests
78
+
79
+ # 4. NFR VALIDATION (Check quality attributes)
80
+ @qa *nfr {story-in-progress}
81
+ # Assesses:
82
+ # - Security: Authentication, authorization, data protection
83
+ # - Performance: Response times, resource usage
84
+ # - Reliability: Error handling, recovery
85
+ # - Maintainability: Code quality, documentation
86
+ # Run when: Before marking "Ready for Review"
87
+ ```
88
+
89
+ ### Stage 3: Story Review (Quality Gate Assessment)
90
+
91
+ **REQUIRED - Comprehensive Test Architecture Review:**
92
+
93
+ **Prerequisite:** All tests green locally; lint & type checks pass.
94
+
95
+ ```bash
96
+ # 5. FULL REVIEW (Standard review process)
97
+ @qa *review {completed-story}
98
+ ```
99
+
100
+ **What Happens During Review:**
101
+
102
+ 1. **Deep Code Analysis**
103
+ - Architecture pattern compliance
104
+ - Code quality and maintainability
105
+ - Security vulnerability scanning
106
+ - Performance bottleneck detection
107
+
108
+ 2. **Active Refactoring**
109
+ - Improves code directly when safe
110
+ - Fixes obvious issues immediately
111
+ - Suggests complex refactoring for dev
112
+
113
+ 3. **Test Validation**
114
+ - Coverage at all levels (unit/integration/E2E)
115
+ - Test quality (no flaky tests, proper assertions)
116
+ - Regression test adequacy
117
+
118
+ 4. **Gate Decision**
119
+ - Creates: `docs/qa/gates/{epic}.{story}-{slug}.yml`
120
+ - Adds: QA Results section to story file
121
+ - Status: PASS/CONCERNS/FAIL/WAIVED
122
+
123
+ ### Stage 4: Post-Review (After Addressing Issues)
124
+
125
+ **Update Gate Status After Fixes:**
126
+
127
+ ```bash
128
+ # 6. GATE UPDATE (Document final decision)
129
+ @qa *gate {reviewed-story}
130
+ # Updates: Quality gate with new status
131
+ # Use when: After addressing review feedback
132
+ # Documents: What was fixed, what was waived
133
+ ```
134
+
135
+ ### Understanding Gate Decisions
136
+
137
+ | **Status** | **Meaning** | **Action Required** | **Can Proceed?** |
138
+ | ------------ | -------------------------------------------- | ----------------------- | ---------------- |
139
+ | **PASS** | All critical requirements met | None | ✅ Yes |
140
+ | **CONCERNS** | Non-critical issues found | Team review recommended | ⚠️ With caution |
141
+ | **FAIL** | Critical issues (security, missing P0 tests) | Must fix | ❌ No |
142
+ | **WAIVED** | Issues acknowledged and accepted | Document reasoning | ✅ With approval |
143
+
144
+ ### Risk-Based Testing Strategy
145
+
146
+ The Test Architect uses risk scoring to prioritize testing:
147
+
148
+ | **Risk Score** | **Calculation** | **Testing Priority** | **Gate Impact** |
149
+ | -------------- | ------------------------------ | ------------------------- | ------------------------ |
150
+ | **9** | High probability × High impact | P0 - Must test thoroughly | FAIL if untested |
151
+ | **6** | Medium-high combinations | P1 - Should test well | CONCERNS if gaps |
152
+ | **4** | Medium combinations | P1 - Should test | CONCERNS if notable gaps |
153
+ | **2-3** | Low-medium combinations | P2 - Nice to have | Note in review |
154
+ | **1** | Minimal risk | P2 - Minimal | Note in review |
155
+
156
+ ### Special Situations & Best Practices
157
+
158
+ #### High-Risk or Brownfield Stories
159
+
160
+ ```bash
161
+ # ALWAYS run this sequence:
162
+ @qa *risk {story} # First - identify dangers
163
+ @qa *design {story} # Second - plan defense
164
+ # Then during dev:
165
+ @qa *trace {story} # Verify regression coverage
166
+ @qa *nfr {story} # Check performance impact
167
+ # Finally:
168
+ @qa *review {story} # Deep integration analysis
169
+ ```
170
+
171
+ #### Complex Integrations
172
+
173
+ - Run `*trace` multiple times during development
174
+ - Focus on integration test coverage
175
+ - Use `*nfr` to validate cross-system performance
176
+ - Review with extra attention to API contracts
177
+
178
+ #### Performance-Critical Features
179
+
180
+ - Run `*nfr` early and often (not just at review)
181
+ - Establish performance baselines before changes
182
+ - Document acceptable performance degradation
183
+ - Consider load testing requirements in `*design`
184
+
185
+ ### Test Quality Standards Enforced
186
+
187
+ Quinn ensures all tests meet these standards:
188
+
189
+ - **No Flaky Tests**: Proper async handling, explicit waits
190
+ - **No Hard Waits**: Dynamic strategies only (polling, events)
191
+ - **Stateless**: Tests run independently and in parallel
192
+ - **Self-Cleaning**: Tests manage their own test data
193
+ - **Appropriate Levels**: Unit for logic, integration for interactions, E2E for journeys
194
+ - **Clear Assertions**: Keep assertions in tests, not buried in helpers
195
+
196
+ ### Documentation & Audit Trail
197
+
198
+ All Test Architect activities create permanent records:
199
+
200
+ - **Assessment Reports**: Timestamped analysis in `docs/qa/assessments/`
201
+ - **Gate Files**: Decision records in `docs/qa/gates/`
202
+ - **Story Updates**: QA Results sections in story files
203
+ - **Traceability**: Requirements to test mapping maintained
204
+
205
+ ## Commit Changes and Push
206
+
207
+ 1. **Commit changes**
208
+ 2. **Push to remote**
209
+
210
+ ## Complete Development Cycle Flow
211
+
212
+ ### The Full Workflow with Test Architect
213
+
214
+ 1. **SM**: Create next story → Review → Approve
215
+ 2. **QA (Optional)**: Risk assessment (`*risk`) → Test design (`*design`)
216
+ 3. **Dev**: Implement story → Write tests → Complete
217
+ 4. **QA (Optional)**: Mid-dev checks (`*trace`, `*nfr`)
218
+ 5. **Dev**: Mark Ready for Review
219
+ 6. **QA (Required)**: Review story (`*review`) → Gate decision
220
+ 7. **Dev (If needed)**: Address issues
221
+ 8. **QA (If needed)**: Update gate (`*gate`)
222
+ 9. **Commit**: All changes
223
+ 10. **Push**: To remote
224
+ 11. **Continue**: Until all features implemented
225
+
226
+ ### Quick Decision Guide
227
+
228
+ **Should I run Test Architect commands?**
229
+
230
+ | **Scenario** | **Before Dev** | **During Dev** | **After Dev** |
231
+ | ------------------------ | ------------------------------- | ---------------------------- | ---------------------------- |
232
+ | **Simple bug fix** | Optional | Optional | Required `*review` |
233
+ | **New feature** | Recommended `*risk`, `*design` | Optional `*trace` | Required `*review` |
234
+ | **Brownfield change** | **Required** `*risk`, `*design` | Recommended `*trace`, `*nfr` | Required `*review` |
235
+ | **API modification** | **Required** `*risk`, `*design` | **Required** `*trace` | Required `*review` |
236
+ | **Performance-critical** | Recommended `*design` | **Required** `*nfr` | Required `*review` |
237
+ | **Data migration** | **Required** `*risk`, `*design` | **Required** `*trace` | Required `*review` + `*gate` |
238
+
239
+ ### Success Metrics
240
+
241
+ The Test Architect helps achieve:
242
+
243
+ - **Zero regression defects** in production
244
+ - **100% requirements coverage** with tests
245
+ - **Clear quality gates** for go/no-go decisions
246
+ - **Documented risk acceptance** for technical debt
247
+ - **Consistent test quality** across the team
248
+ - **Shift-left testing** with early risk identification
@@ -0,0 +1,301 @@
1
+ #!/usr/bin/env bash
2
+ # TechieFlow PreToolUse hook for Bash — the git guard + the YOLO permission gate.
3
+ #
4
+ # Two jobs, one hook (wired in .claude/settings.json → hooks.PreToolUse, matcher
5
+ # "Bash"; the OpenCode plugin .opencode/plugin/techieflow.js feeds it the same
6
+ # Claude-shaped stdin for the `bash` tool):
7
+ #
8
+ # 1. GIT GUARD. Git is MANUAL in TechieFlow — agents never COMMIT, PUSH, STAGE,
9
+ # RESET, CHECKOUT or otherwise WRITE to git, ever (.tfcore/tasks/_smoke-test-policy.md
10
+ # §"Git is manual", _status-update-gate.md §"Never run git"). Outside YOLO,
11
+ # agents never READ git either (status/log/diff/blame) — status evidence is the
12
+ # checklist table + working tree + a fresh build. In YOLO mode (below) READ-ONLY
13
+ # git/gh is allowed; WRITES stay blocked in every mode. settings.json's deny
14
+ # rules list the write subcommands as a second layer (deny rules hold in every
15
+ # permission mode, bypass included); this hook catches the compound forms
16
+ # prefix-matching misses ("cd x && git log", "foo | git …", "bash -c 'git …'").
17
+ #
18
+ # 2. YOLO GATE (.tfcore/tasks/_yolo-mode.md). Claude Code honours settings.json
19
+ # `ask` rules EVEN in bypassPermissions mode and EVEN when a hook says allow —
20
+ # so `rm`/`rmdir`/`sudo` are NOT in settings.json `ask` any more; this hook is
21
+ # the only place that decides. Outside YOLO it returns permissionDecision=ask
22
+ # for them (same prompt the owner always had). In YOLO it stays silent and the
23
+ # bare "Bash" allow rule lets them run — an unattended goal run never stalls on
24
+ # a delete. Catastrophic `rm -rf /|~` stay in settings.json `deny` (every mode).
25
+ #
26
+ # YOLO is ON when any of: env TF_YOLO=1 · .tfcore/.session/yolo.json exists
27
+ # (tf-yolo.sh on) · the hook payload's permission_mode is bypassPermissions/auto.
28
+ #
29
+ # Exit codes: 2 + stderr = BLOCK (both harnesses); 0 + JSON on stdout = decision
30
+ # (Claude Code only; OpenCode ignores stdout and uses its own permission map).
31
+ # Any internal failure → fall back to the ORIGINAL conservative behaviour
32
+ # (block any command word git/gh via regex; leave rm to the harness).
33
+
34
+ INPUT="$(cat)"
35
+ ROOT="${CLAUDE_PROJECT_DIR:-${TF_PROJECT_DIR:-}}"
36
+ STRICT_GIT="${TF_STRICT_GIT:-0}"
37
+
38
+ YOLO=0
39
+ [[ "${TF_YOLO:-0}" == "1" ]] && YOLO=1
40
+ # The on-disk flag EXPIRES (tf-yolo.sh flag_live, same 24h default and the same
41
+ # portable `find -mmin` test). `off`/`done` clear it, but a killed or crashed run
42
+ # leaves it behind and an unnoticed flag silently suppresses delete prompts for as
43
+ # long as it sits there — five repos were found in that state on 2026-08-28, one of
44
+ # them 6 days old. TF_YOLO=1 is checked above and never expires, so a long
45
+ # tf-goal.sh run (which exports it) is unaffected.
46
+ if [[ $YOLO -eq 0 && -n "$ROOT" && -f "$ROOT/.tfcore/.session/yolo.json" ]]; then
47
+ TTL_HOURS="${TF_YOLO_TTL_HOURS:-24}"
48
+ if [[ "$TTL_HOURS" == "0" ]] || [[ -z "$(find "$ROOT/.tfcore/.session/yolo.json" -mmin "+$(( TTL_HOURS * 60 ))" 2>/dev/null)" ]]; then
49
+ YOLO=1
50
+ fi
51
+ fi
52
+ if [[ $YOLO -eq 0 ]] && printf '%s' "$INPUT" | grep -qE '"permission_mode"[[:space:]]*:[[:space:]]*"(bypassPermissions|auto)"'; then YOLO=1; fi
53
+
54
+ block_git_msg() {
55
+ cat >&2 <<'MSG'
56
+ BLOCKED by TechieFlow policy: agents NEVER WRITE to git or gh — no commit / push / add / reset / checkout / stash / tag / merge / rebase / branch edits / gh pr|issue create|merge|close. Git is manual, owner-only, in EVERY mode including YOLO.
57
+ Do NOT retry with another git/gh form. Instead:
58
+ - Status updates / "what changed": read the checklist Requirements Status table + the working-tree files (ls -lt, find -newer, Read/Glob/Grep) + a fresh dotnet build — never commit history (.tfcore/tasks/_status-update-gate.md).
59
+ - Investigating code: read the files on disk at file:line — the working tree IS the as-built code.
60
+ - Committing/tagging: never yours. Record REQ IDs in the checklist Remarks, not in commits. The owner commits manually.
61
+ - If your command merely CONTAINS the word git (e.g. writing a doc, grepping for the string): use the Write/Edit/Grep tools instead of bash — that is the standing tool-preference rule anyway.
62
+ MSG
63
+ }
64
+ block_read_msg() {
65
+ if [[ "$STRICT_GIT" == "1" ]]; then
66
+ cat >&2 <<'MSG'
67
+ BLOCKED by TechieFlow Codex policy: agents do not run any git or gh command, including read-only status/log/diff/blame, in any mode.
68
+ Use the checklist Requirements Status table, working-tree files, filesystem metadata, and fresh build/test evidence instead. The owner performs version-control operations manually.
69
+ MSG
70
+ return
71
+ fi
72
+ cat >&2 <<'MSG'
73
+ BLOCKED by TechieFlow policy: agents do not READ git outside YOLO mode (no status/log/diff/show/blame/grep) — git is manual, owner-only.
74
+ Do NOT retry with another git/gh form. Instead:
75
+ - Status updates / "what changed": read the checklist Requirements Status table + the working-tree files (ls -lt, find -newer, Read/Glob/Grep) + a fresh dotnet build — never commit history (.tfcore/tasks/_status-update-gate.md).
76
+ - Investigating code: read the files on disk at file:line — the working tree IS the as-built code.
77
+ - Read-only git (status/log/diff/blame) becomes available only in YOLO / goal mode (`*yolo` → bash .tfcore/utils/tf-yolo.sh on). Git WRITES are never available.
78
+ MSG
79
+ }
80
+
81
+ if ! command -v python3 >/dev/null 2>&1; then
82
+ # Original conservative behaviour — no parser available.
83
+ if printf '%s' "$INPUT" | grep -qE '(^|[^[:alnum:]_./@-])(git|gh)([^[:alnum:]_.-]|$)'; then block_git_msg; exit 2; fi
84
+ exit 0
85
+ fi
86
+
87
+ # Verdicts: ALLOW | ASK_RM | BLOCK_WRITE | BLOCK_READ
88
+ VERDICT="$(TF_HOOK_INPUT="$INPUT" TF_YOLO_ON="$YOLO" python3 - <<'PY' 2>/dev/null
89
+ import json, os, re, shlex, sys
90
+
91
+ raw = os.environ.get("TF_HOOK_INPUT", "")
92
+ yolo = os.environ.get("TF_YOLO_ON") == "1"
93
+ strict_git = os.environ.get("TF_STRICT_GIT") == "1"
94
+ try:
95
+ data = json.loads(raw)
96
+ cmd = str((data.get("tool_input") or {}).get("command") or "")
97
+ except Exception:
98
+ cmd = raw # be conservative: scan whatever we got
99
+
100
+ # ---- git / gh classification --------------------------------------------------
101
+ GIT_READ = {
102
+ "status", "log", "diff", "show", "blame", "grep", "ls-files", "ls-tree", "rev-parse",
103
+ "rev-list", "describe", "shortlog", "cat-file", "name-rev", "merge-base", "cherry",
104
+ "whatchanged", "count-objects", "fsck", "var", "check-ignore", "check-attr",
105
+ "for-each-ref", "diff-tree", "diff-index", "diff-files", "show-ref", "show-branch",
106
+ "ls-remote", "version", "help", "range-diff", "annotate", "bisect", "reflog",
107
+ }
108
+ # read-only only with these arg shapes (no args == list/show)
109
+ BRANCH_LIST_FLAGS = {"-a", "-r", "-v", "-vv", "--list", "--show-current", "--contains", "--no-contains",
110
+ "--merged", "--no-merged", "--all", "--remotes", "--verbose", "--points-at", "--sort"}
111
+ TAG_LIST_FLAGS = {"-l", "--list", "-n", "--contains", "--no-contains", "--points-at", "--sort", "--merged", "--no-merged"}
112
+
113
+ def _listing(a, list_flags):
114
+ """read-only iff every flag is a listing flag AND (no positional args, or an explicit list flag is present)."""
115
+ flags = [t for t in a if t.startswith("-")]
116
+ pos = [t for t in a if not t.startswith("-")]
117
+ if any(t.split("=", 1)[0] not in list_flags and not t.startswith("-n") for t in flags):
118
+ return False
119
+ return not pos or any(t.split("=", 1)[0] in list_flags for t in flags)
120
+
121
+ GIT_COND = {
122
+ "branch": lambda a: _listing(a, BRANCH_LIST_FLAGS),
123
+ "tag": lambda a: _listing(a, TAG_LIST_FLAGS),
124
+ "stash": lambda a: bool(a) and a[0] in ("list", "show"),
125
+ "remote": lambda a: (not a) or a[0] in ("-v", "--verbose", "show", "get-url"),
126
+ "config": lambda a: any(t in ("--get", "--get-all", "--get-regexp", "--list", "-l") for t in a)
127
+ and not any(t in ("--unset", "--unset-all", "--add", "--replace-all", "--edit", "-e",
128
+ "--remove-section", "--rename-section") for t in a),
129
+ "worktree": lambda a: bool(a) and a[0] == "list",
130
+ "submodule": lambda a: bool(a) and a[0] in ("status", "summary"),
131
+ "notes": lambda a: (not a) or a[0] in ("list", "show"),
132
+ "reflog": lambda a: (not a) or a[0] in ("show",) or a[0].startswith("-"),
133
+ "bisect": lambda a: bool(a) and a[0] in ("log", "view", "visualize"),
134
+ }
135
+ GH_READ_VERBS = {"list", "view", "status", "checks", "diff", "watch", "download"}
136
+ GH_READ_TOP = {"auth": {"status"}, "pr": GH_READ_VERBS, "issue": GH_READ_VERBS, "run": GH_READ_VERBS,
137
+ "release": GH_READ_VERBS, "repo": {"view", "list"}, "search": None, "browse": None,
138
+ "label": {"list"}, "workflow": {"list", "view"}, "gist": {"list", "view"},
139
+ "cache": {"list"}, "variable": {"list"}, "secret": {"list"}, "ruleset": {"list", "view"}}
140
+
141
+ WRAPPERS = {"command", "exec", "sudo", "env", "nohup", "time", "nice", "stdbuf", "timeout", "xargs",
142
+ "winrun", "doas", "busybox", "ionice", "chronic", "unbuffer", "script"}
143
+ SHELLS = {"bash", "sh", "zsh", "dash", "ksh", "fish"}
144
+ SEPS = {";", "&&", "||", "|", "&", "(", ")", "{", "}", "\n", "|&"}
145
+
146
+ def basename(tok):
147
+ tok = tok.strip("\"'")
148
+ return tok.rsplit("/", 1)[-1]
149
+
150
+ def classify_git(args):
151
+ """args = tokens after 'git'. Returns 'read' or 'write'."""
152
+ i = 0
153
+ # skip global options like -C <path>, -c k=v, --git-dir=..., --no-pager
154
+ while i < len(args) and args[i].startswith("-"):
155
+ if args[i] in ("-C", "-c", "--git-dir", "--work-tree", "--namespace") and i + 1 < len(args):
156
+ i += 2
157
+ else:
158
+ i += 1
159
+ if i >= len(args):
160
+ return "read" # bare `git` prints usage
161
+ sub = args[i]
162
+ rest = args[i + 1:]
163
+ if sub in GIT_READ:
164
+ return "read"
165
+ if sub in GIT_COND:
166
+ try:
167
+ return "read" if GIT_COND[sub](rest) else "write"
168
+ except Exception:
169
+ return "write"
170
+ return "write"
171
+
172
+ def classify_gh(args):
173
+ a = [t for t in args if not t.startswith("-")] or [""]
174
+ top = a[0]
175
+ if top == "api":
176
+ flags = set(t for t in args if t.startswith("-"))
177
+ if any(f in flags for f in ("-X", "--method", "-f", "-F", "--field", "--raw-field", "--input")):
178
+ # explicit GET is fine
179
+ for k, t in enumerate(args):
180
+ if t in ("-X", "--method") and k + 1 < len(args) and args[k + 1].upper() == "GET":
181
+ continue
182
+ if any(f in flags for f in ("-f", "-F", "--field", "--raw-field", "--input")):
183
+ return "write"
184
+ for k, t in enumerate(args):
185
+ if t in ("-X", "--method") and k + 1 < len(args) and args[k + 1].upper() != "GET":
186
+ return "write"
187
+ return "read"
188
+ return "read"
189
+ if top in GH_READ_TOP:
190
+ verbs = GH_READ_TOP[top]
191
+ if verbs is None:
192
+ return "read"
193
+ return "read" if len(a) > 1 and a[1] in verbs else "write"
194
+ return "write"
195
+
196
+ found = {"read": 0, "write": 0}
197
+ found_rm = [False]
198
+ found_sudo = [False]
199
+
200
+ def scan(cmdline, depth=0):
201
+ if depth > 4:
202
+ return
203
+ try:
204
+ lexer = shlex.shlex(cmdline, posix=True, punctuation_chars=";&|()")
205
+ lexer.whitespace_split = True
206
+ lexer.commenters = ""
207
+ toks = list(lexer)
208
+ except Exception:
209
+ raise
210
+ # split into simple commands
211
+ groups, cur = [], []
212
+ for t in toks:
213
+ if t in SEPS or t in (";;", "&&", "||", "|&"):
214
+ if cur:
215
+ groups.append(cur)
216
+ cur = []
217
+ else:
218
+ # shlex keeps "$(git" / "`git" glued; split those too
219
+ for piece in re.split(r"(?:\$\(|`|<\(|>\()", t):
220
+ if piece:
221
+ cur.append(piece)
222
+ if cur:
223
+ groups.append(cur)
224
+ for g in groups:
225
+ j = 0
226
+ # env assignments
227
+ while j < len(g) and re.match(r"^[A-Za-z_][A-Za-z0-9_]*=", g[j]):
228
+ j += 1
229
+ # wrappers
230
+ while j < len(g):
231
+ b = basename(g[j])
232
+ if b in WRAPPERS:
233
+ if b == "sudo" or b == "doas":
234
+ found_sudo[0] = True
235
+ if b == "timeout" and j + 1 < len(g):
236
+ j += 2; continue
237
+ if b == "env":
238
+ j += 1
239
+ while j < len(g) and re.match(r"^[A-Za-z_][A-Za-z0-9_]*=", g[j]):
240
+ j += 1
241
+ continue
242
+ j += 1
243
+ continue
244
+ break
245
+ if j >= len(g):
246
+ continue
247
+ head = basename(g[j])
248
+ args = g[j + 1:]
249
+ if head in SHELLS:
250
+ # bash -c "<string>" → recurse into the string
251
+ for k, t in enumerate(args):
252
+ if t in ("-c", "-lc", "-ic", "-ec", "-euc", "-exc") and k + 1 < len(args):
253
+ scan(args[k + 1], depth + 1)
254
+ continue
255
+ if head == "eval":
256
+ scan(" ".join(args), depth + 1)
257
+ continue
258
+ if head in ("git", "git.exe"):
259
+ found[classify_git(args)] += 1
260
+ elif head in ("gh", "gh.exe"):
261
+ found[classify_gh(args)] += 1
262
+ elif head in ("rm", "rmdir", "unlink", "shred"):
263
+ found_rm[0] = True
264
+ elif head in ("find",) and ("-delete" in args or "-exec" in args and any(basename(x) == "rm" for x in args)):
265
+ found_rm[0] = True
266
+
267
+ try:
268
+ scan(cmd)
269
+ except Exception:
270
+ # unparsable (unbalanced quotes etc.) → conservative regex, as before
271
+ if re.search(r'(^|[^A-Za-z0-9_./@-])(git|gh)([^A-Za-z0-9_.-]|$)', cmd):
272
+ print("BLOCK_WRITE" if not yolo else "BLOCK_WRITE")
273
+ else:
274
+ print("ALLOW")
275
+ sys.exit(0)
276
+
277
+ if found["write"]:
278
+ print("BLOCK_WRITE")
279
+ elif found["read"] and (strict_git or not yolo):
280
+ print("BLOCK_READ")
281
+ elif (found_rm[0] or found_sudo[0]) and not yolo:
282
+ print("ASK_RM")
283
+ else:
284
+ print("ALLOW")
285
+ PY
286
+ )"
287
+
288
+ case "$VERDICT" in
289
+ BLOCK_WRITE) block_git_msg; exit 2 ;;
290
+ BLOCK_READ) block_read_msg; exit 2 ;;
291
+ ASK_RM)
292
+ # Claude Code: surface the owner's usual delete/sudo prompt (hook "ask"
293
+ # beats the bare "Bash" allow). OpenCode: its own `rm *: ask` map prompts.
294
+ printf '%s\n' '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"ask","permissionDecisionReason":"TechieFlow: delete/sudo asks unless YOLO is on (*yolo / tf-yolo.sh on)"}}'
295
+ exit 0 ;;
296
+ ALLOW|"") exit 0 ;;
297
+ *)
298
+ # Unknown verdict text → original conservative behaviour.
299
+ if printf '%s' "$INPUT" | grep -qE '(^|[^[:alnum:]_./@-])(git|gh)([^[:alnum:]_.-]|$)'; then block_git_msg; exit 2; fi
300
+ exit 0 ;;
301
+ esac