@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.
- package/.claude/commands/TechieFlow/agents/analyst.md +97 -0
- package/.claude/commands/TechieFlow/agents/architect.md +84 -0
- package/.claude/commands/TechieFlow/agents/flow-master.md +217 -0
- package/.claude/commands/TechieFlow/agents/verifier.md +72 -0
- package/.claude/commands/TechieFlow/tasks/_metrics-emit-gate.md +138 -0
- package/.claude/commands/TechieFlow/tasks/_smoke-test-policy.md +98 -0
- package/.claude/commands/TechieFlow/tasks/_status-update-gate.md +78 -0
- package/.claude/commands/TechieFlow/tasks/_yolo-mode.md +77 -0
- package/.claude/commands/TechieFlow/tasks/advanced-elicitation.md +117 -0
- package/.claude/commands/TechieFlow/tasks/amend-docs.md +149 -0
- package/.claude/commands/TechieFlow/tasks/author-brd.md +79 -0
- package/.claude/commands/TechieFlow/tasks/build-phase.md +231 -0
- package/.claude/commands/TechieFlow/tasks/create-deep-research-prompt.md +278 -0
- package/.claude/commands/TechieFlow/tasks/create-doc.md +101 -0
- package/.claude/commands/TechieFlow/tasks/day1-brownfield.md +507 -0
- package/.claude/commands/TechieFlow/tasks/day1-greenfield.md +224 -0
- package/.claude/commands/TechieFlow/tasks/devguide.md +224 -0
- package/.claude/commands/TechieFlow/tasks/document-project.md +343 -0
- package/.claude/commands/TechieFlow/tasks/execute-checklist.md +86 -0
- package/.claude/commands/TechieFlow/tasks/facilitate-brainstorming-session.md +136 -0
- package/.claude/commands/TechieFlow/tasks/fix-issues.md +134 -0
- package/.claude/commands/TechieFlow/tasks/generate-html.md +115 -0
- package/.claude/commands/TechieFlow/tasks/handoff-phase.md +126 -0
- package/.claude/commands/TechieFlow/tasks/index-docs.md +173 -0
- package/.claude/commands/TechieFlow/tasks/kb-mode-interaction.md +75 -0
- package/.claude/commands/TechieFlow/tasks/log-miss.md +160 -0
- package/.claude/commands/TechieFlow/tasks/metrics-report.md +143 -0
- package/.claude/commands/TechieFlow/tasks/mockups.md +122 -0
- package/.claude/commands/TechieFlow/tasks/productguide.md +105 -0
- package/.claude/commands/TechieFlow/tasks/refresh-status.md +135 -0
- package/.claude/commands/TechieFlow/tasks/render-workflow-docs.md +117 -0
- package/.claude/commands/TechieFlow/tasks/shard-doc.md +185 -0
- package/.claude/commands/TechieFlow/tasks/split-brd.md +131 -0
- package/.claude/commands/TechieFlow/tasks/triage-issues.md +157 -0
- package/.claude/commands/TechieFlow/tasks/verify-phase.md +579 -0
- package/.claude/commands/generate-html.md +124 -0
- package/.codex/config.toml +46 -0
- package/.codex/hooks.json +63 -0
- package/.codex/rules/techieflow.rules +8 -0
- package/.opencode/command/generate-html.md +129 -0
- package/.opencode/plugin/techieflow.js +350 -0
- package/.tfcore/TOKEN-GUIDE.md +59 -0
- package/.tfcore/agents/analyst.md +97 -0
- package/.tfcore/agents/architect.md +84 -0
- package/.tfcore/agents/flow-master.md +217 -0
- package/.tfcore/agents/verifier.md +72 -0
- package/.tfcore/checklists/architect-checklist.md +438 -0
- package/.tfcore/core-config.yaml +47 -0
- package/.tfcore/data/brainstorming-techniques.md +36 -0
- package/.tfcore/data/elicitation-methods.md +154 -0
- package/.tfcore/data/techieflow-kb.md +807 -0
- package/.tfcore/data/technical-preferences.md +3 -0
- package/.tfcore/enhanced-ide-development-workflow.md +248 -0
- package/.tfcore/hooks/block-git.sh +301 -0
- package/.tfcore/hooks/codex-adapter.py +248 -0
- package/.tfcore/hooks/guard-artifacts.sh +101 -0
- package/.tfcore/hooks/guard-status-html.sh +102 -0
- package/.tfcore/hooks/guard-status.sh +124 -0
- package/.tfcore/hooks/guard-verify.sh +108 -0
- package/.tfcore/hooks/metrics-session.sh +129 -0
- package/.tfcore/hooks/session-pointer.sh +52 -0
- package/.tfcore/hooks/sweep-artifacts.sh +198 -0
- package/.tfcore/install-manifest.yaml +231 -0
- package/.tfcore/routing.yaml +105 -0
- package/.tfcore/tasks/_metrics-emit-gate.md +138 -0
- package/.tfcore/tasks/_smoke-test-policy.md +98 -0
- package/.tfcore/tasks/_status-update-gate.md +78 -0
- package/.tfcore/tasks/_yolo-mode.md +77 -0
- package/.tfcore/tasks/advanced-elicitation.md +117 -0
- package/.tfcore/tasks/amend-docs.md +149 -0
- package/.tfcore/tasks/author-brd.md +79 -0
- package/.tfcore/tasks/build-phase.md +231 -0
- package/.tfcore/tasks/create-deep-research-prompt.md +278 -0
- package/.tfcore/tasks/create-doc.md +101 -0
- package/.tfcore/tasks/day1-brownfield.md +507 -0
- package/.tfcore/tasks/day1-greenfield.md +224 -0
- package/.tfcore/tasks/devguide.md +224 -0
- package/.tfcore/tasks/document-project.md +343 -0
- package/.tfcore/tasks/execute-checklist.md +86 -0
- package/.tfcore/tasks/facilitate-brainstorming-session.md +136 -0
- package/.tfcore/tasks/fix-issues.md +134 -0
- package/.tfcore/tasks/generate-html.md +115 -0
- package/.tfcore/tasks/handoff-phase.md +126 -0
- package/.tfcore/tasks/index-docs.md +173 -0
- package/.tfcore/tasks/kb-mode-interaction.md +75 -0
- package/.tfcore/tasks/log-miss.md +160 -0
- package/.tfcore/tasks/metrics-report.md +143 -0
- package/.tfcore/tasks/mockups.md +122 -0
- package/.tfcore/tasks/productguide.md +105 -0
- package/.tfcore/tasks/refresh-status.md +135 -0
- package/.tfcore/tasks/render-workflow-docs.md +117 -0
- package/.tfcore/tasks/shard-doc.md +185 -0
- package/.tfcore/tasks/split-brd.md +131 -0
- package/.tfcore/tasks/triage-issues.md +157 -0
- package/.tfcore/tasks/verify-phase.md +579 -0
- package/.tfcore/telemetry/SCHEMA.md +678 -0
- package/.tfcore/telemetry/install-metrics.sh +390 -0
- package/.tfcore/telemetry/pre-commit +94 -0
- package/.tfcore/telemetry/tf-metrics.sh +1415 -0
- package/.tfcore/templates/architecture-tmpl.yaml +650 -0
- package/.tfcore/templates/brainstorming-output-tmpl.yaml +156 -0
- package/.tfcore/templates/brownfield-architecture-tmpl.yaml +476 -0
- package/.tfcore/templates/competitor-analysis-tmpl.yaml +306 -0
- package/.tfcore/templates/front-end-architecture-tmpl.yaml +218 -0
- package/.tfcore/templates/fullstack-architecture-tmpl.yaml +823 -0
- package/.tfcore/templates/market-research-tmpl.yaml +252 -0
- package/.tfcore/templates/project-brief-tmpl.yaml +221 -0
- package/.tfcore/templates/v4custom/app-agents-md-tmpl.md +61 -0
- package/.tfcore/templates/v4custom/app-architecture-tmpl.md +127 -0
- package/.tfcore/templates/v4custom/app-brd-tmpl.md +204 -0
- package/.tfcore/templates/v4custom/app-checklist-tmpl.md +90 -0
- package/.tfcore/templates/v4custom/app-claude-md-tmpl.md +33 -0
- package/.tfcore/templates/v4custom/app-devguide-tmpl.md +167 -0
- package/.tfcore/templates/v4custom/app-editorconfig-tmpl.editorconfig +44 -0
- package/.tfcore/templates/v4custom/app-library-feedback-tmpl.md +31 -0
- package/.tfcore/templates/v4custom/app-productguide-tmpl.md +54 -0
- package/.tfcore/templates/v4custom/app-project-status-tmpl.md +98 -0
- package/.tfcore/templates/v4custom/app-uidesign-tmpl.md +48 -0
- package/.tfcore/templates/v4custom/app-usageguide-tmpl.md +67 -0
- package/.tfcore/templates/v4custom/build-invocation-ladder.md +190 -0
- package/.tfcore/templates/v4custom/html-render-shell.md +502 -0
- package/.tfcore/templates/v4custom/metrics-report-template.md +273 -0
- package/.tfcore/templates/v4custom/opencode-operating-contract.md +56 -0
- package/.tfcore/user-guide.md +633 -0
- package/.tfcore/utils/techieflow-doc-template.md +325 -0
- package/.tfcore/utils/tf-assets.sh +310 -0
- package/.tfcore/utils/tf-codex-bind.py +196 -0
- package/.tfcore/utils/tf-codex-telemetry.py +60 -0
- package/.tfcore/utils/tf-emit.sh +1075 -0
- package/.tfcore/utils/tf-gitignore-audit.sh +281 -0
- package/.tfcore/utils/tf-goal.sh +421 -0
- package/.tfcore/utils/tf-harness.sh +160 -0
- package/.tfcore/utils/tf-mockup-parity.mjs +555 -0
- package/.tfcore/utils/tf-mockup-parity.sh +65 -0
- package/.tfcore/utils/tf-opencode-audit.py +126 -0
- package/.tfcore/utils/tf-perf.sh +241 -0
- package/.tfcore/utils/tf-render-html.py +715 -0
- package/.tfcore/utils/tf-render-html.sh +28 -0
- package/.tfcore/utils/tf-routing-bind.sh +216 -0
- package/.tfcore/utils/tf-routing.sh +247 -0
- package/.tfcore/utils/tf-yolo.sh +119 -0
- package/.tfcore/working-in-the-brownfield.md +606 -0
- package/LICENSE +201 -0
- package/README.md +1212 -0
- package/WORKFLOW.html +1986 -0
- package/docs/TechieFlow-Installation.md +299 -0
- package/opencode.jsonc +929 -0
- package/package.json +60 -0
- package/scripts/install.mjs +992 -0
- package/scripts/test-install.mjs +505 -0
- package/scripts/validate.mjs +155 -0
|
@@ -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
|