create-ccc-tutor 0.1.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 (106) hide show
  1. package/README.md +41 -0
  2. package/bin/cli.js +76 -0
  3. package/package.json +28 -0
  4. package/template/.claude/commands/abandon.md +7 -0
  5. package/template/.claude/commands/add-anti-flag.md +7 -0
  6. package/template/.claude/commands/add-constitution-clause.md +7 -0
  7. package/template/.claude/commands/audit-spec.md +7 -0
  8. package/template/.claude/commands/commit.md +7 -0
  9. package/template/.claude/commands/constitution-edit.md +7 -0
  10. package/template/.claude/commands/db-schema.md +7 -0
  11. package/template/.claude/commands/exam.md +66 -0
  12. package/template/.claude/commands/execution-plan.md +7 -0
  13. package/template/.claude/commands/feature-draft.md +7 -0
  14. package/template/.claude/commands/handoff.md +7 -0
  15. package/template/.claude/commands/implement.md +7 -0
  16. package/template/.claude/commands/init.md +7 -0
  17. package/template/.claude/commands/next.md +7 -0
  18. package/template/.claude/commands/offload.md +7 -0
  19. package/template/.claude/commands/pickup.md +7 -0
  20. package/template/.claude/commands/recall.md +7 -0
  21. package/template/.claude/commands/remember.md +7 -0
  22. package/template/.claude/commands/slide.md +87 -0
  23. package/template/.claude/commands/spec-finalize.md +7 -0
  24. package/template/.claude/commands/test-fix.md +7 -0
  25. package/template/.claude/commands/uninstall.md +7 -0
  26. package/template/.claude/settings.json +161 -0
  27. package/template/.claude-plugin/plugin.json +41 -0
  28. package/template/.codex/config.toml +24 -0
  29. package/template/.codex/hooks.json +4 -0
  30. package/template/.codex/install-skills.sh +18 -0
  31. package/template/.codex/skills/exam/SKILL.md +61 -0
  32. package/template/.codex/skills/slide/SKILL.md +69 -0
  33. package/template/.harness/agents/README.md +70 -0
  34. package/template/.harness/agents/_template/junior-agent-template.md +116 -0
  35. package/template/.harness/agents/backend-reviewer.md +153 -0
  36. package/template/.harness/agents/frontend-reviewer.md +158 -0
  37. package/template/.harness/agents/security-reviewer.md +148 -0
  38. package/template/.harness/agents/test-fixer.md +147 -0
  39. package/template/.harness/docs/doc-sync.md +29 -0
  40. package/template/.harness/docs/git-hygiene.md +56 -0
  41. package/template/.harness/docs/spec-model.md +47 -0
  42. package/template/.harness/docs/tool-map.md +120 -0
  43. package/template/.harness/docs/workflow.md +59 -0
  44. package/template/.harness/scripts/README.md +70 -0
  45. package/template/.harness/scripts/auditor-gate.sh +388 -0
  46. package/template/.harness/scripts/bootstrap-check.sh +103 -0
  47. package/template/.harness/scripts/budget-monitor.sh +223 -0
  48. package/template/.harness/scripts/check-prereqs.sh +165 -0
  49. package/template/.harness/scripts/checkpoint-recall.sh +136 -0
  50. package/template/.harness/scripts/checkpoint-write.sh +281 -0
  51. package/template/.harness/scripts/decision-log-append.sh +90 -0
  52. package/template/.harness/scripts/env-check.sh +286 -0
  53. package/template/.harness/scripts/format-edit.sh +80 -0
  54. package/template/.harness/scripts/lint-bans.sh +110 -0
  55. package/template/.harness/scripts/memory-archive.sh +129 -0
  56. package/template/.harness/scripts/memory-recall.sh +197 -0
  57. package/template/.harness/scripts/memory-snapshot.sh +124 -0
  58. package/template/.harness/scripts/post-migration.sh +58 -0
  59. package/template/.harness/scripts/precommit-cycles.sh +74 -0
  60. package/template/.harness/scripts/precommit-typecheck.sh +69 -0
  61. package/template/.harness/scripts/scratchpad-recall.sh +83 -0
  62. package/template/.harness/scripts/scratchpad-update.sh +39 -0
  63. package/template/.harness/scripts/standalone-bootstrap.md +443 -0
  64. package/template/.harness/skills/abandon/SKILL.md +157 -0
  65. package/template/.harness/skills/add-anti-flag/SKILL.md +205 -0
  66. package/template/.harness/skills/add-constitution-clause/SKILL.md +244 -0
  67. package/template/.harness/skills/audit-spec/SKILL.md +395 -0
  68. package/template/.harness/skills/commit/SKILL.md +270 -0
  69. package/template/.harness/skills/constitution-edit/SKILL.md +292 -0
  70. package/template/.harness/skills/db-schema/SKILL.md +145 -0
  71. package/template/.harness/skills/db-schema/references/methodology.md +202 -0
  72. package/template/.harness/skills/execution-plan/SKILL.md +346 -0
  73. package/template/.harness/skills/feature-draft/SKILL.md +426 -0
  74. package/template/.harness/skills/handoff/SKILL.md +211 -0
  75. package/template/.harness/skills/implement/SKILL.md +355 -0
  76. package/template/.harness/skills/init/SKILL.md +805 -0
  77. package/template/.harness/skills/next/SKILL.md +245 -0
  78. package/template/.harness/skills/offload/SKILL.md +134 -0
  79. package/template/.harness/skills/pickup/SKILL.md +213 -0
  80. package/template/.harness/skills/recall/SKILL.md +159 -0
  81. package/template/.harness/skills/remember/SKILL.md +205 -0
  82. package/template/.harness/skills/spec-finalize/SKILL.md +196 -0
  83. package/template/.harness/skills/test-fix/SKILL.md +363 -0
  84. package/template/.harness/skills/uninstall/SKILL.md +370 -0
  85. package/template/.harness/state/install.json +83 -0
  86. package/template/AGENTS.md +262 -0
  87. package/template/CCC_MAGI_LICENSE +201 -0
  88. package/template/CCC_MAGI_README.md +986 -0
  89. package/template/CLAUDE.md +658 -0
  90. package/template/codex.md +39 -0
  91. package/template/constitution.md +164 -0
  92. package/template/course/README.md +15 -0
  93. package/template/course/course_code(example)/exam/README.md +2 -0
  94. package/template/course/course_code(example)/slide/slide_example-1.pdf +40 -0
  95. package/template/course/course_code(example)/slide/slide_example-2.pdf +40 -0
  96. package/template/docs/features/slide-query-implementation.md +79 -0
  97. package/template/docs/features/slide-query.md +211 -0
  98. package/template/docs-harness/README.md +42 -0
  99. package/template/docs-harness/adoption-playbook.md +373 -0
  100. package/template/docs-harness/ccc-step1-driver-template.md +288 -0
  101. package/template/docs-harness/cli-configs-README.md +78 -0
  102. package/template/docs-harness/context-architecture-v2.md +249 -0
  103. package/template/docs-harness/design-spec.md +437 -0
  104. package/template/docs-harness/memory-layer.md +135 -0
  105. package/template/docs-harness/retrospective-notes.md +204 -0
  106. package/template/gitignore +106 -0
@@ -0,0 +1,281 @@
1
+ #!/usr/bin/env bash
2
+ # checkpoint-write.sh — atomic writer for .harness/state/workflow-checkpoints/<feature>.json
3
+ #
4
+ # Called by every stage skill at its successful completion. Centralizes the
5
+ # checkpoint schema (single source of truth — change schema here, all skills
6
+ # inherit it). Per Phase 5 (Session resume) of the v0.9.0 release.
7
+ #
8
+ # USAGE:
9
+ # checkpoint-write.sh --feature <slug> [options]
10
+ #
11
+ # OPTIONS:
12
+ # --feature <slug> Required. Feature slug (matches branch name suffix).
13
+ # --branch <name> Override detected branch (default: current git branch).
14
+ # --mode <new-feature|audit> Workflow mode (default: new-feature).
15
+ # --lane <full|stability-fix|trivial> Workflow lane (default: full).
16
+ # --stage <N> Set current_stage to N.
17
+ # --stage-complete <N> Mark stage N as complete (append to stages_completed).
18
+ # --stage-skip <N> --skip-reason <text> Mark stage N as skipped with reason.
19
+ # --artifact-spec <path> Record spec artifact path (computes sha256).
20
+ # --artifact-implementation <path> Record implementation-doc artifact path.
21
+ # --artifact-plan <path> Record execution-plan artifact path.
22
+ # --artifact-schema <path> Record schema artifact path.
23
+ # --append-audit '<json>' Append one audit entry. JSON: {"stage":N,"verdict":"...","risk":N,"at":"<iso>"}
24
+ # --stage-in-progress '<json>' Replace stage_in_progress block. JSON: {"stage_number":N,"files_total":N,...}
25
+ # --file-done <path> Append one path to stage_in_progress.files_done_list (idempotent: dedupe).
26
+ # --append-decision '<json>' Append one decision entry. JSON: {"at":"...","stage":N,"by":"CEO","decision":"..."}
27
+ # --archive Move checkpoint to _archived/<feature>-<timestamp>.json (used by /commit).
28
+ # --create-if-missing Create a minimal checkpoint if file doesn't exist (used by /feature-draft as first stage).
29
+ #
30
+ # OUTPUT:
31
+ # - On success: prints "✓ checkpoint updated: <path>" to stdout, exits 0.
32
+ # - On error: prints error to stderr, exits 1.
33
+ #
34
+ # DESIGN NOTES:
35
+ # - Atomic write: tmp + rename (won't leave half-written checkpoint).
36
+ # - Idempotent: rerunning the same call doesn't duplicate stages/files.
37
+ # - Schema versioning: bumps schema_version if needed, refuses to write older schema over newer.
38
+ # - jq is required.
39
+
40
+ set -euo pipefail
41
+ export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
42
+
43
+ if ! command -v jq >/dev/null 2>&1; then
44
+ echo "checkpoint-write.sh requires jq. Install with: brew install jq" >&2
45
+ exit 1
46
+ fi
47
+
48
+ # ─── Defaults / state ──────────────────────────────────────────────────
49
+ SCHEMA_VERSION=1
50
+ FEATURE=""
51
+ BRANCH=""
52
+ MODE=""
53
+ LANE=""
54
+ SET_STAGE=""
55
+ COMPLETE_STAGE=""
56
+ SKIP_STAGE=""
57
+ SKIP_REASON=""
58
+ ARTIFACT_SPEC=""
59
+ ARTIFACT_IMPL=""
60
+ ARTIFACT_PLAN=""
61
+ ARTIFACT_SCHEMA=""
62
+ APPEND_AUDIT=""
63
+ STAGE_IN_PROGRESS=""
64
+ FILE_DONE=""
65
+ APPEND_DECISION=""
66
+ ARCHIVE=false
67
+ CREATE_IF_MISSING=false
68
+
69
+ # ─── Parse args ────────────────────────────────────────────────────────
70
+ while [ "$#" -gt 0 ]; do
71
+ case "$1" in
72
+ --feature) FEATURE="$2"; shift 2 ;;
73
+ --branch) BRANCH="$2"; shift 2 ;;
74
+ --mode) MODE="$2"; shift 2 ;;
75
+ --lane) LANE="$2"; shift 2 ;;
76
+ --stage) SET_STAGE="$2"; shift 2 ;;
77
+ --stage-complete) COMPLETE_STAGE="$2"; shift 2 ;;
78
+ --stage-skip) SKIP_STAGE="$2"; shift 2 ;;
79
+ --skip-reason) SKIP_REASON="$2"; shift 2 ;;
80
+ --artifact-spec) ARTIFACT_SPEC="$2"; shift 2 ;;
81
+ --artifact-implementation) ARTIFACT_IMPL="$2"; shift 2 ;;
82
+ --artifact-plan) ARTIFACT_PLAN="$2"; shift 2 ;;
83
+ --artifact-schema) ARTIFACT_SCHEMA="$2"; shift 2 ;;
84
+ --append-audit) APPEND_AUDIT="$2"; shift 2 ;;
85
+ --stage-in-progress) STAGE_IN_PROGRESS="$2"; shift 2 ;;
86
+ --file-done) FILE_DONE="$2"; shift 2 ;;
87
+ --append-decision) APPEND_DECISION="$2"; shift 2 ;;
88
+ --archive) ARCHIVE=true; shift ;;
89
+ --create-if-missing) CREATE_IF_MISSING=true; shift ;;
90
+ *)
91
+ echo "Unknown arg: $1" >&2
92
+ exit 1
93
+ ;;
94
+ esac
95
+ done
96
+
97
+ if [ -z "$FEATURE" ]; then
98
+ echo "checkpoint-write.sh: --feature <slug> required" >&2
99
+ exit 1
100
+ fi
101
+
102
+ CHECKPOINT_DIR=".harness/state/workflow-checkpoints"
103
+ CHECKPOINT_FILE="$CHECKPOINT_DIR/${FEATURE}.json"
104
+ mkdir -p "$CHECKPOINT_DIR"
105
+
106
+ NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
107
+
108
+ # Detect branch if not provided
109
+ if [ -z "$BRANCH" ]; then
110
+ BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo "(no branch)")
111
+ fi
112
+
113
+ # ─── Archive mode (used by /commit at Stage 8) ─────────────────────────
114
+ if [ "$ARCHIVE" = "true" ]; then
115
+ if [ ! -f "$CHECKPOINT_FILE" ]; then
116
+ echo "✓ checkpoint not found for $FEATURE (already archived or never created); no-op"
117
+ exit 0
118
+ fi
119
+ ARCHIVE_DIR="$CHECKPOINT_DIR/_archived"
120
+ mkdir -p "$ARCHIVE_DIR"
121
+ ARCHIVED_FILE="$ARCHIVE_DIR/${FEATURE}-$(date -u +%Y%m%dT%H%M%SZ).json"
122
+ mv "$CHECKPOINT_FILE" "$ARCHIVED_FILE"
123
+ echo "✓ checkpoint archived: $ARCHIVED_FILE"
124
+ exit 0
125
+ fi
126
+
127
+ # ─── Create-if-missing (initial checkpoint from /feature-draft Stage 1) ───
128
+ if [ ! -f "$CHECKPOINT_FILE" ]; then
129
+ if [ "$CREATE_IF_MISSING" = "true" ]; then
130
+ INIT_MODE="${MODE:-new-feature}"
131
+ INIT_LANE="${LANE:-full}"
132
+ INIT_STAGE="${SET_STAGE:-1}"
133
+ jq -n \
134
+ --argjson schema_version "$SCHEMA_VERSION" \
135
+ --arg feature "$FEATURE" \
136
+ --arg branch "$BRANCH" \
137
+ --arg started_at "$NOW" \
138
+ --arg last_at "$NOW" \
139
+ --arg mode "$INIT_MODE" \
140
+ --arg lane "$INIT_LANE" \
141
+ --argjson stage "$INIT_STAGE" \
142
+ '{
143
+ schema_version: $schema_version,
144
+ feature: $feature,
145
+ feature_slug: $feature,
146
+ branch: $branch,
147
+ started_at: $started_at,
148
+ last_activity_at: $last_at,
149
+ mode: $mode,
150
+ lane: $lane,
151
+ current_stage: $stage,
152
+ stages_completed: [],
153
+ stages_skipped: [],
154
+ stages_skipped_reasons: {},
155
+ artifacts: { spec: null, implementation: null, plan: null, schema: null },
156
+ audits: [],
157
+ stage_in_progress: null,
158
+ decisions: [],
159
+ session_chain: []
160
+ }' > "$CHECKPOINT_FILE"
161
+ # Fall through to apply any additional updates from this call
162
+ else
163
+ echo "checkpoint-write.sh: $CHECKPOINT_FILE does not exist. Use --create-if-missing to bootstrap." >&2
164
+ exit 1
165
+ fi
166
+ fi
167
+
168
+ # ─── Atomic update via tmp + rename ────────────────────────────────────
169
+ TMP_FILE=$(mktemp "${CHECKPOINT_FILE}.tmp.XXXXXX")
170
+ trap 'rm -f "$TMP_FILE"' EXIT
171
+
172
+ # Build a jq filter chain that applies all requested mutations
173
+ JQ_FILTER='. | .last_activity_at = $now'
174
+
175
+ # Mode / lane updates
176
+ [ -n "$MODE" ] && JQ_FILTER="$JQ_FILTER | .mode = \$mode"
177
+ [ -n "$LANE" ] && JQ_FILTER="$JQ_FILTER | .lane = \$lane"
178
+ [ -n "$BRANCH" ] && JQ_FILTER="$JQ_FILTER | .branch = \$branch"
179
+
180
+ # Stage current
181
+ [ -n "$SET_STAGE" ] && JQ_FILTER="$JQ_FILTER | .current_stage = (\$set_stage | tonumber)"
182
+
183
+ # Complete stage (dedupe via unique)
184
+ [ -n "$COMPLETE_STAGE" ] && JQ_FILTER="$JQ_FILTER | .stages_completed = ((.stages_completed + [(\$complete_stage | tonumber)]) | unique)"
185
+
186
+ # Skip stage
187
+ if [ -n "$SKIP_STAGE" ]; then
188
+ JQ_FILTER="$JQ_FILTER | .stages_skipped = ((.stages_skipped + [(\$skip_stage | tonumber)]) | unique)"
189
+ if [ -n "$SKIP_REASON" ]; then
190
+ JQ_FILTER="$JQ_FILTER | .stages_skipped_reasons[\$skip_stage] = \$skip_reason"
191
+ fi
192
+ fi
193
+
194
+ # Portable sha256 (Mac uses shasum, Linux/Git-Bash use sha256sum)
195
+ portable_sha256() {
196
+ local path="$1"
197
+ if command -v sha256sum >/dev/null 2>&1; then
198
+ sha256sum "$path" 2>/dev/null | awk '{print $1}' | head -c 16
199
+ elif command -v shasum >/dev/null 2>&1; then
200
+ shasum -a 256 "$path" 2>/dev/null | awk '{print $1}' | head -c 16
201
+ elif command -v openssl >/dev/null 2>&1; then
202
+ openssl dgst -sha256 "$path" 2>/dev/null | awk '{print $NF}' | head -c 16
203
+ else
204
+ echo ""
205
+ fi
206
+ }
207
+
208
+ # Artifact paths (compute sha256 if file exists)
209
+ compute_artifact_block() {
210
+ local path="$1"
211
+ if [ -f "$path" ]; then
212
+ local sha
213
+ sha=$(portable_sha256 "$path")
214
+ jq -n --arg p "$path" --arg s "$sha" '{path: $p, sha256: $s, exists: true}'
215
+ else
216
+ jq -n --arg p "$path" '{path: $p, sha256: null, exists: false}'
217
+ fi
218
+ }
219
+
220
+ if [ -n "$ARTIFACT_SPEC" ]; then
221
+ ART_SPEC_JSON=$(compute_artifact_block "$ARTIFACT_SPEC")
222
+ JQ_FILTER="$JQ_FILTER | .artifacts.spec = \$art_spec"
223
+ fi
224
+ if [ -n "$ARTIFACT_IMPL" ]; then
225
+ ART_IMPL_JSON=$(compute_artifact_block "$ARTIFACT_IMPL")
226
+ JQ_FILTER="$JQ_FILTER | .artifacts.implementation = \$art_impl"
227
+ fi
228
+ if [ -n "$ARTIFACT_PLAN" ]; then
229
+ ART_PLAN_JSON=$(compute_artifact_block "$ARTIFACT_PLAN")
230
+ JQ_FILTER="$JQ_FILTER | .artifacts.plan = \$art_plan"
231
+ fi
232
+ if [ -n "$ARTIFACT_SCHEMA" ]; then
233
+ ART_SCHEMA_JSON=$(compute_artifact_block "$ARTIFACT_SCHEMA")
234
+ JQ_FILTER="$JQ_FILTER | .artifacts.schema = \$art_schema"
235
+ fi
236
+
237
+ # Append audit entry
238
+ if [ -n "$APPEND_AUDIT" ]; then
239
+ JQ_FILTER="$JQ_FILTER | .audits = (.audits + [\$append_audit])"
240
+ fi
241
+
242
+ # Replace stage_in_progress (full block)
243
+ if [ -n "$STAGE_IN_PROGRESS" ]; then
244
+ JQ_FILTER="$JQ_FILTER | .stage_in_progress = \$stage_in_progress"
245
+ fi
246
+
247
+ # Append single file to files_done_list (idempotent dedupe)
248
+ if [ -n "$FILE_DONE" ]; then
249
+ JQ_FILTER="$JQ_FILTER | .stage_in_progress = (.stage_in_progress // {stage_number: .current_stage, files_total: 0, files_done_list: [], files_remaining_list: [], last_action: null, resume_hint: null}) | .stage_in_progress.files_done_list = ((.stage_in_progress.files_done_list + [\$file_done]) | unique) | .stage_in_progress.last_action = (\"Wrote \" + \$file_done)"
250
+ fi
251
+
252
+ # Append decision entry
253
+ if [ -n "$APPEND_DECISION" ]; then
254
+ JQ_FILTER="$JQ_FILTER | .decisions = (.decisions + [\$append_decision])"
255
+ fi
256
+
257
+ # Build the jq invocation with all required --arg / --argjson
258
+ JQ_ARGS=(--arg now "$NOW")
259
+
260
+ [ -n "$MODE" ] && JQ_ARGS+=(--arg mode "$MODE")
261
+ [ -n "$LANE" ] && JQ_ARGS+=(--arg lane "$LANE")
262
+ [ -n "$BRANCH" ] && JQ_ARGS+=(--arg branch "$BRANCH")
263
+ [ -n "$SET_STAGE" ] && JQ_ARGS+=(--arg set_stage "$SET_STAGE")
264
+ [ -n "$COMPLETE_STAGE" ] && JQ_ARGS+=(--arg complete_stage "$COMPLETE_STAGE")
265
+ [ -n "$SKIP_STAGE" ] && JQ_ARGS+=(--arg skip_stage "$SKIP_STAGE")
266
+ [ -n "$SKIP_REASON" ] && JQ_ARGS+=(--arg skip_reason "$SKIP_REASON")
267
+ [ -n "$FILE_DONE" ] && JQ_ARGS+=(--arg file_done "$FILE_DONE")
268
+
269
+ [ -n "$ARTIFACT_SPEC" ] && JQ_ARGS+=(--argjson art_spec "$ART_SPEC_JSON")
270
+ [ -n "$ARTIFACT_IMPL" ] && JQ_ARGS+=(--argjson art_impl "$ART_IMPL_JSON")
271
+ [ -n "$ARTIFACT_PLAN" ] && JQ_ARGS+=(--argjson art_plan "$ART_PLAN_JSON")
272
+ [ -n "$ARTIFACT_SCHEMA" ] && JQ_ARGS+=(--argjson art_schema "$ART_SCHEMA_JSON")
273
+ [ -n "$APPEND_AUDIT" ] && JQ_ARGS+=(--argjson append_audit "$APPEND_AUDIT")
274
+ [ -n "$STAGE_IN_PROGRESS" ] && JQ_ARGS+=(--argjson stage_in_progress "$STAGE_IN_PROGRESS")
275
+ [ -n "$APPEND_DECISION" ] && JQ_ARGS+=(--argjson append_decision "$APPEND_DECISION")
276
+
277
+ jq "${JQ_ARGS[@]}" "$JQ_FILTER" "$CHECKPOINT_FILE" > "$TMP_FILE"
278
+ mv "$TMP_FILE" "$CHECKPOINT_FILE"
279
+ trap - EXIT
280
+
281
+ echo "✓ checkpoint updated: $CHECKPOINT_FILE"
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env bash
2
+ # decision-log-append.sh — appends a human-readable row to .harness/memory/decision-log.md
3
+ #
4
+ # Per BMAD-style decision-log pattern (the v0.9.0 "memory layer upgrade").
5
+ # Each call appends one line; file is gitignored (per-developer record).
6
+ #
7
+ # USAGE:
8
+ # decision-log-append.sh \
9
+ # --feature <slug> \
10
+ # --stage <N> \
11
+ # --by <CEO|MAGI-Core|MAGI-Verdict|MAGI-Planner|MAGI-Programmer|MAGI-Tester|MAGI-Reviewer|MAGI-Archivist|system> \
12
+ # --decision "<short prose>"
13
+ #
14
+ # OPTIONS:
15
+ # --feature <slug> Required. Feature slug.
16
+ # --stage <N> Required. Stage number (1-9) or word ("init", "audit", "config").
17
+ # --by <actor> Required. Who made the decision.
18
+ # --decision "<text>" Required. One-line description. ≤120 chars recommended.
19
+ # --evidence "<text>" Optional. Brief evidence / link / commit / verdict file.
20
+ #
21
+ # OUTPUT:
22
+ # - On success: prints "✓ decision logged" to stdout, exits 0.
23
+ # - On error: prints error to stderr, exits 1.
24
+
25
+ set -euo pipefail
26
+ export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
27
+
28
+ FEATURE=""
29
+ STAGE=""
30
+ BY=""
31
+ DECISION=""
32
+ EVIDENCE=""
33
+
34
+ while [ "$#" -gt 0 ]; do
35
+ case "$1" in
36
+ --feature) FEATURE="$2"; shift 2 ;;
37
+ --stage) STAGE="$2"; shift 2 ;;
38
+ --by) BY="$2"; shift 2 ;;
39
+ --decision) DECISION="$2"; shift 2 ;;
40
+ --evidence) EVIDENCE="$2"; shift 2 ;;
41
+ *)
42
+ echo "Unknown arg: $1" >&2
43
+ exit 1
44
+ ;;
45
+ esac
46
+ done
47
+
48
+ if [ -z "$FEATURE" ] || [ -z "$STAGE" ] || [ -z "$BY" ] || [ -z "$DECISION" ]; then
49
+ echo "decision-log-append.sh: --feature, --stage, --by, --decision all required" >&2
50
+ exit 1
51
+ fi
52
+
53
+ LOG_FILE=".harness/memory/decision-log.md"
54
+ mkdir -p "$(dirname "$LOG_FILE")"
55
+
56
+ # Initialize file with header if missing
57
+ if [ ! -f "$LOG_FILE" ]; then
58
+ cat > "$LOG_FILE" <<'HEADER'
59
+ # Decision Log
60
+
61
+ > Per-developer chronological log of workflow decisions. Each row captures
62
+ > WHO decided WHAT at WHICH stage of WHICH feature. Maintained automatically
63
+ > by stage skills + MAGI Archivist. Gitignored — your private project diary.
64
+ >
65
+ > Use cases:
66
+ > - Release-note source ("why we chose Redis over Memcached")
67
+ > - Onboarding new teammates (paste relevant rows into Slack/Wiki)
68
+ > - Post-mortem after incidents ("what did MAGI Verdict flag, did CEO accept?")
69
+ > - Quarterly review of personal decision quality
70
+
71
+ | Timestamp (UTC) | Feature | Stage | Actor | Decision | Evidence |
72
+ |-----------------|---------|-------|-------|----------|----------|
73
+ HEADER
74
+ fi
75
+
76
+ NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
77
+
78
+ # Escape pipe characters in text fields so they don't break the markdown table
79
+ escape_pipes() {
80
+ echo "$1" | sed 's/|/\\|/g'
81
+ }
82
+
83
+ DECISION_ESC=$(escape_pipes "$DECISION")
84
+ EVIDENCE_ESC=$(escape_pipes "${EVIDENCE:-—}")
85
+
86
+ printf "| %s | %s | %s | %s | %s | %s |\n" \
87
+ "$NOW" "$FEATURE" "$STAGE" "$BY" "$DECISION_ESC" "$EVIDENCE_ESC" \
88
+ >> "$LOG_FILE"
89
+
90
+ echo "✓ decision logged to $LOG_FILE"
@@ -0,0 +1,286 @@
1
+ #!/usr/bin/env bash
2
+ # env-check.sh — environment / dependency detector for CCC-MAGI
3
+ #
4
+ # Called by MAGI Core (via Bash tool) during the bootstrap S1 phase to detect
5
+ # what's installed. Outputs structured JSON that MAGI Core parses to guide
6
+ # the user through installation of any missing dependencies conversationally.
7
+ #
8
+ # USAGE:
9
+ # env-check.sh # Detect + output JSON to stdout, exit 0
10
+ # env-check.sh --finalize # Detect; if all required deps OK, write env-check.json. Exit 0 on success, 1 if blockers remain.
11
+ # env-check.sh --install-jq-vendored # Download jq binary to .harness/bin/jq (no sudo needed)
12
+ #
13
+ # OUTPUT JSON SCHEMA:
14
+ # {
15
+ # "detected_at": "<iso>",
16
+ # "platform": "darwin|linux|windows-wsl|windows-git-bash|unknown",
17
+ # "shell": "bash <version>",
18
+ # "required": {
19
+ # "git": {"installed": true, "version": "2.39.5"},
20
+ # "jq": {"installed": false, "install_hints": [...]}
21
+ # },
22
+ # "ai_clis": {
23
+ # "claude": {"installed": true, "path": "..."},
24
+ # "codex": {"installed": true, "path": "..."},
25
+ # "gemini": {"installed": false}
26
+ # },
27
+ # "tier": "1-claude-codex|1-codex-claude|2-single-claude|2-single-codex|3-other|0-none",
28
+ # "recommendation": "<human-readable>",
29
+ # "all_required_ok": true|false,
30
+ # "blockers": ["jq"]
31
+ # }
32
+
33
+ set -eu
34
+ export PATH="/opt/homebrew/bin:/usr/local/bin:.harness/bin:$PATH"
35
+
36
+ MODE="${1:-detect}"
37
+
38
+ # ─── Platform detection ────────────────────────────────────────────────
39
+ detect_platform() {
40
+ case "$(uname -s)" in
41
+ Darwin*) echo "darwin" ;;
42
+ Linux*)
43
+ # WSL?
44
+ if grep -qi microsoft /proc/version 2>/dev/null || [ -n "${WSL_DISTRO_NAME:-}" ]; then
45
+ echo "windows-wsl"
46
+ else
47
+ echo "linux"
48
+ fi
49
+ ;;
50
+ MINGW*|MSYS*|CYGWIN*) echo "windows-git-bash" ;;
51
+ *) echo "unknown" ;;
52
+ esac
53
+ }
54
+
55
+ PLATFORM=$(detect_platform)
56
+
57
+ # ─── Helpers ───────────────────────────────────────────────────────────
58
+ detect_tool() {
59
+ local name="$1"
60
+ if command -v "$name" >/dev/null 2>&1; then
61
+ local path version
62
+ path="$(command -v "$name")"
63
+ version="$("$name" --version 2>/dev/null | head -1 | sed 's/"/\\"/g' || echo "unknown")"
64
+ printf '{"installed":true,"path":"%s","version":"%s"}' "$path" "$version"
65
+ else
66
+ printf '{"installed":false}'
67
+ fi
68
+ }
69
+
70
+ # Install hints for jq, per platform
71
+ jq_install_hints() {
72
+ case "$PLATFORM" in
73
+ darwin)
74
+ if command -v brew >/dev/null 2>&1; then
75
+ cat <<'EOF'
76
+ [
77
+ {"method":"brew","cmd":"brew install jq","sudo":false,"speed":"~10s"},
78
+ {"method":"vendored","cmd":".harness/scripts/env-check.sh --install-jq-vendored","sudo":false,"speed":"~5s"}
79
+ ]
80
+ EOF
81
+ else
82
+ cat <<'EOF'
83
+ [
84
+ {"method":"brew","cmd":"/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\" && brew install jq","sudo":false,"speed":"~5min"},
85
+ {"method":"vendored","cmd":".harness/scripts/env-check.sh --install-jq-vendored","sudo":false,"speed":"~5s","recommended":true}
86
+ ]
87
+ EOF
88
+ fi
89
+ ;;
90
+ linux|windows-wsl)
91
+ if [ -f /etc/debian_version ]; then
92
+ cat <<'EOF'
93
+ [
94
+ {"method":"apt","cmd":"sudo apt install -y jq","sudo":true,"speed":"~10s"},
95
+ {"method":"vendored","cmd":".harness/scripts/env-check.sh --install-jq-vendored","sudo":false,"speed":"~5s"}
96
+ ]
97
+ EOF
98
+ elif [ -f /etc/redhat-release ]; then
99
+ cat <<'EOF'
100
+ [
101
+ {"method":"yum","cmd":"sudo yum install -y jq","sudo":true,"speed":"~15s"},
102
+ {"method":"vendored","cmd":".harness/scripts/env-check.sh --install-jq-vendored","sudo":false,"speed":"~5s"}
103
+ ]
104
+ EOF
105
+ elif [ -f /etc/arch-release ]; then
106
+ cat <<'EOF'
107
+ [
108
+ {"method":"pacman","cmd":"sudo pacman -S --noconfirm jq","sudo":true,"speed":"~10s"},
109
+ {"method":"vendored","cmd":".harness/scripts/env-check.sh --install-jq-vendored","sudo":false,"speed":"~5s"}
110
+ ]
111
+ EOF
112
+ else
113
+ cat <<'EOF'
114
+ [
115
+ {"method":"vendored","cmd":".harness/scripts/env-check.sh --install-jq-vendored","sudo":false,"speed":"~5s","recommended":true}
116
+ ]
117
+ EOF
118
+ fi
119
+ ;;
120
+ windows-git-bash)
121
+ cat <<'EOF'
122
+ [
123
+ {"method":"scoop","cmd":"scoop install jq","sudo":false,"speed":"~15s","precondition":"requires Scoop package manager"},
124
+ {"method":"chocolatey","cmd":"choco install jq -y","sudo":true,"speed":"~30s","precondition":"requires Chocolatey package manager"},
125
+ {"method":"vendored","cmd":".harness/scripts/env-check.sh --install-jq-vendored","sudo":false,"speed":"~5s","recommended":true}
126
+ ]
127
+ EOF
128
+ ;;
129
+ *)
130
+ echo '[{"method":"manual","cmd":"Install jq from https://jqlang.github.io/jq/download/","sudo":false}]'
131
+ ;;
132
+ esac
133
+ }
134
+
135
+ # ─── Vendored jq install ───────────────────────────────────────────────
136
+ install_jq_vendored() {
137
+ local arch url
138
+ arch="$(uname -m)"
139
+ case "$PLATFORM-$arch" in
140
+ darwin-arm64) url="https://github.com/jqlang/jq/releases/latest/download/jq-macos-arm64" ;;
141
+ darwin-x86_64) url="https://github.com/jqlang/jq/releases/latest/download/jq-macos-amd64" ;;
142
+ linux-x86_64|windows-wsl-x86_64) url="https://github.com/jqlang/jq/releases/latest/download/jq-linux-amd64" ;;
143
+ linux-aarch64|windows-wsl-aarch64) url="https://github.com/jqlang/jq/releases/latest/download/jq-linux-arm64" ;;
144
+ windows-git-bash-*) url="https://github.com/jqlang/jq/releases/latest/download/jq-windows-amd64.exe" ;;
145
+ *) echo "Unsupported platform/arch combo: $PLATFORM-$arch" >&2; exit 1 ;;
146
+ esac
147
+
148
+ mkdir -p .harness/bin
149
+ TARGET=".harness/bin/jq"
150
+ [ "$PLATFORM" = "windows-git-bash" ] && TARGET=".harness/bin/jq.exe"
151
+
152
+ echo "Downloading jq from: $url"
153
+ if command -v curl >/dev/null 2>&1; then
154
+ curl -fsSL "$url" -o "$TARGET" || { echo "Download failed"; exit 1; }
155
+ elif command -v wget >/dev/null 2>&1; then
156
+ wget -q "$url" -O "$TARGET" || { echo "Download failed"; exit 1; }
157
+ else
158
+ echo "Neither curl nor wget found" >&2
159
+ exit 1
160
+ fi
161
+ chmod +x "$TARGET" 2>/dev/null || true
162
+
163
+ echo "✓ jq installed to $TARGET"
164
+ echo " Verify: $TARGET --version"
165
+ }
166
+
167
+ # ─── Mode dispatch ─────────────────────────────────────────────────────
168
+ case "$MODE" in
169
+ --install-jq-vendored)
170
+ install_jq_vendored
171
+ exit 0
172
+ ;;
173
+ detect|--finalize)
174
+ ;;
175
+ *)
176
+ echo "Unknown mode: $MODE" >&2
177
+ echo "Usage: $0 [--finalize | --install-jq-vendored]" >&2
178
+ exit 1
179
+ ;;
180
+ esac
181
+
182
+ # ─── Build detection JSON ──────────────────────────────────────────────
183
+ GIT_INFO=$(detect_tool git)
184
+ JQ_INFO=$(detect_tool jq)
185
+ CLAUDE_INFO=$(detect_tool claude)
186
+ CODEX_INFO=$(detect_tool codex)
187
+ GEMINI_INFO=$(detect_tool gemini)
188
+
189
+ # Bash version (just for info)
190
+ BASH_VER="${BASH_VERSION:-unknown}"
191
+ SHELL_DESC="bash $BASH_VER"
192
+
193
+ # Determine tier
194
+ HAS_CLAUDE=$(printf '%s' "$CLAUDE_INFO" | grep -q '"installed":true' && echo yes || echo no)
195
+ HAS_CODEX=$(printf '%s' "$CODEX_INFO" | grep -q '"installed":true' && echo yes || echo no)
196
+ HAS_GEMINI=$(printf '%s' "$GEMINI_INFO" | grep -q '"installed":true' && echo yes || echo no)
197
+
198
+ if [ "$HAS_CLAUDE" = "yes" ] && [ "$HAS_CODEX" = "yes" ]; then
199
+ TIER="1-claude-codex"
200
+ RECOMMENDATION="Tier 1 ideal: Claude writes code, Codex audits. Cross-model bias cancellation active."
201
+ elif [ "$HAS_CLAUDE" = "yes" ]; then
202
+ TIER="2-single-claude"
203
+ RECOMMENDATION="Tier 2: Claude only. Audit will use fresh-context Claude (same model, weaker bias cancellation). Install Codex for Tier 1."
204
+ elif [ "$HAS_CODEX" = "yes" ]; then
205
+ TIER="2-single-codex"
206
+ RECOMMENDATION="Tier 2: Codex only. Audit will use fresh-context Codex. Install Claude for Tier 1."
207
+ elif [ "$HAS_GEMINI" = "yes" ]; then
208
+ TIER="3-other"
209
+ RECOMMENDATION="Tier 3: Gemini detected but untested. Install Claude or Codex for Tier 1 support."
210
+ else
211
+ TIER="0-none"
212
+ RECOMMENDATION="No supported AI CLI detected. This is unusual — you must have at least one (Claude/Codex) to be talking to MAGI Core right now. Check PATH."
213
+ fi
214
+
215
+ # Determine blockers (jq is the only true required blocker)
216
+ JQ_OK=$(printf '%s' "$JQ_INFO" | grep -q '"installed":true' && echo yes || echo no)
217
+ GIT_OK=$(printf '%s' "$GIT_INFO" | grep -q '"installed":true' && echo yes || echo no)
218
+
219
+ BLOCKERS="["
220
+ ALL_OK="true"
221
+ if [ "$GIT_OK" = "no" ]; then
222
+ BLOCKERS="${BLOCKERS}\"git\","
223
+ ALL_OK="false"
224
+ fi
225
+ if [ "$JQ_OK" = "no" ]; then
226
+ BLOCKERS="${BLOCKERS}\"jq\","
227
+ ALL_OK="false"
228
+ fi
229
+ BLOCKERS="${BLOCKERS%,}]" # strip trailing comma
230
+
231
+ NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
232
+
233
+ # Build JQ install hints if needed
234
+ JQ_HINTS="[]"
235
+ if [ "$JQ_OK" = "no" ]; then
236
+ JQ_HINTS=$(jq_install_hints)
237
+ fi
238
+
239
+ # ─── Assemble output JSON ──────────────────────────────────────────────
240
+ OUTPUT=$(cat <<EOF
241
+ {
242
+ "detected_at": "$NOW",
243
+ "platform": "$PLATFORM",
244
+ "shell": "$SHELL_DESC",
245
+ "required": {
246
+ "git": $GIT_INFO,
247
+ "jq": $JQ_INFO
248
+ },
249
+ "jq_install_hints": $JQ_HINTS,
250
+ "ai_clis": {
251
+ "claude": $CLAUDE_INFO,
252
+ "codex": $CODEX_INFO,
253
+ "gemini": $GEMINI_INFO
254
+ },
255
+ "tier": "$TIER",
256
+ "recommendation": "$RECOMMENDATION",
257
+ "all_required_ok": $ALL_OK,
258
+ "blockers": $BLOCKERS
259
+ }
260
+ EOF
261
+ )
262
+
263
+ # Pretty-print if jq available (recursive bootstrap problem: if jq isn't installed yet, we just output raw)
264
+ if command -v jq >/dev/null 2>&1; then
265
+ echo "$OUTPUT" | jq .
266
+ else
267
+ echo "$OUTPUT"
268
+ fi
269
+
270
+ # ─── Finalize mode: write env-check.json if all required deps OK ──────
271
+ if [ "$MODE" = "--finalize" ]; then
272
+ if [ "$ALL_OK" != "true" ]; then
273
+ echo "" >&2
274
+ echo "✗ Cannot finalize — blockers remain: $BLOCKERS" >&2
275
+ echo " Install the missing dependency, then re-run env-check.sh --finalize" >&2
276
+ exit 1
277
+ fi
278
+
279
+ mkdir -p .harness/state
280
+ echo "$OUTPUT" > .harness/state/env-check.json
281
+ echo "" >&2
282
+ echo "✓ Environment check finalized: .harness/state/env-check.json" >&2
283
+ echo " Phase 1 complete. Next: project deployment via /init" >&2
284
+ fi
285
+
286
+ exit 0