Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@

Portable, installable workflow enforcement system for Claude Code. One setup script installs the entire spec→hook→test→PR pipeline with full audit trail. Includes enforceable workflows — ordered step pipelines backed by hooks.

## Status: Complete
## Status: In Progress

All tasks done. Deployed to all 4 workers. 12-page evidence PDF.
## Active

- [x] T027 Fresh deployment evidence report (Linux EC2)
- Provisioned fresh Ubuntu 22.04 EC2 (i-05bc762ad4d8c37fc, 3.129.204.76)
- Installed xvfb + xterm + scrot for REAL screen captures
- Phase A: Native — 10 real xterm screenshots, all hooks firing correctly
- Phase B: Docker — 10 real xterm screenshots from inside container b4b099a6e5af
- 15-page PDF: reports/shtd_flow_evidence_20260403_220200.pdf (776 KB)
- EC2 terminated after evidence captured

## Completed

Expand All @@ -19,3 +27,4 @@ All tasks done. Deployed to all 4 workers. 12-page evidence PDF.
- [x] T024 Deploy fixed hooks to all 4 CCC workers (PR #2)
- [x] T025 Tighten allowed-paths regex — `/test/i` was too broad (PR #3)
- [x] Reinstalled locally + redeployed T025 fix to all 4 workers
- [x] T026 Code review: DRY worker config, archive stale scripts, tighten audit regex (PR #4)
28 changes: 28 additions & 0 deletions reports/evidence-docker/01-install-check.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:53 UTC
│ Mode: docker | Host: 3349f9d04ca6 | IP: 18.116.59.247
│ User: root | Node: v20.20.2 | Python: 3.10.12
│ Container: 3349f9d04ca6
└─────────────────────────────────────────────────────────────

$ bash install.sh --check


=== Verifying SHTD Flow installation ===
[OK] lib/audit.js
[OK] lib/task_claims.py
[OK] lib/workflow.js
[OK] lib/get-audit.js
[OK] lib/allowed-paths.js
[OK] PreToolUse/shtd_spec-gate.js
[OK] PreToolUse/shtd_test-first-gate.js
[OK] PreToolUse/shtd_branch-gate.js
[OK] PreToolUse/shtd_pr-per-task-gate.js
[OK] PreToolUse/shtd_e2e-merge-gate.js
[OK] PreToolUse/shtd_remote-tracking-gate.js
[OK] PreToolUse/shtd_secret-scan-gate.js
[OK] PreToolUse/shtd_task-claim.js
[OK] PreToolUse/shtd_workflow-gate.js
[OK] PostToolUse/shtd_audit-logger.js
[OK] Stop/shtd_task-release.js
[OK] rules/shtd-audit-log.md
17 changes: 17 additions & 0 deletions reports/evidence-docker/02-branch-gate-block.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:53 UTC
│ Mode: docker | Host: 3349f9d04ca6 | IP: 18.116.59.247
│ User: root | Node: v20.20.2 | Python: 3.10.12
│ Container: 3349f9d04ca6
└─────────────────────────────────────────────────────────────

$ git branch
* master

>>> Simulating Claude Write to src/app.js on main branch <<<
Hook result: {
"decision": "block",
"reason": "[shtd] On master branch. Create a feature branch first: git checkout -b <NNN>-<feature-name>"
}

✗ BLOCKED: [shtd] On master branch. Create a feature branch first: git checkout -b <NNN>-<feature-name>
18 changes: 18 additions & 0 deletions reports/evidence-docker/03-spec-gate-block.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:53 UTC
│ Mode: docker | Host: 3349f9d04ca6 | IP: 18.116.59.247
│ User: root | Node: v20.20.2 | Python: 3.10.12
│ Container: 3349f9d04ca6
└─────────────────────────────────────────────────────────────

$ git branch
* 001-test-feature
master

>>> Simulating Claude Write to src/app.js without specs/ <<<
Hook result: {
"decision": "block",
"reason": "[shtd] No specs/ directory. Create a spec first: specs/<NNN>-<feature>/spec.md"
}

✗ BLOCKED: [shtd] No specs/ directory. Create a spec first: specs/<NNN>-<feature>/spec.md
13 changes: 13 additions & 0 deletions reports/evidence-docker/04-spec-gate-allow.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:53 UTC
│ Mode: docker | Host: 3349f9d04ca6 | IP: 18.116.59.247
│ User: root | Node: v20.20.2 | Python: 3.10.12
│ Container: 3349f9d04ca6
└─────────────────────────────────────────────────────────────

$ ls specs/
001-test-feature

>>> Simulating Claude Write to src/app.js WITH specs/ <<<
Hook result: null
✓ ALLOWED
18 changes: 18 additions & 0 deletions reports/evidence-docker/05-tracking-gate-block.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:53 UTC
│ Mode: docker | Host: 3349f9d04ca6 | IP: 18.116.59.247
│ User: root | Node: v20.20.2 | Python: 3.10.12
│ Container: 3349f9d04ca6
└─────────────────────────────────────────────────────────────

$ git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>&1 || echo 'No upstream'
fatal: no upstream configured for branch '001-test-feature'
No upstream

>>> Simulating Claude Write on untracked feature branch <<<
Hook result: {
"decision": "block",
"reason": "[shtd] Branch \"001-test-feature\" doesn't track a remote. Run: git push -u origin 001-test-feature"
}

✗ BLOCKED: [shtd] Branch "001-test-feature" doesn't track a remote. Run: git push -u origin 001-test-feature
17 changes: 17 additions & 0 deletions reports/evidence-docker/06-secret-scan-block.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:53 UTC
│ Mode: docker | Host: 3349f9d04ca6 | IP: 18.116.59.247
│ User: root | Node: v20.20.2 | Python: 3.10.12
│ Container: 3349f9d04ca6
└─────────────────────────────────────────────────────────────

$ ls .github/workflows/ 2>/dev/null || echo 'No workflows dir'
No workflows dir

>>> Simulating Claude Bash: git push origin main <<<
Hook result: {
"decision": "block",
"reason": "[shtd] No .github/workflows/secret-scan.yml. Add a secret scan CI workflow before pushing."
}

✗ BLOCKED: [shtd] No .github/workflows/secret-scan.yml. Add a secret scan CI workflow before pushing.
18 changes: 18 additions & 0 deletions reports/evidence-docker/07-pr-task-gate.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:53 UTC
│ Mode: docker | Host: 3349f9d04ca6 | IP: 18.116.59.247
│ User: root | Node: v20.20.2 | Python: 3.10.12
│ Container: 3349f9d04ca6
└─────────────────────────────────────────────────────────────

>>> Simulating Claude Bash: gh pr create --title 'Add feature' <<<
Hook result: {
"decision": "block",
"reason": "[shtd] PR title must include task ID (e.g. \"T001: Add config parser\"). One PR per task."
}

✗ BLOCKED: [shtd] PR title must include task ID (e.g. "T001: Add config parser"). One PR per task.

>>> Now with task ID: gh pr create --title 'T001: Add feature' <<<
Hook result: null
✓ ALLOWED
18 changes: 18 additions & 0 deletions reports/evidence-docker/08-e2e-merge-gate.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:53 UTC
│ Mode: docker | Host: 3349f9d04ca6 | IP: 18.116.59.247
│ User: root | Node: v20.20.2 | Python: 3.10.12
│ Container: 3349f9d04ca6
└─────────────────────────────────────────────────────────────

>>> Simulating Claude Bash: gh pr merge on feature branch 001-test-feature <<<
Hook result: {
"decision": "block",
"reason": "[shtd] Feature branch \"001-test-feature\" has no E2E test results. Run integration tests and create .test-results/001-test-feature.passed before merging to main."
}

✗ BLOCKED: [shtd] Feature branch "001-test-feature" has no E2E test results. Run integration tests and create .test-results/001-test-feature.passed before merging to main.

>>> Now with .test-results/001-test-feature.passed <<<
Hook result: null
✓ ALLOWED
30 changes: 30 additions & 0 deletions reports/evidence-docker/09-workflow-gate.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:53 UTC
│ Mode: docker | Host: 3349f9d04ca6 | IP: 18.116.59.247
│ User: root | Node: v20.20.2 | Python: 3.10.12
│ Container: 3349f9d04ca6
└─────────────────────────────────────────────────────────────

Workflow started. Current step: build
State: {
"workflow": "test-pipeline",
"workflow_path": "/tmp/shtd-test-project/workflows/test-pipeline.yml",
"started_at": "2026-04-04T02:48:53.799Z",
"steps": {
"build": {
"status": "pending"
},
"test": {
"status": "pending"
},
"deploy": {
"status": "pending"
}
}
}

>>> Attempting to Write during 'deploy' step (should block — build not done) <<<
Build step completed. Current step: test

Hook result: null
✓ ALLOWED (test step gate satisfied — build is done)
13 changes: 13 additions & 0 deletions reports/evidence-docker/10-audit-log.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:53 UTC
│ Mode: docker | Host: 3349f9d04ca6 | IP: 18.116.59.247
│ User: root | Node: v20.20.2 | Python: 3.10.12
│ Container: 3349f9d04ca6
└─────────────────────────────────────────────────────────────

$ tail -20 /root/.claude/shtd-flow/audit.jsonl
{"ts":"2026-04-04T02:48:53.263Z","event":"code_blocked","project":"shtd-test-project","session":"","pid":4062,"reason":"no_specs_dir","file":"app.js"}
{"ts":"2026-04-04T02:48:53.686Z","event":"merge_blocked","project":"shtd-test-project","session":"","pid":4194,"reason":"no_e2e","branch":"001-test-feature"}

$ wc -l /root/.claude/shtd-flow/audit.jsonl
2 /root/.claude/shtd-flow/audit.jsonl
27 changes: 27 additions & 0 deletions reports/evidence-native/01-install-check.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:38 UTC
│ Mode: native | Host: ip-172-31-29-67 | IP: 18.116.59.247
│ User: ubuntu | Node: v20.20.2 | Python: 3.10.12
└─────────────────────────────────────────────────────────────

$ bash install.sh --check


=== Verifying SHTD Flow installation ===
[OK] lib/audit.js
[OK] lib/task_claims.py
[OK] lib/workflow.js
[OK] lib/get-audit.js
[OK] lib/allowed-paths.js
[OK] PreToolUse/shtd_spec-gate.js
[OK] PreToolUse/shtd_test-first-gate.js
[OK] PreToolUse/shtd_branch-gate.js
[OK] PreToolUse/shtd_pr-per-task-gate.js
[OK] PreToolUse/shtd_e2e-merge-gate.js
[OK] PreToolUse/shtd_remote-tracking-gate.js
[OK] PreToolUse/shtd_secret-scan-gate.js
[OK] PreToolUse/shtd_task-claim.js
[OK] PreToolUse/shtd_workflow-gate.js
[OK] PostToolUse/shtd_audit-logger.js
[OK] Stop/shtd_task-release.js
[OK] rules/shtd-audit-log.md
16 changes: 16 additions & 0 deletions reports/evidence-native/02-branch-gate-block.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:38 UTC
│ Mode: native | Host: ip-172-31-29-67 | IP: 18.116.59.247
│ User: ubuntu | Node: v20.20.2 | Python: 3.10.12
└─────────────────────────────────────────────────────────────

$ git branch
* master

>>> Simulating Claude Write to src/app.js on main branch <<<
Hook result: {
"decision": "block",
"reason": "[shtd] On master branch. Create a feature branch first: git checkout -b <NNN>-<feature-name>"
}

✗ BLOCKED: [shtd] On master branch. Create a feature branch first: git checkout -b <NNN>-<feature-name>
17 changes: 17 additions & 0 deletions reports/evidence-native/03-spec-gate-block.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:38 UTC
│ Mode: native | Host: ip-172-31-29-67 | IP: 18.116.59.247
│ User: ubuntu | Node: v20.20.2 | Python: 3.10.12
└─────────────────────────────────────────────────────────────

$ git branch
* 001-test-feature
master

>>> Simulating Claude Write to src/app.js without specs/ <<<
Hook result: {
"decision": "block",
"reason": "[shtd] No specs/ directory. Create a spec first: specs/<NNN>-<feature>/spec.md"
}

✗ BLOCKED: [shtd] No specs/ directory. Create a spec first: specs/<NNN>-<feature>/spec.md
12 changes: 12 additions & 0 deletions reports/evidence-native/04-spec-gate-allow.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:38 UTC
│ Mode: native | Host: ip-172-31-29-67 | IP: 18.116.59.247
│ User: ubuntu | Node: v20.20.2 | Python: 3.10.12
└─────────────────────────────────────────────────────────────

$ ls specs/
001-test-feature

>>> Simulating Claude Write to src/app.js WITH specs/ <<<
Hook result: null
✓ ALLOWED
17 changes: 17 additions & 0 deletions reports/evidence-native/05-tracking-gate-block.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:38 UTC
│ Mode: native | Host: ip-172-31-29-67 | IP: 18.116.59.247
│ User: ubuntu | Node: v20.20.2 | Python: 3.10.12
└─────────────────────────────────────────────────────────────

$ git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>&1 || echo 'No upstream'
fatal: no upstream configured for branch '001-test-feature'
No upstream

>>> Simulating Claude Write on untracked feature branch <<<
Hook result: {
"decision": "block",
"reason": "[shtd] Branch \"001-test-feature\" doesn't track a remote. Run: git push -u origin 001-test-feature"
}

✗ BLOCKED: [shtd] Branch "001-test-feature" doesn't track a remote. Run: git push -u origin 001-test-feature
16 changes: 16 additions & 0 deletions reports/evidence-native/06-secret-scan-block.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:38 UTC
│ Mode: native | Host: ip-172-31-29-67 | IP: 18.116.59.247
│ User: ubuntu | Node: v20.20.2 | Python: 3.10.12
└─────────────────────────────────────────────────────────────

$ ls .github/workflows/ 2>/dev/null || echo 'No workflows dir'
No workflows dir

>>> Simulating Claude Bash: git push origin main <<<
Hook result: {
"decision": "block",
"reason": "[shtd] No .github/workflows/secret-scan.yml. Add a secret scan CI workflow before pushing."
}

✗ BLOCKED: [shtd] No .github/workflows/secret-scan.yml. Add a secret scan CI workflow before pushing.
17 changes: 17 additions & 0 deletions reports/evidence-native/07-pr-task-gate.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:39 UTC
│ Mode: native | Host: ip-172-31-29-67 | IP: 18.116.59.247
│ User: ubuntu | Node: v20.20.2 | Python: 3.10.12
└─────────────────────────────────────────────────────────────

>>> Simulating Claude Bash: gh pr create --title 'Add feature' <<<
Hook result: {
"decision": "block",
"reason": "[shtd] PR title must include task ID (e.g. \"T001: Add config parser\"). One PR per task."
}

✗ BLOCKED: [shtd] PR title must include task ID (e.g. "T001: Add config parser"). One PR per task.

>>> Now with task ID: gh pr create --title 'T001: Add feature' <<<
Hook result: null
✓ ALLOWED
17 changes: 17 additions & 0 deletions reports/evidence-native/08-e2e-merge-gate.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
┌─────────────────────────────────────────────────────────────
│ SHTD Flow Evidence — 2026-04-04 02:48:39 UTC
│ Mode: native | Host: ip-172-31-29-67 | IP: 18.116.59.247
│ User: ubuntu | Node: v20.20.2 | Python: 3.10.12
└─────────────────────────────────────────────────────────────

>>> Simulating Claude Bash: gh pr merge on feature branch 001-test-feature <<<
Hook result: {
"decision": "block",
"reason": "[shtd] Feature branch \"001-test-feature\" has no E2E test results. Run integration tests and create .test-results/001-test-feature.passed before merging to main."
}

✗ BLOCKED: [shtd] Feature branch "001-test-feature" has no E2E test results. Run integration tests and create .test-results/001-test-feature.passed before merging to main.

>>> Now with .test-results/001-test-feature.passed <<<
Hook result: null
✓ ALLOWED
Loading
Loading