thachvd-kit 1.0.25 → 1.0.27

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/bin/cli.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const fs = require('fs');
4
- const path = require('path');
5
- const { spawnSync } = require('child_process');
6
- const prompts = require('prompts');
7
- const pc = require('picocolors');
8
- const packageJson = require('../package.json');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { spawnSync } = require('child_process');
6
+ const prompts = require('prompts');
7
+ const pc = require('picocolors');
8
+ const packageJson = require('../package.json');
9
9
 
10
10
  const sourceDir = path.resolve(__dirname, '..');
11
11
  const targetDir = process.cwd();
@@ -63,7 +63,7 @@ const INFRA_SKILLS = {
63
63
  vercel: ["deployment-procedures"],
64
64
  };
65
65
 
66
- function resolveSkills(data) {
66
+ function resolveSkills(data) {
67
67
  const skills = new Set();
68
68
  const lang = (data.primary_language || "").toLowerCase();
69
69
 
@@ -88,16 +88,16 @@ function resolveSkills(data) {
88
88
  skills.add("clean-code");
89
89
  skills.add("systematic-debugging");
90
90
 
91
- return Array.from(skills).sort();
92
- }
93
-
94
- function resolveNativeSkills(data) {
95
- return Array.from(new Set([
96
- ...resolveSkills(data),
97
- 'verification-before-completion',
98
- 'webapp-testing'
99
- ])).sort();
100
- }
91
+ return Array.from(skills).sort();
92
+ }
93
+
94
+ function resolveNativeSkills(data) {
95
+ return Array.from(new Set([
96
+ ...resolveSkills(data),
97
+ 'verification-before-completion',
98
+ 'webapp-testing'
99
+ ])).sort();
100
+ }
101
101
 
102
102
  const FRAMEWORK_CHOICES = [
103
103
  'vue', 'react', 'next', 'nuxt', 'svelte', 'angular',
@@ -120,59 +120,70 @@ const IGNORED_SCAN_DIRS = new Set(['.git', 'node_modules', 'vendor', 'dist', 'bu
120
120
 
121
121
  function printHelp() {
122
122
  console.log(`
123
- ${pc.bold('Usage:')}
124
- thachvd-kit [--yes]
125
- thachvd-kit init [--yes]
126
- thachvd-kit --version
127
- thachvd-kit --help
128
-
129
- ${pc.bold('Commands:')}
130
- init Bootstrap shared AI-agent rules and tooling
131
-
132
- ${pc.bold('Options:')}
133
- --yes Overwrite generated files when they already exist
134
- --no-setup-mcp Skip local Codegraph and Playwright MCP setup
135
- --version Show the installed CLI version
136
- --help Show this help message
137
-
138
- ${pc.bold('What gets generated:')}
139
- AGENTS.md Shared instructions for Codex, Antigravity, Claude Code, and Cursor
140
- CLAUDE.md Claude Code entry file that imports AGENTS.md
141
- GEMINI.md Antigravity entry file that points to AGENTS.md
142
- .cursorrules Cursor entry file that points to AGENTS.md
143
- .agent/ Shared docs, skills, workflows, agents, and rules
144
- ~/.codex/skills/ Selected Codex skills copied to global user dir (shows in $ menu)
145
- .claude/skills/ Selected Claude Code project skills copied from .agent/skills
146
-
123
+ ${pc.bold('Usage:')}
124
+ thachvd-kit [--yes]
125
+ thachvd-kit init [--yes]
126
+ thachvd-kit --version
127
+ thachvd-kit --help
128
+
129
+ ${pc.bold('Commands:')}
130
+ init Bootstrap shared AI-agent rules and tooling
131
+
132
+ ${pc.bold('Options:')}
133
+ --yes Overwrite generated files when they already exist
134
+ --no-setup-mcp Skip local Codegraph and Playwright MCP setup
135
+ --version Show the installed CLI version
136
+ --help Show this help message
137
+
138
+ ${pc.bold('What gets generated:')}
139
+ AGENTS.md Shared instructions for Codex, Antigravity, Claude Code, and Cursor
140
+ CLAUDE.md Claude Code entry file that imports AGENTS.md
141
+ GEMINI.md Antigravity entry file that points to AGENTS.md
142
+ .cursorrules Cursor entry file that points to AGENTS.md
143
+ .agent/ Shared docs, skills, workflows, agents, and rules
144
+ ~/.codex/skills/ Selected Codex skills copied to global user dir (shows in $ menu)
145
+ .claude/skills/ Selected Claude Code project skills copied from .agent/skills
146
+
147
147
  ${pc.bold('Workflow guide:')}
148
+ Every task /task Classify the request and select the workflow, skill, and agent
149
+ Small obvious fix /simple Fast path; skips spec/plan/review but still verifies
148
150
  Idea is fuzzy /brainstorm Explore options, tradeoffs, and recommended direction
151
+ Scope needs a contract /spec Define requirements and acceptance criteria; no code yet
149
152
  New app from scratch /create Turn an app idea into plan + implementation flow
150
153
  Feature is clear /plan Create docs/PLAN-*.md first, no code yet
151
154
  Existing app update /enhance Add or change a feature in an existing codebase
152
- Bug or failing behavior /debug Investigate symptoms, hypotheses, root cause, fix
153
- UI / UX work ui-ux-pro-max, frontend-specialist, $frontend-design, $webapp-testing
154
- Run or add tests /test Generate tests, run tests, check coverage
155
- Preview locally /preview Start, stop, restart, or health-check dev server
155
+ Bug or failing behavior /debug Investigate symptoms, hypotheses, root cause, fix
156
+ UI / UX work ui-ux-pro-max, frontend-specialist, $frontend-design, $webapp-testing
157
+ Run or add tests /test Generate tests, run tests, check coverage
158
+ Preview locally /preview Start, stop, restart, or health-check dev server
156
159
  Deploy / infra /deploy Release, hosting, Docker, cloud, environment setup
160
+ Pre-merge review /review Run the five-axis review before calling work complete
161
+ Npm package release /release Verify, version, tag, publish, and verify the package
157
162
  Project state /status Summarize stack, progress, preview, pending work
158
163
  Multi-domain work /orchestrate Coordinate frontend, backend, data, security, QA
159
164
 
160
165
  ${pc.bold('Common explicit skill prompts:')}
166
+ Use /task to route this request before editing.
167
+ Use /simple for a one-file fix with no behavior or contract change.
161
168
  Use /brainstorm for this feature idea before planning.
169
+ Use /spec when requirements or scope need an explicit contract.
162
170
  Use /plan for this feature; do not write code yet.
163
171
  Use /enhance to implement this planned feature.
164
- Use $clean-code before editing this module.
165
- Use $systematic-debugging to investigate this bug.
166
- Use $webapp-testing to verify the UI with Playwright.
167
- Use $verification-before-completion before claiming done.
168
- Use $writing-skills to improve a SKILL.md description.
169
-
170
- ${pc.bold('Tip:')}
171
- Skills are copied for Codex/Claude, but you can call them explicitly with $skill-name
172
- when implicit matching does not fire.
173
- `);
174
-
175
- }
172
+ Use /debug for this failing behavior and find the root cause before editing.
173
+ Use /review before claiming this feature/refactor complete.
174
+ Use /release for npm versioning and publishing.
175
+ Use $clean-code before editing this module.
176
+ Use $systematic-debugging to investigate this bug.
177
+ Use $webapp-testing to verify the UI with Playwright.
178
+ Use $verification-before-completion before claiming done.
179
+ Use $writing-skills to improve a SKILL.md description.
180
+
181
+ ${pc.bold('Tip:')}
182
+ Skills are copied for Codex/Claude, but you can call them explicitly with $skill-name
183
+ when implicit matching does not fire.
184
+ `);
185
+
186
+ }
176
187
 
177
188
  function formatScanPreviewLines(scanned) {
178
189
  return [
@@ -886,859 +897,1104 @@ function resolveAgentTable(data) {
886
897
  rows.push(["Debug", "debugger", "systematic-debugging"]);
887
898
  rows.push(["Security", "security-auditor", "vulnerability-scanner"]);
888
899
  rows.push(["Planning", "project-planner", "brainstorming, plan-writing"]);
889
-
890
900
  return rows;
891
- }
892
- // --- File Generators ---
893
-
894
- function generateSharedAgentsMd(data) {
895
- return `# AGENTS.md
896
-
897
- Shared operating instructions for Codex, Antigravity, Claude Code, and Cursor.
898
-
899
- ## Startup
900
-
901
- 1. Read this file first.
902
- 2. Read \`.agent/docs/project.md\` for detected stack, commands, and routing.
903
- 3. Read \`.agent/docs/workflow.md\` for the task flow before editing.
904
- 4. Read \`.agent/docs/architecture.md\` and \`.agent/docs/conventions.md\` before planning code changes.
905
- 5. Read \`.agent/docs/tooling.md\` when the task needs Playwright, codegraph, MCP, or native Codex/Claude skill setup.
906
- 6. Select and load only the agent, skill, or workflow files that match the current task.
907
-
908
- If any \`.agent/docs/*.md\` file still contains \`TODO: refine\`, update the docs by scanning the project before making product code changes.
909
-
901
+
910
902
  return rows;
903
+ }
904
+ // --- File Generators ---
905
+
906
+ function generateSharedAgentsMd(data) {
907
+ return `# AGENTS.md
908
+
909
+ Shared operating instructions for Codex, Antigravity, Claude Code, and Cursor.
910
+
911
+ ## Startup
912
+
913
+ 1. Read this file first.
914
+ 2. Read \`.agent/docs/project.md\` for detected stack, commands, and routing.
915
+ 3. Read \`.agent/docs/workflow.md\` for the task flow before editing.
916
+ 4. Read \`.agent/docs/architecture.md\` and \`.agent/docs/conventions.md\` before planning code changes.
917
+ 5. Read \`.agent/docs/tooling.md\` when the task needs Playwright, codegraph, MCP, or native Codex/Claude skill setup.
918
+ 6. Select and load only the agent, skill, or workflow files that match the current task.
919
+
920
+ If any \`.agent/docs/*.md\` file still contains \`TODO: refine\`, update the docs by scanning the project before making product code changes.
921
+
911
922
  ## Task Flow
912
923
 
924
+ Route every task before editing. Use \`/task <request>\` when the correct path is not obvious.
925
+
913
926
  - Questions and analysis: answer directly, cite relevant files when useful, and do not edit code.
914
- - Simple fix: inspect dependencies, make the smallest change, run focused verification.
915
- - Feature or refactor: define success criteria, make a short plan, implement, then verify.
927
+ - Simple fix: use \`/simple <request>\` only for one-file, unambiguous changes with no behavior or contract change.
928
+ - Bug or failing behavior: use \`/debug <symptom>\` and follow the evidence-first root-cause flow.
929
+ - Feature or refactor: use \`/brainstorm\` for discovery, \`/spec\` for ambiguous or multi-file scope, then \`/plan\`, wait for approval, implement, test, and \`/review\`.
930
+ - Pre-merge review: use \`/review\` even when the implementation itself was done by another client or member.
931
+ - Release or npm publish: use \`/release\`; release work never uses the simple fast path.
916
932
  - Multi-domain work: use \`.agent/workflows/orchestrate.md\` and route to the relevant specialist docs.
917
933
  - UI work: read \`.agent/agents/frontend-specialist.md\` and applicable design skills before editing.
918
934
 
919
- ## Skill Loading
920
-
921
- - Treat \`.agent/skills/\` as the shared source of truth for all kit skills.
922
- - Codex exposes skills from \`~/.codex/skills/\` in the \`$\` menu; \`thachvd-kit\` copies selected skills there on init.
923
- - Claude Code project skills live in \`.claude/skills/\`.
924
- - If a skill is missing from the global dir, fall back to the matching \`.agent/skills/<skill>/SKILL.md\` file.
925
- - Do not load skill bodies by default; load a skill only when the user mentions it, the task clearly matches its description, or \`.agent/docs/project.md\` routes the task to it.
926
- - Prefer explicit skill mentions for predictable behavior: \`$clean-code\`, \`$systematic-debugging\`, \`$webapp-testing\`, or any skill listed in \`.agent/docs/project.md\`.
927
- - Run \`thachvd-kit --help\` to see common workflow and skill recommendations.
928
- - When creating or improving skills, use \`writing-skills\` first and make the \`description\` field specific enough for implicit invocation.
929
-
930
- ## Rules
931
-
932
- - Respond in the user's language; keep code, identifiers, and code comments in English.
933
- - State assumptions when the request is ambiguous.
934
- - Prefer the existing project style over new abstractions.
935
- - Keep changes surgical and remove only dead code introduced by your change.
936
- - **MCP First**: Prioritize using MCP server tools (e.g., \`codegraph\` for codebase search/symbol tracking, \`context7\` for API/docs queries, and \`playwright\` for browser/UI testing and verification) to explore, search, and verify rather than recursively listing directories, running expensive shell commands/grep, or reading large files. This minimizes token usage and maintains a cleaner context.
937
- - Tests or equivalent verification are mandatory before claiming done.
938
- - Keep files under ${data.max_file_lines || '300'} lines unless the project already has a different standard in \`.agent/docs/conventions.md\`.
939
-
940
- ## Shared Knowledge
941
-
942
- - Project docs: \`.agent/docs/\`
943
- - Specialist agents: \`.agent/agents/\`
944
- - Skills: \`.agent/skills/\`
945
- - Codex global skills: \`~/.codex/skills/\` (installed by thachvd-kit init)
946
- - Claude Code project skills: \`.claude/skills/\`
947
- - Workflows: \`.agent/workflows/\`
948
- - Tooling setup: \`.agent/docs/tooling.md\`
949
- - Antigravity mirror rules: \`.agent/rules/GEMINI.md\`
950
- - Cursor entry rules: \`.cursorrules\`
951
- `;
952
- }
953
-
954
- function generateSharedClaudeMd(data) {
955
- return `@AGENTS.md
935
+ ### Fast Path (\`/simple\`)
956
936
 
957
- ${generateSharedAgentsMd(data)}
937
+ The fast path intentionally bypasses only Spec, Plan, and the feature/refactor Review gate for a trivial change. It never bypasses inspection, focused verification, or reporting evidence. The agent must state this protocol before editing:
958
938
 
959
- ## Claude Code
960
-
961
- This repository uses AGENTS.md as the shared cross-agent entry file. Follow the imported instructions and keep Claude-specific notes here only when they cannot apply to Codex or Antigravity.
962
- `;
963
- }
939
+ \`\`\`text
940
+ FAST_PATH: simple-fix
941
+ REASON: [why the change is one-file and unambiguous]
942
+ SCOPE: [file or narrow area]
943
+ \`\`\`
964
944
 
965
- function generateSharedGeminiMd() {
966
- return `# GEMINI.md
945
+ If the scope expands, stop and re-route with \`/task\`. Do not silently skip gates for work that changes behavior, APIs, schemas, security, CI, dependencies, workflows, or release state.
946
+
947
+ ### Gated Flow (feature or refactor)
967
948
 
968
- Antigravity entry file for this project.
949
+ 1. **Spec** — run \`.agent/workflows/spec.md\` when scope is ambiguous, touches multiple files, or would take more than ~30 minutes. Skip only for single-line/self-contained fixes. Stop at its exit criteria and wait for human confirmation before moving on.
950
+ 2. **Plan** — run \`.agent/workflows/plan.md\` (project-planner agent, no code writing). Wait for explicit user approval of the plan file before implementing.
951
+ 3. **Implement** — smallest coherent change per the approved plan, with focused tests for changed behavior.
952
+ 4. **Review** — run \`.agent/workflows/review.md\` (five-axis review) before the change is considered done. All 🔴 BLOCKING items must be resolved or explicitly accepted with rationale.
969
953
 
970
- Read AGENTS.md first, then follow the shared docs under .agent/docs/.
971
- `;
972
- }
954
+ A feature/refactor task is not "done" until step 4's exit criteria are met — passing tests alone does not satisfy the gate. Simple fixes use the explicit \`/simple\` fast path above. See \`.agent/docs/getting-started.md\` for the complete route guide.
973
955
 
974
- function generateSharedCursorrules(data) {
956
+ ## Skill Loading
957
+
958
+ - Treat \`.agent/skills/\` as the shared source of truth for all kit skills.
959
+ - Codex exposes skills from \`~/.codex/skills/\` in the \`$\` menu; \`thachvd-kit\` copies selected skills there on init.
960
+ - Claude Code project skills live in \`.claude/skills/\`.
961
+ - If a skill is missing from the global dir, fall back to the matching \`.agent/skills/<skill>/SKILL.md\` file.
962
+ - Do not load skill bodies by default; load a skill only when the user mentions it, the task clearly matches its description, or \`.agent/docs/project.md\` routes the task to it.
963
+ - Prefer explicit skill mentions for predictable behavior: \`$clean-code\`, \`$systematic-debugging\`, \`$webapp-testing\`, or any skill listed in \`.agent/docs/project.md\`.
964
+ - Run \`thachvd-kit --help\` to see common workflow and skill recommendations.
965
+ - When creating or improving skills, use \`writing-skills\` first and make the \`description\` field specific enough for implicit invocation.
966
+
967
+ ## Rules
968
+
969
+ - Respond in the user's language; keep code, identifiers, and code comments in English.
970
+ - State assumptions when the request is ambiguous.
971
+ - Prefer the existing project style over new abstractions.
972
+ - Keep changes surgical and remove only dead code introduced by your change.
973
+ - **MCP First**: Prioritize using MCP server tools (e.g., \`codegraph\` for codebase search/symbol tracking, \`context7\` for API/docs queries, and \`playwright\` for browser/UI testing and verification) to explore, search, and verify rather than recursively listing directories, running expensive shell commands/grep, or reading large files. This minimizes token usage and maintains a cleaner context.
974
+ - Tests or equivalent verification are mandatory before claiming done.
975
+ - Keep files under ${data.max_file_lines || '300'} lines unless the project already has a different standard in \`.agent/docs/conventions.md\`.
976
+
977
+ ## Shared Knowledge
978
+
979
+ - Project docs: \`.agent/docs/\`
980
+ - Specialist agents: \`.agent/agents/\`
981
+ - Skills: \`.agent/skills/\`
982
+ - Codex global skills: \`~/.codex/skills/\` (installed by thachvd-kit init)
983
+ - Claude Code project skills: \`.claude/skills/\`
984
+ - Workflows: \`.agent/workflows/\`
985
+ - Tooling setup: \`.agent/docs/tooling.md\`
986
+ - Antigravity mirror rules: \`.agent/rules/GEMINI.md\`
987
+ - Cursor entry rules: \`.cursorrules\`
988
+ `;
989
+ }
990
+
991
+ function generateSharedClaudeMd() {
992
+ return `@AGENTS.md
993
+
994
+ ## Claude Code
995
+
996
+ This repository uses AGENTS.md as the shared cross-agent entry file. Follow the imported instructions and keep Claude-specific notes here only when they cannot apply to Codex or Antigravity.
997
+ `;
998
+ }
999
+
1000
+ function generateSharedGeminiMd() {
1001
+ return `# GEMINI.md
1002
+
1003
+ Antigravity entry file for this project.
1004
+
1005
+ Read AGENTS.md first, then follow the shared docs under .agent/docs/.
1006
+ `;
1007
+ }
1008
+
1009
+ function generateSharedCursorrules(data) {
975
1010
  return `# Cursor Rules
976
-
977
- This repository uses AGENTS.md as the shared cross-agent entry file. Follow the instructions in AGENTS.md and keep Cursor-specific notes here only when they cannot apply to Codex, Antigravity, or Claude Code.
978
-
979
- Read AGENTS.md first, then follow the shared docs under .agent/docs/.
980
-
981
- ---
982
-
983
- ${generateSharedAgentsMd(data)}
984
- `;
985
- }
986
-
987
- function resolveCommands(data) {
988
- const frameworks = data.frameworks || [];
989
- const primaryLang = data.primary_language || 'javascript';
990
- const pkgManager = data.package_manager || 'npm';
991
- const testFramework = data.test_framework || 'auto-detect';
992
-
993
- const isPython = primaryLang === 'python';
994
- const isGo = primaryLang === 'go';
995
- const isRust = primaryLang === 'rust';
996
- const isPhp = primaryLang === 'php';
997
-
998
- let install = 'npm install';
999
- let dev = 'npm run dev';
1000
- let build = 'npm run build';
1001
- let test = 'npm test';
1002
- let lint = 'npm run lint';
1003
-
1004
- if (pkgManager === 'pnpm') { install = 'pnpm install'; dev = 'pnpm dev'; build = 'pnpm build'; test = 'pnpm test'; lint = 'pnpm lint'; }
1005
- else if (pkgManager === 'yarn') { install = 'yarn'; dev = 'yarn dev'; build = 'yarn build'; test = 'yarn test'; lint = 'yarn lint'; }
1006
- else if (pkgManager === 'bun') { install = 'bun install'; dev = 'bun dev'; build = 'bun run build'; test = 'bun test'; lint = 'bun run lint'; }
1007
- else if (isPython) { install = 'pip install -r requirements.txt'; dev = 'python manage.py runserver'; build = '# no build step'; test = 'pytest'; lint = 'ruff check .'; }
1008
- else if (isGo) { install = 'go mod download'; dev = 'go run .'; build = 'go build ./...'; test = 'go test ./...'; lint = 'golangci-lint run'; }
1009
- else if (isRust) { install = 'cargo build'; dev = 'cargo run'; build = 'cargo build --release'; test = 'cargo test'; lint = 'cargo clippy'; }
1010
- else if (isPhp) {
1011
- install = 'composer install';
1012
- build = '# no build step';
1013
- test = testFramework === 'pest' ? './vendor/bin/pest' : './vendor/bin/phpunit';
1014
- const isCakePHP = frameworks.some(f => f.toLowerCase().includes('cakephp'));
1015
- const isSymfony = frameworks.some(f => f.toLowerCase().includes('symfony'));
1016
- const isCodeIgniter = frameworks.some(f => f.toLowerCase().includes('codeigniter'));
1017
- if (isCakePHP) {
1018
- dev = 'bin/cake server';
1019
- lint = './vendor/bin/phpcs';
1020
- } else if (isSymfony) {
1021
- dev = 'bin/console server:run';
1022
- lint = './vendor/bin/phpcs';
1023
- } else if (isCodeIgniter) {
1024
- dev = 'php spark serve';
1025
- lint = './vendor/bin/phpcs';
1026
- } else {
1027
- dev = 'php artisan serve';
1028
- lint = 'php artisan pint';
1029
- }
1030
- }
1031
-
1032
- if (testFramework === 'vitest') test = `${pkgManager === 'pnpm' ? 'pnpm' : pkgManager === 'yarn' ? 'yarn' : pkgManager === 'bun' ? 'bun run' : 'npx'} vitest`;
1033
- else if (testFramework === 'jest') test = `${pkgManager === 'pnpm' ? 'pnpm' : pkgManager === 'yarn' ? 'yarn' : 'npx'} jest`;
1034
-
1035
- return { install, dev, build, test, lint };
1036
- }
1037
-
1038
- function generateProjectDoc(data) {
1039
- const commands = resolveCommands(data);
1040
- const agentRows = resolveAgentTable(data).map(([task, agent, skills]) => `| ${task} | \`${agent}\` | ${skills} |`).join('\n');
1041
- const skillsList = resolveSkills(data).map(s => `- ${s}`).join('\n');
1042
- const evidence = (data.scan_evidence || []).length > 0
1043
- ? (data.scan_evidence || []).map(line => `- ${line}`).join('\n')
1044
- : '- TODO: refine scan evidence by inspecting the project.';
1045
-
1046
- return `# Project Rules
1047
-
1048
- Generated by thachvd-kit on ${new Date().toISOString().split('T')[0]}.
1049
-
1050
- ## Summary
1051
-
1052
- - Name: ${data.project_name}
1053
- - Description: ${data.description}
1054
- - Type: ${data.project_type}
1055
- - App root: ${data.app_root || '.'}
1056
-
1057
- ## Stack
1058
-
1059
- - Language: ${data.primary_language}
1060
- - Frameworks: ${(data.frameworks || []).join(', ') || 'none'}
1061
- - Database: ${data.database || 'none'}
1062
- - Infrastructure: ${(data.infrastructure || []).join(', ') || 'none'}
1063
- - Package manager: ${data.package_manager || 'auto-detect'}
1064
- - Test framework: ${data.test_framework || 'auto-detect'}
1065
-
1066
- ## Commands
1067
-
1068
- - Install: \`${commands.install}\`
1069
- - Dev: \`${commands.dev}\`
1070
- - Build: \`${commands.build}\`
1071
- - Test: \`${commands.test}\`
1072
- - Lint: \`${commands.lint}\`
1073
-
1074
- ## Agent Routing
1075
-
1076
- | Task Type | Agent | Primary Skills |
1077
- |-----------|-------|----------------|
1078
- ${agentRows}
1079
-
1080
- ## Auto-Resolved Skills
1081
-
1082
- ${skillsList}
1083
-
1084
- ## Scan Evidence
1085
-
1086
- ${evidence}
1087
- `;
1088
- }
1089
-
1090
- function generateArchitectureDoc(data) {
1091
- const appRootLine = data.app_root && data.app_root !== '.'
1092
- ? `- App root is currently detected as \`${data.app_root}\`.`
1093
- : '- App root is the repository root unless refined below.';
1094
- const evidence = (data.scan_evidence || []).length > 0
1095
- ? (data.scan_evidence || []).map(line => `- ${line}`).join('\n')
1096
- : '- TODO: refine architecture by scanning source directories.';
1097
-
1098
- return `# Architecture Notes
1099
-
1100
- ## Current Map
1101
-
1102
- ${appRootLine}
1103
- - TODO: refine major directories and responsibilities.
1104
- - TODO: refine main entry points, routing, state boundaries, and integration boundaries.
1105
-
1106
- ## Detected Evidence
1107
-
1108
- ${evidence}
1109
-
1110
- ## AI Maintenance Rule
1111
-
1112
- Before non-trivial implementation work, inspect this file. If it is stale or still contains TODO items relevant to the task, update it from the code before editing product code.
1113
- `;
1114
- }
1115
-
1116
- function generateConventionsDoc(data) {
1117
- return `# Coding Conventions
1118
-
1119
- ## Current Standards
1120
-
1121
- - Maximum file length: ${data.max_file_lines || '300'} lines unless the existing project standard is stricter.
1122
- - Code comments and identifiers should be written in English.
1123
- - Keep changes scoped to the user request.
1124
- - Prefer existing local patterns over introducing new abstractions.
1125
- - TODO: refine naming, formatting, folder, API, state, styling, and testing conventions from the real codebase.
1126
-
1127
- ## Verification
1128
-
1129
- - Run the focused test or lint command that matches the touched area.
1130
- - If no automated check exists, document the manual verification performed.
1131
- - For UI/web changes, prioritize using Playwright MCP to automatically verify client-side behavior and capture screenshots.
1132
- - Do not claim completion without verification evidence.
1011
+
1012
+ This repository uses AGENTS.md as the shared cross-agent entry file. Follow the instructions in AGENTS.md and keep Cursor-specific notes here only when they cannot apply to Codex, Antigravity, or Claude Code.
1013
+
1014
+ Read AGENTS.md first, then follow the shared docs under .agent/docs/.
1015
+
1016
+ ---
1017
+
1018
+ ${generateSharedAgentsMd(data).trimEnd()}
1133
1019
  `;
1134
- }
1135
-
1136
- function generateWorkflowDoc() {
1137
- return `# Agent Workflow
1138
-
1139
- ## Before Every Task
1140
-
1141
- 1. Read AGENTS.md.
1142
- 2. Read .agent/docs/project.md.
1143
- 3. Classify the request: question, survey, simple fix, feature, refactor, debug, UI, security, or deploy.
1020
+ }
1021
+
1022
+ function resolveCommands(data) {
1023
+ const frameworks = data.frameworks || [];
1024
+ const primaryLang = data.primary_language || 'javascript';
1025
+ const pkgManager = data.package_manager || 'npm';
1026
+ const testFramework = data.test_framework || 'auto-detect';
1027
+
1028
+ const isPython = primaryLang === 'python';
1029
+ const isGo = primaryLang === 'go';
1030
+ const isRust = primaryLang === 'rust';
1031
+ const isPhp = primaryLang === 'php';
1032
+
1033
+ let install = 'npm install';
1034
+ let dev = 'npm run dev';
1035
+ let build = 'npm run build';
1036
+ let test = 'npm test';
1037
+ let lint = 'npm run lint';
1038
+
1039
+ if (pkgManager === 'pnpm') { install = 'pnpm install'; dev = 'pnpm dev'; build = 'pnpm build'; test = 'pnpm test'; lint = 'pnpm lint'; }
1040
+ else if (pkgManager === 'yarn') { install = 'yarn'; dev = 'yarn dev'; build = 'yarn build'; test = 'yarn test'; lint = 'yarn lint'; }
1041
+ else if (pkgManager === 'bun') { install = 'bun install'; dev = 'bun dev'; build = 'bun run build'; test = 'bun test'; lint = 'bun run lint'; }
1042
+ else if (isPython) { install = 'pip install -r requirements.txt'; dev = 'python manage.py runserver'; build = '# no build step'; test = 'pytest'; lint = 'ruff check .'; }
1043
+ else if (isGo) { install = 'go mod download'; dev = 'go run .'; build = 'go build ./...'; test = 'go test ./...'; lint = 'golangci-lint run'; }
1044
+ else if (isRust) { install = 'cargo build'; dev = 'cargo run'; build = 'cargo build --release'; test = 'cargo test'; lint = 'cargo clippy'; }
1045
+ else if (isPhp) {
1046
+ install = 'composer install';
1047
+ build = '# no build step';
1048
+ test = testFramework === 'pest' ? './vendor/bin/pest' : './vendor/bin/phpunit';
1049
+ const isCakePHP = frameworks.some(f => f.toLowerCase().includes('cakephp'));
1050
+ const isSymfony = frameworks.some(f => f.toLowerCase().includes('symfony'));
1051
+ const isCodeIgniter = frameworks.some(f => f.toLowerCase().includes('codeigniter'));
1052
+ if (isCakePHP) {
1053
+ dev = 'bin/cake server';
1054
+ lint = './vendor/bin/phpcs';
1055
+ } else if (isSymfony) {
1056
+ dev = 'bin/console server:run';
1057
+ lint = './vendor/bin/phpcs';
1058
+ } else if (isCodeIgniter) {
1059
+ dev = 'php spark serve';
1060
+ lint = './vendor/bin/phpcs';
1061
+ } else {
1062
+ dev = 'php artisan serve';
1063
+ lint = 'php artisan pint';
1064
+ }
1065
+ }
1066
+
1067
+ if (testFramework === 'vitest') test = `${pkgManager === 'pnpm' ? 'pnpm' : pkgManager === 'yarn' ? 'yarn' : pkgManager === 'bun' ? 'bun run' : 'npx'} vitest`;
1068
+ else if (testFramework === 'jest') test = `${pkgManager === 'pnpm' ? 'pnpm' : pkgManager === 'yarn' ? 'yarn' : 'npx'} jest`;
1069
+
1070
+ return { install, dev, build, test, lint };
1071
+ }
1072
+
1073
+ function generateProjectDoc(data) {
1074
+ const commands = resolveCommands(data);
1075
+ const agentRows = resolveAgentTable(data).map(([task, agent, skills]) => `| ${task} | \`${agent}\` | ${skills} |`).join('\n');
1076
+ const skillsList = resolveSkills(data).map(s => `- ${s}`).join('\n');
1077
+ const evidence = (data.scan_evidence || []).length > 0
1078
+ ? (data.scan_evidence || []).map(line => `- ${line}`).join('\n')
1079
+ : '- TODO: refine scan evidence by inspecting the project.';
1080
+
1081
+ return `# Project Rules
1082
+
1083
+ Generated by thachvd-kit on ${new Date().toISOString().split('T')[0]}.
1084
+
1085
+ ## Summary
1086
+
1087
+ - Name: ${data.project_name}
1088
+ - Description: ${data.description}
1089
+ - Type: ${data.project_type}
1090
+ - App root: ${data.app_root || '.'}
1091
+
1092
+ ## Stack
1093
+
1094
+ - Language: ${data.primary_language}
1095
+ - Frameworks: ${(data.frameworks || []).join(', ') || 'none'}
1096
+ - Database: ${data.database || 'none'}
1097
+ - Infrastructure: ${(data.infrastructure || []).join(', ') || 'none'}
1098
+ - Package manager: ${data.package_manager || 'auto-detect'}
1099
+ - Test framework: ${data.test_framework || 'auto-detect'}
1100
+
1101
+ ## Commands
1102
+
1103
+ - Install: \`${commands.install}\`
1104
+ - Dev: \`${commands.dev}\`
1105
+ - Build: \`${commands.build}\`
1106
+ - Test: \`${commands.test}\`
1107
+ - Lint: \`${commands.lint}\`
1108
+
1109
+ ## Available MCP Tools
1110
+
1111
+ Use these tools as first-class search and verification methods — prefer them over shell commands or file reads.
1112
+
1113
+ | MCP | When to Use |
1114
+ |-----|-------------|
1115
+ | \`codegraph\` | Explore symbols, trace call chains, find usages — use BEFORE reading files |
1116
+ | \`context7\` | Look up library/framework docs, API signatures, migration guides |
1117
+ | \`playwright\` | Verify UI behavior, take screenshots, test forms and navigation |
1118
+
1119
+ > Check \`.agent/docs/tooling.md\` for setup details and additional MCP servers.
1120
+
1121
+ ## Agent Routing
1122
+
1123
+ | Task Type | Agent | Primary Skills |
1124
+ |-----------|-------|----------------|
1125
+ ${agentRows}
1126
+
1127
+ ## Auto-Resolved Skills
1128
+
1129
+ ${skillsList}
1130
+
1131
+ ## Scan Evidence
1132
+
1133
+ ${evidence}
1134
+ `;
1135
+ }
1136
+
1137
+ function generateArchitectureDoc(data) {
1138
+ const appRootLine = data.app_root && data.app_root !== '.'
1139
+ ? `- App root is currently detected as \`${data.app_root}\`.`
1140
+ : '- App root is the repository root unless refined below.';
1141
+ const evidence = (data.scan_evidence || []).length > 0
1142
+ ? (data.scan_evidence || []).map(line => `- ${line}`).join('\n')
1143
+ : '- TODO: refine architecture by scanning source directories.';
1144
+
1145
+ return `# Architecture Notes
1146
+
1147
+ ## Current Map
1148
+
1149
+ ${appRootLine}
1150
+ - TODO: refine major directories and responsibilities.
1151
+ - TODO: refine main entry points, routing, state boundaries, and integration boundaries.
1152
+
1153
+ ## Detected Evidence
1154
+
1155
+ ${evidence}
1156
+
1157
+ ## AI Maintenance Rule
1158
+
1159
+ Before non-trivial implementation work, inspect this file. If it is stale or still contains TODO items relevant to the task, update it from the code before editing product code.
1160
+ `;
1161
+ }
1162
+
1163
+ function generateConventionsDoc(data) {
1164
+ return `# Coding Conventions
1165
+
1166
+ ## Current Standards
1167
+
1168
+ - Maximum file length: ${data.max_file_lines || '300'} lines unless the existing project standard is stricter.
1169
+ - Code comments and identifiers should be written in English.
1170
+ - Keep changes scoped to the user request.
1171
+ - Prefer existing local patterns over introducing new abstractions.
1172
+ - TODO: refine naming, formatting, folder, API, state, styling, and testing conventions from the real codebase.
1173
+
1174
+ ## Verification
1175
+
1176
+ - Run the focused test or lint command that matches the touched area.
1177
+ - If no automated check exists, document the manual verification performed.
1178
+ - For UI/web changes, prioritize using Playwright MCP to automatically verify client-side behavior and capture screenshots.
1179
+ - Do not claim completion without verification evidence.
1180
+ `;
1181
+ }
1182
+
1183
+ function generateWorkflowDoc() {
1184
+ return `# Agent Workflow
1185
+
1186
+ ## Before Every Task
1187
+
1188
+ 1. Read AGENTS.md.
1189
+ 2. Read .agent/docs/project.md.
1190
+ 3. Route the request with \`/task <request>\` when the path is not obvious.
1144
1191
  4. Read only the relevant docs under .agent/agents, .agent/skills, .claude/skills, and .agent/workflows.
1145
1192
  5. Check if MCP servers (like \`codegraph\`) are active/available and prioritize using them as the primary entry point to search and locate files, symbols, and code blocks.
1146
1193
 
1147
- ## Skill Selection
1148
-
1149
- - Prefer native skill discovery when the client exposes it.
1150
- - Codex global skills live in ~/.codex/skills/ and are visible via the $ menu; thachvd-kit copies selected skills there on init.
1151
- - Claude Code project skills live in .claude/skills.
1152
- - Shared fallback skills live in .agent/skills.
1153
- - Do not load skill bodies by default.
1154
- - Load a skill when the user mentions it, the task clearly matches its SKILL.md description, or .agent/docs/project.md routes the task to it.
1155
- - Use explicit skill names in prompts for predictable behavior, for example $webapp-testing or $clean-code.
1156
- - Run thachvd-kit --help to see common workflow and skill recommendations.
1194
+ ## Route Matrix
1157
1195
 
1158
- ## Implementation Flow
1196
+ | Situation | Command | Workflow / gate |
1197
+ |---|---|---|
1198
+ | Question or analysis only | direct answer | no edits |
1199
+ | One obvious local fix | \`/simple\` | \`.agent/workflows/simple.md\`, fast-path |
1200
+ | Bug, regression, failing test, or unknown error | \`/debug\` | \`.agent/workflows/debug.md\`, evidence-first |
1201
+ | New behavior, multi-file change, or unclear scope | \`/brainstorm\` -> \`/spec\` when needed -> \`/plan\` | spec/plan approval -> implement -> review |
1202
+ | Pre-merge review | \`/review\` | \`.agent/workflows/review.md\`, five-axis |
1203
+ | npm version, tag, publish, or deployment | \`/release\` | \`.agent/workflows/release.md\`, release gate |
1204
+ | Several specialist domains | \`/orchestrate\` | plan -> approval -> parallel work -> integration verify |
1159
1205
 
1160
- 1. State assumptions and success criteria when the task is not trivial.
1161
- 2. Inspect dependent files before editing.
1162
- 3. Make the smallest coherent change.
1163
- 4. Add or update focused tests when behavior changes.
1164
- 5. Run verification (prioritize using Playwright MCP for web/UI changes to automate verification and capture screenshots).
1165
- 6. Summarize changed files and verification evidence.
1166
-
1167
- ## When To Update Docs
1206
+ If a task is not clearly simple, use the standard flow. Never use the fast path for behavior, API, schema, security, CI, dependency, workflow, or release changes.
1207
+
1208
+ ## Skill Selection
1209
+
1210
+ - Prefer native skill discovery when the client exposes it.
1211
+ - Codex global skills live in ~/.codex/skills/ and are visible via the $ menu; thachvd-kit copies selected skills there on init.
1212
+ - Claude Code project skills live in .claude/skills.
1213
+ - Shared fallback skills live in .agent/skills.
1214
+ - Do not load skill bodies by default.
1215
+ - Load a skill when the user mentions it, the task clearly matches its SKILL.md description, or .agent/docs/project.md routes the task to it.
1216
+ - Use explicit skill names in prompts for predictable behavior, for example $webapp-testing or $clean-code.
1217
+ - Run thachvd-kit --help to see common workflow and skill recommendations.
1218
+
1219
+ ## Implementation Flow
1220
+
1221
+ For \`/simple\` fixes, state the fast-path decision before editing:
1168
1222
 
1169
- - Update .agent/docs/architecture.md when structure, boundaries, or entry points change.
1170
- - Update .agent/docs/conventions.md when repeated project patterns become clear.
1171
- - Update .agent/docs/project.md when stack, scripts, app root, test tooling, or routing changes.
1172
- - Keep AGENTS.md concise. Put project-specific detail in .agent/docs.
1173
- `;
1174
- }
1223
+ \`\`\`text
1224
+ FAST_PATH: simple-fix
1225
+ REASON: [why Spec/Plan/Review are not needed]
1226
+ SCOPE: [file or narrow area]
1227
+ \`\`\`
1175
1228
 
1176
- function resolveToolingSetup(data) {
1177
- const primaryLang = data.primary_language || 'javascript';
1178
- const packageManager = data.package_manager || 'npm';
1179
- const isPython = primaryLang === 'python';
1180
- const runner = packageManager === 'pnpm'
1181
- ? 'pnpm dlx'
1182
- : packageManager === 'yarn'
1183
- ? 'yarn dlx'
1184
- : packageManager === 'bun'
1185
- ? 'bunx'
1186
- : 'npx';
1187
- const playwrightCommand = isPython
1188
- ? 'pip install playwright && playwright install chromium'
1189
- : `${runner} playwright install`;
1229
+ Then:
1190
1230
 
1191
- return { runner, playwrightCommand };
1192
- }
1231
+ 1. State assumptions and success criteria when the task is not trivial.
1232
+ 2. Inspect dependent files before editing.
1233
+ 3. Make the smallest coherent change.
1234
+ 4. Add or update focused tests when behavior changes.
1235
+ 5. Run verification (prioritize using Playwright MCP for web/UI changes to automate verification and capture screenshots).
1236
+ 6. Summarize changed files and verification evidence.
1237
+
1238
+ For bugs, use \`/debug\` with \`$systematic-debugging\`, the \`debugger\` agent, and \`testing-patterns\`: reproduce, isolate the root cause, add regression protection, make the smallest fix, and verify.
1193
1239
 
1194
- function generateToolingDoc(data) {
1195
- const { runner, playwrightCommand } = resolveToolingSetup(data);
1240
+ For features or refactors, this flow runs *inside* the gated flow defined in AGENTS.md (spec -> plan -> implement -> review) — steps 3-5 above are the "Implement" phase, and step 6 is not a substitute for the mandatory \`.agent/workflows/review.md\` gate.
1196
1241
 
1197
- return `# Optional Tooling
1242
+ ## Definition of Done (feature or refactor)
1198
1243
 
1199
- This kit keeps tool setup explicit. Do not assume these tools are available until you verify them in the current environment.
1244
+ A feature/refactor task is only complete when all of the following hold — not when code compiles or tests pass:
1200
1245
 
1201
- ## Playwright
1246
+ The Spec checkbox may be skipped only when the documented \`/simple\` fast-path protocol is stated and its criteria are met.
1202
1247
 
1203
- Use Playwright for browser and UI verification when a task touches web behavior.
1248
+ - [ ] \`.agent/workflows/spec.md\` exit criteria met (or explicitly skipped as a trivial/self-contained change)
1249
+ - [ ] \`.agent/workflows/plan.md\` produced a plan file, approved by the user
1250
+ - [ ] Tests added/updated for the changed behavior and passing
1251
+ - [ ] \`.agent/workflows/review.md\` five-axis review completed with all 🔴 BLOCKING items resolved or accepted with rationale
1252
+ - [ ] Changed files and verification evidence summarized to the user
1204
1253
 
1205
- - Check availability: \`${runner} playwright --version\`
1206
- - Install browsers: \`${playwrightCommand}\`
1207
- - Codex MCP CLI setup: \`codex mcp add playwright -- npx -y @playwright/mcp\`
1208
- - Auto setup: \`thachvd-kit\`
1209
- - Kit helper: \`python .agent/skills/webapp-testing/scripts/playwright_runner.py <url> --screenshot\`
1254
+ Do not report a feature/refactor task as done if any box above is unchecked — say explicitly which gate is still open.
1210
1255
 
1211
- If the project already has Playwright configured, prefer the project's existing scripts.
1256
+ ## When To Update Docs
1257
+
1258
+ - Update .agent/docs/architecture.md when structure, boundaries, or entry points change.
1259
+ - Update .agent/docs/conventions.md when repeated project patterns become clear.
1260
+ - Update .agent/docs/project.md when stack, scripts, app root, test tooling, or routing changes.
1261
+ - Keep AGENTS.md concise. Put project-specific detail in .agent/docs.
1262
+ `;
1263
+ }
1264
+
1265
+ function generateGettingStartedDoc() {
1266
+ return `# Getting Started With This Kit
1212
1267
 
1213
- Codex \`config.toml\` example:
1268
+ Read this after \`thachvd-kit init\`. The kit gives every member one entry point, then selects only the process and expertise the task needs.
1214
1269
 
1215
- \`\`\`toml
1216
- [mcp_servers.context7]
1217
- command = "npx"
1218
- args = ["-y", "@upstash/context7-mcp"]
1219
- startup_timeout_sec = 20
1220
- tool_timeout_sec = 120
1270
+ ## Start Every Task With /task
1221
1271
 
1222
- [mcp_servers.filesystem]
1223
- command = "npx"
1224
- args = ["-y", "@modelcontextprotocol/server-filesystem", "<projectPath>"]
1225
- startup_timeout_sec = 20
1226
- tool_timeout_sec = 120
1272
+ Use \`/task <request>\` before editing whenever the route is not already obvious. It must produce:
1227
1273
 
1228
- [mcp_servers.playwright]
1229
- command = "npx"
1230
- args = ["-y", "@playwright/mcp"]
1231
- startup_timeout_sec = 20
1232
- tool_timeout_sec = 120
1274
+ \`\`\`text
1275
+ ROUTE: question | simple | feature | bug | review | release | multi-domain
1276
+ WORKFLOW: [exact .agent/workflows/<name>.md file]
1277
+ SKILLS: [matching skills, or none]
1278
+ AGENTS: [matching specialist agents, or none]
1279
+ GATE: fast-path | standard
1280
+ NEXT: [the next command or action]
1233
1281
  \`\`\`
1234
1282
 
1235
- ## Codegraph
1283
+ A workflow is the process and its gates. A skill is the method or checklist. An agent is the specialist role. Chat alone is not a route: the member must select the route and invoke the matching workflow or explicitly choose the question path.
1236
1284
 
1237
- Use codegraph for codebase exploration when the environment exposes it. The index is local state and should not be committed.
1285
+ ## Route Matrix
1238
1286
 
1239
- - Check for an index: look for \`.codegraph/\`
1240
- - Check CLI availability: \`codegraph --help\`
1241
- - Install CLI if needed: \`npm install -g @colbymchenry/codegraph\`
1242
- - Codex MCP CLI setup: \`codex mcp add codegraph -- codegraph serve --mcp\`
1243
- - Auto setup: \`thachvd-kit\`
1244
- - If your Codex environment provides the codegraph CLI, run its project indexing step from the repository root.
1245
- - Keep \`.codegraph/\` ignored in git.
1287
+ | Situation | Command | Gate | Required next step |
1288
+ |---|---|---|---|
1289
+ | Explain, inspect, or brainstorm only | direct answer or \`/brainstorm\` | none | no code until the request becomes actionable |
1290
+ | One obvious local fix | \`/simple <request>\` | fast-path | inspect -> edit -> focused verify |
1291
+ | New behavior, multi-file change, unclear scope, or >~30 min | \`/task\` -> \`/brainstorm\` -> \`/spec\` when needed -> \`/plan\` | standard | wait for approval before implementation |
1292
+ | Bug, regression, failing test, or unknown error | \`/debug <symptom>\` | bug | reproduce -> isolate -> regression test -> fix -> verify |
1293
+ | Pre-merge or independent review | \`/review\` | review | five-axis review; resolve blocking findings |
1294
+ | Version, tag, npm publish, or deployment | \`/release\` | release | release checklist; never fast-path |
1295
+ | Frontend + backend + data/security together | \`/orchestrate\` | standard | plan -> approval -> specialist work -> integration verify |
1246
1296
 
1247
- Codex \`config.toml\` example:
1297
+ ## Standard Feature Flow
1248
1298
 
1249
- \`\`\`toml
1250
- [mcp_servers.codegraph]
1251
- command = "codegraph"
1252
- args = ["serve", "--mcp"]
1253
- startup_timeout_sec = 20
1254
- tool_timeout_sec = 120
1255
- \`\`\`
1299
+ The gated sequence is Spec -> Plan -> Implement -> Review: \`/task\` -> \`/brainstorm\` -> \`/spec\` when scope is ambiguous or multi-file -> \`/plan\` -> user approves the plan -> implementation -> \`/test\` -> \`/review\` -> final verification -> commit/push.
1256
1300
 
1257
- Codex reads MCP servers from \`~/.codex/config.toml\` by default. For repo-local setup, use \`.codex/config.toml\`; Codex loads project config only for trusted projects.
1301
+ The plan is a gate, not a suggestion. Do not start product-code implementation before explicit approval. Load only the relevant specialist agent and skills, such as \`$frontend-design\`, \`$api-design\`, or \`$webapp-testing\`.
1258
1302
 
1259
- Gemini CLI / Antigravity \`mcp_config.json\` example:
1303
+ ## Bug Fix Flow
1260
1304
 
1261
- \`\`\`json
1262
- {
1263
- "mcpServers": {
1264
- "codegraph": {
1265
- "command": "codegraph",
1266
- "args": ["serve", "--mcp"]
1267
- },
1268
- "context7": {
1269
- "command": "npx",
1270
- "args": ["-y", "@upstash/context7-mcp"]
1271
- },
1272
- "filesystem": {
1273
- "command": "npx",
1274
- "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
1275
- },
1276
- "playwright": {
1277
- "command": "npx",
1278
- "args": ["-y", "@playwright/mcp"]
1279
- }
1280
- }
1281
- }
1282
- \`\`\`
1305
+ Use \`/debug <symptom>\`, not the feature flow, when something is failing or the root cause is unknown:
1283
1306
 
1284
- Common local paths:
1307
+ 1. Capture the exact symptom, environment, reproduction, and expected result.
1308
+ 2. Inspect the relevant code path with MCP/codegraph when available.
1309
+ 3. Form and test a small number of hypotheses; do not patch by guesswork.
1310
+ 4. Add or update a regression test that fails before the fix when practical.
1311
+ 5. Make the smallest root-cause fix.
1312
+ 6. Run focused tests, then broader verification when the blast radius is shared.
1313
+ 7. Use \`/review\` when the fix touches multiple files, contracts, security, or release behavior.
1285
1314
 
1286
- - Gemini CLI: \`~/.gemini/config/mcp_config.json\`
1287
- - Antigravity IDE: \`~/.gemini/antigravity-ide/mcp_config.json\`
1288
- - Older Antigravity setups may use \`~/.gemini/antigravity/mcp_config.json\`
1315
+ Load \`$systematic-debugging\`, the \`debugger\` agent, and \`testing-patterns\` for this route.
1289
1316
 
1290
- Claude Code user config example:
1317
+ ## Simple Fast Path
1291
1318
 
1292
- \`\`\`json
1293
- {
1294
- "mcpServers": {
1295
- "codegraph": {
1296
- "type": "stdio",
1297
- "command": "codegraph",
1298
- "args": ["serve", "--mcp"]
1299
- },
1300
- "context7": {
1301
- "type": "stdio",
1302
- "command": "npx",
1303
- "args": ["-y", "@upstash/context7-mcp"]
1304
- },
1305
- "filesystem": {
1306
- "type": "stdio",
1307
- "command": "npx",
1308
- "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
1309
- },
1310
- "playwright": {
1311
- "type": "stdio",
1312
- "command": "npx",
1313
- "args": ["-y", "@playwright/mcp"]
1314
- }
1315
- }
1316
- }
1317
- \`\`\`
1319
+ Use \`/simple <request>\` only when the change is one obvious file, the result is unambiguous, and it changes no behavior, API, schema, security, CI, dependency, workflow, or release contract. Before editing, state:
1318
1320
 
1319
- Common local path:
1321
+ \`\`\`text
1322
+ FAST_PATH: simple-fix
1323
+ REASON: [why Spec/Plan/Review are not needed]
1324
+ SCOPE: [file or narrow area]
1325
+ \`\`\`
1320
1326
 
1321
- - Claude Code: \`~/.claude.json\` or \`~/.claude/settings.json\`
1327
+ This bypasses only Spec, Plan, and the feature/refactor Review gate. It never bypasses inspection, focused verification, or reporting evidence. If the scope expands, stop and re-route with \`/task\`.
1322
1328
 
1323
- ## Native Skill Folders
1329
+ ## Command And Skill Map
1324
1330
 
1325
- The shared kit skills live in \`.agent/skills/\`. Antigravity reads that folder directly. Codex shows skills from \`~/.codex/skills/\` in the \`$\` menu. Claude Code reads project skills from \`.claude/skills/\`.
1331
+ - \`/brainstorm\`: clarify intent and tradeoffs; no code.
1332
+ - \`/spec\`: define requirements and acceptance criteria; no code.
1333
+ - \`/plan\`: create an approved implementation plan; no code before approval.
1334
+ - \`/enhance\` or \`/create\`: implement an approved feature with the relevant specialist agent.
1335
+ - \`/debug\`: systematic root-cause investigation and regression protection.
1336
+ - \`/test\`: add or run tests and assess coverage.
1337
+ - \`/review\`: five-axis review before completion or merge.
1338
+ - \`/release\`: verify, version, tag, publish, and verify npm output.
1339
+ - \`$clean-code\` and \`$verification-before-completion\`: default implementation hygiene.
1340
+ - \`$webapp-testing\`: browser/UI verification; use Playwright when available.
1326
1341
 
1327
- - Codex global skills: \`~/.codex/skills/\` — installed by \`thachvd-kit init\`, visible in Codex \`$\` menu
1328
- - Claude Code project skills: \`.claude/skills/\`
1329
- - Antigravity: reads \`.agent/skills/\` directly (no copy needed)
1330
- - Keep \`.agent/skills/\` as the full shared source of truth committed with the repo.
1331
- - Do not commit \`~/.codex/skills/\`; it is local user state.
1342
+ ## Enforcement
1332
1343
 
1333
- Recommended candidates to copy first:
1344
+ Claude Code has a project Stop hook in \`.claude/settings.json\` for standard feature/refactor work. An explicit \`FAST_PATH: simple-fix\` is accepted only when the simple criteria are met; it still requires verification. Codex, Antigravity, and Cursor use the same written rules through \`AGENTS.md\`, \`.cursorrules\`, and \`.agent/rules/GEMINI.md\`.
1334
1345
 
1335
- - \`clean-code\`
1336
- - \`systematic-debugging\`
1337
- - \`verification-before-completion\`
1338
- - Stack-specific skills listed in \`.agent/docs/project.md\`
1346
+ Full details live in \`AGENTS.md\`, \`.agent/docs/workflow.md\`, and the matching file under \`.agent/workflows/\`.
1339
1347
  `;
1340
1348
  }
1341
1349
 
1342
- // --- Agent Folder Copy ---
1343
-
1344
- function copyAgentFolder() {
1345
- const srcAgent = path.join(sourceDir, '.agent');
1346
- if (!fs.existsSync(srcAgent)) return { copied: 0, skipped: 0 };
1347
-
1348
- const destAgent = path.join(targetDir, '.agent');
1349
- let copied = 0;
1350
-
1351
- function copyDir(src, dest) {
1352
- fs.mkdirSync(dest, { recursive: true });
1353
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
1354
- const srcPath = path.join(src, entry.name);
1355
- const destPath = path.join(dest, entry.name);
1356
- const relativeSrc = path.relative(srcAgent, srcPath).split(path.sep).join('/');
1357
- if (relativeSrc === 'docs' || relativeSrc.startsWith('docs/')) {
1358
- continue;
1359
- }
1360
- if (entry.isDirectory()) {
1361
- copyDir(srcPath, destPath);
1362
- } else {
1363
- fs.copyFileSync(srcPath, destPath);
1364
- copied++;
1365
- }
1366
- }
1367
- }
1368
-
1369
- copyDir(srcAgent, destAgent);
1370
- return { copied, skipped: 0 };
1371
- }
1372
-
1373
- function copySelectedSkillFolders(data, assumeYes) {
1374
- const srcSkills = path.join(sourceDir, '.agent', 'skills');
1375
- if (!fs.existsSync(srcSkills)) return { copied: 0, skipped: 0, missing: 0, skills: [] };
1376
-
1377
- const selectedSkills = resolveNativeSkills(data);
1378
-
1379
- // ~/.codex/skills/ — global Codex user skills dir, always visible in the $ menu
1380
- const codexSkillsDir = homePath('.codex', 'skills');
1381
- // .claude/skills/ — project-level Claude Code skills
1382
- const claudeSkillsDir = path.join(targetDir, '.claude', 'skills');
1383
-
1384
- const destinations = [claudeSkillsDir];
1385
- if (codexSkillsDir) destinations.push(codexSkillsDir);
1386
-
1387
- let copied = 0;
1388
- let missing = 0;
1389
-
1390
- function copyDir(src, dest) {
1391
- fs.mkdirSync(dest, { recursive: true });
1392
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
1393
- const srcPath = path.join(src, entry.name);
1394
- const destPath = path.join(dest, entry.name);
1395
- if (entry.isDirectory()) {
1396
- copyDir(srcPath, destPath);
1397
- } else {
1398
- fs.mkdirSync(path.dirname(destPath), { recursive: true });
1399
- fs.copyFileSync(srcPath, destPath);
1400
- copied++;
1401
- }
1402
- }
1403
- }
1404
-
1405
- for (const skill of selectedSkills) {
1406
- const srcSkill = path.join(srcSkills, skill);
1407
- if (!fs.existsSync(srcSkill)) {
1408
- missing++;
1409
- continue;
1410
- }
1411
- for (const destSkills of destinations) {
1412
- copyDir(srcSkill, path.join(destSkills, skill));
1413
- }
1414
- }
1415
-
1416
- return { copied, skipped: 0, missing, skills: selectedSkills };
1417
- }
1418
-
1419
- async function writeGeneratedFile(relativePath, content, assumeYes) {
1420
- const outputPath = path.join(targetDir, relativePath);
1421
- const exists = fs.existsSync(outputPath);
1422
- if (exists && !assumeYes) {
1423
- const response = await prompts({
1424
- type: 'confirm',
1425
- name: 'overwrite',
1426
- message: `File ${pc.bold(relativePath)} already exists. Do you want to overwrite it?`,
1427
- initial: false
1428
- });
1429
- if (response.overwrite === undefined) {
1430
- console.log(pc.yellow('\nCancelled.'));
1431
- process.exit(130);
1432
- }
1433
- if (!response.overwrite) return false;
1434
- }
1435
-
1436
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
1437
- fs.writeFileSync(outputPath, content, 'utf8');
1438
- return true;
1439
- }
1440
-
1441
- function homePath(...parts) {
1442
- const home = process.env.USERPROFILE || process.env.HOME;
1443
- return home ? path.join(home, ...parts) : null;
1444
- }
1445
-
1446
- function commandExists(command) {
1447
- const checker = process.platform === 'win32' ? 'where' : 'command';
1448
- const args = process.platform === 'win32' ? [command] : ['-v', command];
1449
- const result = spawnSync(checker, args, { encoding: 'utf8', shell: process.platform !== 'win32' });
1450
- return result.status === 0;
1451
- }
1452
-
1453
- function ensureCodegraphCli() {
1454
- if (commandExists('codegraph')) {
1455
- return { ok: true, message: 'codegraph CLI already installed' };
1456
- }
1457
- if (!commandExists('npm')) {
1458
- return { ok: false, message: 'npm not found; run: npm install -g @colbymchenry/codegraph' };
1459
- }
1460
- const result = spawnSync('npm', ['install', '-g', '@colbymchenry/codegraph'], {
1461
- encoding: 'utf8',
1462
- stdio: 'pipe'
1463
- });
1464
- if (result.status !== 0) {
1465
- return { ok: false, message: 'failed to install codegraph; run: npm install -g @colbymchenry/codegraph' };
1466
- }
1467
- return { ok: true, message: 'installed codegraph CLI' };
1468
- }
1350
+ function resolveToolingSetup(data) {
1351
+ const primaryLang = data.primary_language || 'javascript';
1352
+ const packageManager = data.package_manager || 'npm';
1353
+ const isPython = primaryLang === 'python';
1354
+ const runner = packageManager === 'pnpm'
1355
+ ? 'pnpm dlx'
1356
+ : packageManager === 'yarn'
1357
+ ? 'yarn dlx'
1358
+ : packageManager === 'bun'
1359
+ ? 'bunx'
1360
+ : 'npx';
1361
+ const playwrightCommand = isPython
1362
+ ? 'pip install playwright && playwright install chromium'
1363
+ : `${runner} playwright install`;
1364
+
1365
+ return { runner, playwrightCommand };
1366
+ }
1367
+
1368
+ function generateToolingDoc(data) {
1369
+ const { runner, playwrightCommand } = resolveToolingSetup(data);
1370
+
1371
+ return `# Optional Tooling
1372
+
1373
+ This kit keeps tool setup explicit. Do not assume these tools are available until you verify them in the current environment.
1374
+
1375
+ ## Playwright
1376
+
1377
+ Use Playwright for browser and UI verification when a task touches web behavior.
1378
+
1379
+ - Check availability: \`${runner} playwright --version\`
1380
+ - Install browsers: \`${playwrightCommand}\`
1381
+ - Codex MCP CLI setup: \`codex mcp add playwright -- playwright-mcp\`
1382
+ - Auto setup: \`thachvd-kit\`
1383
+ - Kit helper: \`python .agent/skills/webapp-testing/scripts/playwright_runner.py <url> --screenshot\`
1384
+
1385
+ If the project already has Playwright configured, prefer the project's existing scripts.
1386
+
1387
+ Codex \`config.toml\` example:
1388
+
1389
+ \`\`\`toml
1390
+ [mcp_servers.context7]
1391
+ command = "context7-mcp"
1392
+ startup_timeout_sec = 20
1393
+ tool_timeout_sec = 120
1394
+
1395
+ [mcp_servers.filesystem]
1396
+ command = "npx"
1397
+ args = ["-y", "@modelcontextprotocol/server-filesystem", "<projectPath>"]
1398
+ startup_timeout_sec = 20
1399
+ tool_timeout_sec = 120
1400
+
1401
+ [mcp_servers.playwright]
1402
+ command = "playwright-mcp"
1403
+ startup_timeout_sec = 20
1404
+ tool_timeout_sec = 120
1405
+ \`\`\`
1406
+
1407
+ ## Codegraph
1408
+
1409
+ Use codegraph for codebase exploration when the environment exposes it. The index is local state and should not be committed.
1410
+
1411
+ - Check for an index: look for \`.codegraph/\`
1412
+ - Check CLI availability: \`codegraph --help\`
1413
+ - Install CLI if needed: \`npm install -g @colbymchenry/codegraph\`
1414
+ - Codex MCP CLI setup: \`codex mcp add codegraph -- codegraph serve --mcp\`
1415
+ - Auto setup: \`thachvd-kit\`
1416
+ - If your Codex environment provides the codegraph CLI, run its project indexing step from the repository root.
1417
+ - Keep \`.codegraph/\` ignored in git.
1418
+
1419
+ Codex \`config.toml\` example:
1420
+
1421
+ \`\`\`toml
1422
+ [mcp_servers.codegraph]
1423
+ command = "codegraph"
1424
+ args = ["serve", "--mcp"]
1425
+ startup_timeout_sec = 20
1426
+ tool_timeout_sec = 120
1427
+ \`\`\`
1428
+
1429
+ Codex reads MCP servers from \`~/.codex/config.toml\` by default. For repo-local setup, use \`.codex/config.toml\`; Codex loads project config only for trusted projects.
1430
+
1431
+ Gemini CLI / Antigravity \`mcp_config.json\` example:
1432
+
1433
+ \`\`\`json
1434
+ {
1435
+ "mcpServers": {
1436
+ "codegraph": {
1437
+ "command": "codegraph",
1438
+ "args": ["serve", "--mcp"]
1439
+ },
1440
+ "context7": {
1441
+ "command": "context7-mcp"
1442
+ },
1443
+ "filesystem": {
1444
+ "command": "npx",
1445
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
1446
+ },
1447
+ "playwright": {
1448
+ "command": "playwright-mcp"
1449
+ }
1450
+ }
1451
+ }
1452
+ \`\`\`
1453
+
1454
+ Common local paths:
1455
+
1456
+ - Gemini CLI: \`~/.gemini/config/mcp_config.json\`
1457
+ - Antigravity IDE: \`~/.gemini/antigravity-ide/mcp_config.json\`
1458
+ - Older Antigravity setups may use \`~/.gemini/antigravity/mcp_config.json\`
1459
+
1460
+ Claude Code user config example:
1461
+
1462
+ \`\`\`json
1463
+ {
1464
+ "mcpServers": {
1465
+ "codegraph": {
1466
+ "type": "stdio",
1467
+ "command": "codegraph",
1468
+ "args": ["serve", "--mcp"]
1469
+ },
1470
+ "context7": {
1471
+ "type": "stdio",
1472
+ "command": "context7-mcp"
1473
+ },
1474
+ "filesystem": {
1475
+ "type": "stdio",
1476
+ "command": "npx",
1477
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
1478
+ },
1479
+ "playwright": {
1480
+ "type": "stdio",
1481
+ "command": "playwright-mcp"
1482
+ }
1483
+ }
1484
+ }
1485
+ \`\`\`
1486
+
1487
+ Common local path:
1488
+
1489
+ - Claude Code: \`~/.claude.json\` or \`~/.claude/settings.json\`
1490
+
1491
+ ## Native Skill Folders
1492
+
1493
+ The shared kit skills live in \`.agent/skills/\`. Antigravity reads that folder directly. Codex shows skills from \`~/.codex/skills/\` in the \`$\` menu. Claude Code reads project skills from \`.claude/skills/\`.
1494
+
1495
+ - Codex global skills: \`~/.codex/skills/\` — installed by \`thachvd-kit init\`, visible in Codex \`$\` menu
1496
+ - Claude Code project skills: \`.claude/skills/\`
1497
+ - Antigravity: reads \`.agent/skills/\` directly (no copy needed)
1498
+ - Keep \`.agent/skills/\` as the full shared source of truth committed with the repo.
1499
+ - Do not commit \`~/.codex/skills/\`; it is local user state.
1500
+
1501
+ Recommended candidates to copy first:
1502
+
1503
+ - \`clean-code\`
1504
+ - \`systematic-debugging\`
1505
+ - \`verification-before-completion\`
1506
+ - Stack-specific skills listed in \`.agent/docs/project.md\`
1507
+ `;
1508
+ }
1509
+
1510
+ // --- Agent Folder Copy ---
1511
+
1512
+ function copyAgentFolder() {
1513
+ const srcAgent = path.join(sourceDir, '.agent');
1514
+ if (!fs.existsSync(srcAgent)) return { copied: 0, skipped: 0 };
1515
+
1516
+ const destAgent = path.join(targetDir, '.agent');
1517
+ let copied = 0;
1518
+
1519
+ function copyDir(src, dest) {
1520
+ fs.mkdirSync(dest, { recursive: true });
1521
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
1522
+ const srcPath = path.join(src, entry.name);
1523
+ const destPath = path.join(dest, entry.name);
1524
+ const relativeSrc = path.relative(srcAgent, srcPath).split(path.sep).join('/');
1525
+ if (relativeSrc === 'docs' || relativeSrc.startsWith('docs/')) {
1526
+ continue;
1527
+ }
1528
+ if (entry.isDirectory()) {
1529
+ copyDir(srcPath, destPath);
1530
+ } else {
1531
+ fs.copyFileSync(srcPath, destPath);
1532
+ copied++;
1533
+ }
1534
+ }
1535
+ }
1536
+
1537
+ copyDir(srcAgent, destAgent);
1538
+ return { copied, skipped: 0 };
1539
+ }
1540
+
1541
+ function copySelectedSkillFolders(data, assumeYes) {
1542
+ const srcSkills = path.join(sourceDir, '.agent', 'skills');
1543
+ if (!fs.existsSync(srcSkills)) return { copied: 0, skipped: 0, missing: 0, skills: [] };
1544
+
1545
+ const selectedSkills = resolveNativeSkills(data);
1546
+
1547
+ // ~/.codex/skills/ — global Codex user skills dir, always visible in the $ menu
1548
+ const codexSkillsDir = homePath('.codex', 'skills');
1549
+ // .claude/skills/ — project-level Claude Code skills
1550
+ const claudeSkillsDir = path.join(targetDir, '.claude', 'skills');
1551
+
1552
+ const destinations = [claudeSkillsDir];
1553
+ if (codexSkillsDir) destinations.push(codexSkillsDir);
1554
+
1555
+ let copied = 0;
1556
+ let missing = 0;
1557
+
1558
+ function copyDir(src, dest) {
1559
+ fs.mkdirSync(dest, { recursive: true });
1560
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
1561
+ const srcPath = path.join(src, entry.name);
1562
+ const destPath = path.join(dest, entry.name);
1563
+ if (entry.isDirectory()) {
1564
+ copyDir(srcPath, destPath);
1565
+ } else {
1566
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
1567
+ fs.copyFileSync(srcPath, destPath);
1568
+ copied++;
1569
+ }
1570
+ }
1571
+ }
1572
+
1573
+ for (const skill of selectedSkills) {
1574
+ const srcSkill = path.join(srcSkills, skill);
1575
+ if (!fs.existsSync(srcSkill)) {
1576
+ missing++;
1577
+ continue;
1578
+ }
1579
+ for (const destSkills of destinations) {
1580
+ copyDir(srcSkill, path.join(destSkills, skill));
1581
+ }
1582
+ }
1583
+
1584
+ return { copied, skipped: 0, missing, skills: selectedSkills };
1585
+ }
1586
+
1587
+ async function writeGeneratedFile(relativePath, content, assumeYes) {
1588
+ const outputPath = path.join(targetDir, relativePath);
1589
+ const exists = fs.existsSync(outputPath);
1590
+ if (exists && !assumeYes) {
1591
+ const response = await prompts({
1592
+ type: 'confirm',
1593
+ name: 'overwrite',
1594
+ message: `File ${pc.bold(relativePath)} already exists. Do you want to overwrite it?`,
1595
+ initial: false
1596
+ });
1597
+ if (response.overwrite === undefined) {
1598
+ console.log(pc.yellow('\nCancelled.'));
1599
+ process.exit(130);
1600
+ }
1601
+ if (!response.overwrite) return false;
1602
+ }
1603
+
1604
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
1605
+ fs.writeFileSync(outputPath, content, 'utf8');
1606
+ return true;
1607
+ }
1608
+
1609
+ function homePath(...parts) {
1610
+ const home = process.env.USERPROFILE || process.env.HOME;
1611
+ return home ? path.join(home, ...parts) : null;
1612
+ }
1613
+
1614
+ function commandExists(command) {
1615
+ const checker = process.platform === 'win32' ? 'where' : 'command';
1616
+ const args = process.platform === 'win32' ? [command] : ['-v', command];
1617
+ const result = spawnSync(checker, args, { encoding: 'utf8', shell: process.platform !== 'win32' });
1618
+ return result.status === 0;
1619
+ }
1620
+
1621
+ function ensureGlobalNpmPackage(binaryName, packageName) {
1622
+ if (commandExists(binaryName)) {
1623
+ return { ok: true, message: `${binaryName} already installed` };
1624
+ }
1625
+ if (!commandExists('npm')) {
1626
+ return { ok: false, message: `npm not found; run: npm install -g ${packageName}` };
1627
+ }
1628
+ const result = spawnSync('npm', ['install', '-g', packageName], {
1629
+ encoding: 'utf8',
1630
+ stdio: 'pipe'
1631
+ });
1632
+ if (result.status !== 0) {
1633
+ return { ok: false, message: `failed to install ${binaryName}; run: npm install -g ${packageName}` };
1634
+ }
1635
+ return { ok: true, message: `installed ${binaryName}` };
1636
+ }
1637
+
1638
+ function ensureCodegraphCli() {
1639
+ return ensureGlobalNpmPackage('codegraph', '@colbymchenry/codegraph');
1640
+ }
1641
+
1642
+ function ensureContext7Cli() {
1643
+ return ensureGlobalNpmPackage('context7-mcp', '@upstash/context7-mcp');
1644
+ }
1645
+
1646
+ function ensurePlaywrightMcpCli() {
1647
+ return ensureGlobalNpmPackage('playwright-mcp', '@playwright/mcp');
1648
+ }
1649
+
1650
+ function readJsonFile(filePath) {
1651
+ if (!fs.existsSync(filePath)) return {};
1652
+ try {
1653
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
1654
+ } catch {
1655
+ return null;
1656
+ }
1657
+ }
1658
+
1659
+ function writeJsonFile(filePath, data) {
1660
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
1661
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
1662
+ }
1663
+
1664
+ function mergeMcpJson(filePath, withType = false) {
1665
+ const data = readJsonFile(filePath);
1666
+ if (data === null) {
1667
+ return { ok: false, message: `${filePath} is not valid JSON; skipped` };
1668
+ }
1669
+ data.mcpServers = data.mcpServers || {};
1670
+ const baseServers = {
1671
+ codegraph: { command: 'codegraph', args: ['serve', '--mcp'] },
1672
+ playwright: { command: 'playwright-mcp' },
1673
+ context7: { command: 'context7-mcp' }
1674
+ };
1675
+ if (data.permissions && Array.isArray(data.permissions.allow)) {
1676
+ const requiredPermissions = [
1677
+ "mcp__context7__resolve-library-id",
1678
+ "mcp__context7__query-docs"
1679
+ ];
1680
+ for (const perm of requiredPermissions) {
1681
+ if (!data.permissions.allow.includes(perm)) {
1682
+ data.permissions.allow.push(perm);
1683
+ }
1684
+ }
1685
+ }
1686
+ for (const [name, server] of Object.entries(baseServers)) {
1687
+ if (!data.mcpServers[name]) {
1688
+ data.mcpServers[name] = withType ? { type: 'stdio', ...server } : server;
1689
+ }
1690
+ }
1691
+ writeJsonFile(filePath, data);
1692
+ const tools = Object.keys(baseServers).join(', ');
1693
+ return { ok: true, message: `configured ${tools} MCP in ${filePath}` };
1694
+ }
1695
+
1696
+ function appendMcpTomlIfMissing(filePath) {
1697
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
1698
+ const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
1699
+ const blocks = [];
1700
+ if (!/\[mcp_servers\.context7\]/.test(existing)) {
1701
+ blocks.push(`[mcp_servers.context7]
1702
+ command = "context7-mcp"
1703
+ startup_timeout_sec = 20
1704
+ tool_timeout_sec = 120
1705
+ `);
1706
+ }
1707
+ if (!/\[mcp_servers\.codegraph\]/.test(existing)) {
1708
+ blocks.push(`[mcp_servers.codegraph]
1709
+ command = "codegraph"
1710
+ args = ["serve", "--mcp"]
1711
+ startup_timeout_sec = 20
1712
+ tool_timeout_sec = 120
1713
+ `);
1714
+ }
1715
+ if (!/\[mcp_servers\.playwright\]/.test(existing)) {
1716
+ blocks.push(`[mcp_servers.playwright]
1717
+ command = "playwright-mcp"
1718
+ startup_timeout_sec = 20
1719
+ tool_timeout_sec = 120
1720
+ `);
1721
+ }
1722
+ if (blocks.length === 0) { return { ok: true, message: `already configured ${filePath}` };
1723
+ }
1724
+ const separator = existing && !existing.endsWith('\n') ? '\n\n' : existing ? '\n' : '';
1725
+ fs.writeFileSync(filePath, existing + separator + blocks.join('\n'), 'utf8');
1726
+ return { ok: true, message: `configured context7, codegraph, playwright MCP in ${filePath}` };
1727
+ }
1728
+
1729
+ const DOD_HOOK_MARKER = 'feature/refactor Definition-of-Done gate';
1469
1730
 
1470
- function readJsonFile(filePath) {
1471
- if (!fs.existsSync(filePath)) return {};
1472
- try {
1473
- return JSON.parse(fs.readFileSync(filePath, 'utf8'));
1474
- } catch {
1475
- return null;
1476
- }
1731
+ function generateDodStopHookPrompt() {
1732
+ return `Input JSON (Stop hook payload): $ARGUMENTS\n\nCheck this project's ${DOD_HOOK_MARKER} (defined in AGENTS.md "Gated Flow" and .agent/docs/workflow.md "Definition of Done"). Use the \`last_assistant_message\` field as the authoritative final response. Use \`transcript_path\` only for additional context because the transcript may not contain the final response yet.\n\nFor a feature or refactor (multi-file change, new behavior, or non-trivial refactor), the work must go through spec -> plan -> implement -> review before being reported as complete:\n- spec: \`.agent/workflows/spec.md\` (skip allowed for trivial/self-contained changes)\n- plan: \`.agent/workflows/plan.md\`, with a plan artifact such as \`docs/PLAN-*.md\` and explicit user approval\n- review: \`.agent/workflows/review.md\` five-axis review, with blocking issues resolved\n\nSimple/self-contained fixes (single-line, typo, or unambiguous one-file change) may use /simple and are explicitly exempt from spec+plan+review only when the final response states FAST_PATH: simple-fix, its reason, and its narrow scope. They should never be blocked when those criteria are met. Verification is still mandatory.\n\nSteps:\n1. If the input JSON has \`stop_hook_active: true\`, allow stopping immediately (already checked once this cycle; never block twice in a row).\n2. Inspect the changed files and the \`last_assistant_message\` field.\n3. If no source files changed, the final response does not claim the task is done/complete, or the final response explicitly contains FAST_PATH: simple-fix and the changed scope is clearly a simple/self-contained fix, allow stopping.\n4. If it is a feature/refactor-scale change and the final response claims completion, verify that a plan artifact exists with evidence of user approval and that a review pass was completed. If either gate is missing, block; a generic statement that the task was simple is not enough.\n5. Return exactly JSON: {"ok": true} to allow stopping, or {"ok": false, "reason": "..."} to block.\n\nWhen blocking, name exactly which gate is missing and instruct the assistant to run the relevant workflow or explicitly state why the task qualifies as a simple fix.`;
1477
1733
  }
1478
1734
 
1479
- function writeJsonFile(filePath, data) {
1480
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
1481
- fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
1735
+ function isDefinitionOfDoneHook(hook) {
1736
+ const prompt = hook && typeof hook.prompt === 'string' ? hook.prompt : '';
1737
+ return prompt.includes(DOD_HOOK_MARKER) || (
1738
+ prompt.includes('Input JSON (Stop hook payload)') &&
1739
+ prompt.includes('.agent/workflows/spec.md') &&
1740
+ prompt.includes('.agent/workflows/review.md')
1741
+ );
1482
1742
  }
1483
1743
 
1484
- function mergeMcpJson(filePath, withType = false) {
1744
+ function mergeClaudeProjectHooks(filePath) {
1485
1745
  const data = readJsonFile(filePath);
1486
1746
  if (data === null) {
1487
- return { ok: false, message: `${filePath} is not valid JSON; skipped` };
1747
+ return { ok: false, message: `${filePath} is not valid JSON; skipped hook setup` };
1488
1748
  }
1489
- data.mcpServers = data.mcpServers || {};
1490
- const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
1491
- const baseServers = {
1492
- codegraph: { command: 'codegraph', args: ['serve', '--mcp'] },
1493
- playwright: { command: npxCmd, args: ['-y', '@playwright/mcp'] },
1494
- context7: { command: npxCmd, args: ['-y', '@upstash/context7-mcp'] }
1495
- };
1496
- if (data.permissions && Array.isArray(data.permissions.allow)) {
1497
- const requiredPermissions = [
1498
- "mcp__context7__resolve-library-id",
1499
- "mcp__context7__query-docs"
1500
- ];
1501
- for (const perm of requiredPermissions) {
1502
- if (!data.permissions.allow.includes(perm)) {
1503
- data.permissions.allow.push(perm);
1749
+ if (!data.hooks || typeof data.hooks !== 'object') data.hooks = {};
1750
+ if (!Array.isArray(data.hooks.Stop)) data.hooks.Stop = [];
1751
+
1752
+ let primaryHook = null;
1753
+ let definitionHookCount = 0;
1754
+ for (const entry of data.hooks.Stop) {
1755
+ for (const hook of Array.isArray(entry?.hooks) ? entry.hooks : []) {
1756
+ if (isDefinitionOfDoneHook(hook)) {
1757
+ definitionHookCount++;
1758
+ if (!primaryHook) primaryHook = hook;
1504
1759
  }
1505
1760
  }
1506
1761
  }
1507
- for (const [name, server] of Object.entries(baseServers)) {
1508
- if (!data.mcpServers[name]) {
1509
- data.mcpServers[name] = withType ? { type: 'stdio', ...server } : server;
1510
- }
1511
- }
1512
- writeJsonFile(filePath, data);
1513
- const tools = Object.keys(baseServers).join(', ');
1514
- return { ok: true, message: `configured ${tools} MCP in ${filePath}` };
1515
- }
1516
-
1517
- function appendMcpTomlIfMissing(filePath) {
1518
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
1519
- const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
1520
- const blocks = [];
1521
- const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
1522
- if (!/\[mcp_servers\.context7\]/.test(existing)) {
1523
- blocks.push(`[mcp_servers.context7]
1524
- command = "${npxCmd}"
1525
- args = ["-y", "@upstash/context7-mcp"]
1526
- startup_timeout_sec = 20
1527
- tool_timeout_sec = 120
1528
- `);
1529
- }
1530
- if (!/\[mcp_servers\.codegraph\]/.test(existing)) {
1531
- blocks.push(`[mcp_servers.codegraph]
1532
- command = "codegraph"
1533
- args = ["serve", "--mcp"]
1534
- startup_timeout_sec = 20
1535
- tool_timeout_sec = 120
1536
- `);
1537
- }
1538
- if (!/\[mcp_servers\.playwright\]/.test(existing)) {
1539
- blocks.push(`[mcp_servers.playwright]
1540
- command = "${npxCmd}"
1541
- args = ["-y", "@playwright/mcp"]
1542
- startup_timeout_sec = 20
1543
- tool_timeout_sec = 120
1544
- `);
1545
- }
1546
- if (blocks.length === 0) {
1547
- return { ok: true, message: `already configured ${filePath}` };
1548
- }
1549
- const separator = existing && !existing.endsWith('\n') ? '\n\n' : existing ? '\n' : '';
1550
- fs.writeFileSync(filePath, existing + separator + blocks.join('\n'), 'utf8');
1551
- return { ok: true, message: `configured context7, codegraph, playwright MCP in ${filePath}` };
1552
- }
1553
-
1554
- function setupMcpServers() {
1555
- const results = [];
1556
- results.push(ensureCodegraphCli());
1557
-
1558
- const codexConfig = homePath('.codex', 'config.toml');
1559
- if (codexConfig) results.push(appendMcpTomlIfMissing(codexConfig));
1560
-
1561
- const geminiConfig = homePath('.gemini', 'config', 'mcp_config.json');
1562
- if (geminiConfig) results.push(mergeMcpJson(geminiConfig, false));
1563
-
1564
- const antigravityIdeConfig = homePath('.gemini', 'antigravity-ide', 'mcp_config.json');
1565
- if (antigravityIdeConfig) results.push(mergeMcpJson(antigravityIdeConfig, false));
1566
-
1567
- const antigravityConfig = homePath('.gemini', 'antigravity', 'mcp_config.json');
1568
- if (antigravityConfig && fs.existsSync(path.dirname(antigravityConfig))) {
1569
- results.push(mergeMcpJson(antigravityConfig, false));
1570
- }
1571
-
1572
- const claudeConfig = homePath('.claude.json');
1573
- if (claudeConfig) results.push(mergeMcpJson(claudeConfig, true));
1574
-
1575
- const claudeSettings = homePath('.claude', 'settings.json');
1576
- if (claudeSettings) results.push(mergeMcpJson(claudeSettings, true));
1577
-
1578
- return results;
1579
- }
1580
-
1581
- // --- Main CLI ---
1582
-
1583
- async function main() {
1584
- const rawArgs = process.argv.slice(2);
1585
- const command = rawArgs[0] && !rawArgs[0].startsWith('-') ? rawArgs[0] : 'init';
1586
- const args = command === 'init' ? rawArgs.slice(rawArgs[0] === 'init' ? 1 : 0) : rawArgs.slice(1);
1587
-
1588
- if (rawArgs.includes('--version') || rawArgs.includes('-v')) {
1589
- console.log(packageJson.version);
1590
- return;
1591
- }
1592
1762
 
1593
- if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
1594
- printHelp();
1595
- return;
1596
- }
1763
+ if (primaryHook) {
1764
+ primaryHook.prompt = generateDodStopHookPrompt();
1765
+ primaryHook.timeout = 60;
1766
+ primaryHook.statusMessage = 'Checking feature/refactor Definition-of-Done gate...';
1767
+
1768
+ if (definitionHookCount > 1) {
1769
+ data.hooks.Stop = data.hooks.Stop
1770
+ .map(entry => ({
1771
+ ...entry,
1772
+ hooks: (Array.isArray(entry?.hooks) ? entry.hooks : [])
1773
+ .filter(hook => !isDefinitionOfDoneHook(hook) || hook === primaryHook)
1774
+ }))
1775
+ .filter(entry => entry.hooks.length > 0);
1776
+ }
1597
1777
 
1598
- if (command !== 'init') {
1599
- console.error(pc.red(`Unknown command: ${command}`));
1600
- printHelp();
1601
- process.exit(1);
1778
+ writeJsonFile(filePath, data);
1779
+ return {
1780
+ ok: true,
1781
+ message: definitionHookCount > 1
1782
+ ? `consolidated Definition-of-Done Stop hooks in ${filePath}`
1783
+ : `updated Definition-of-Done Stop hook in ${filePath}`
1784
+ };
1602
1785
  }
1603
1786
 
1604
- const assumeYes = args.includes('--yes') || args.includes('-y');
1605
- const skipMcpSetup = args.includes('--no-setup-mcp') || process.env.THACHVD_KIT_SKIP_MCP_SETUP === '1';
1606
-
1607
- console.log(pc.bold(pc.cyan('='.repeat(50))));
1608
- console.log(' ' + pc.bold('thachvd-kit') + ' - AI Project Bootstrap');
1609
- console.log(' Generates shared agent rules and configures MCP tooling');
1610
- console.log(pc.bold(pc.cyan('='.repeat(50))));
1611
-
1612
- console.log(pc.dim(' Scanning current project files for a baseline...\n'));
1613
- const scanned = scanProject();
1614
-
1615
- console.log(` ${pc.bold('Detected context:')}`);
1616
- formatScanPreviewLines(scanned).forEach(([label, value]) => {
1617
- console.log(` - ${label}: ${value}`);
1787
+ data.hooks.Stop.push({
1788
+ hooks: [
1789
+ {
1790
+ type: 'agent',
1791
+ prompt: generateDodStopHookPrompt(),
1792
+ timeout: 60,
1793
+ statusMessage: 'Checking feature/refactor Definition-of-Done gate...'
1794
+ }
1795
+ ]
1618
1796
  });
1619
- console.log('');
1620
- if ((scanned.scan_evidence || []).length > 0) {
1621
- console.log(` ${pc.bold('Evidence:')}`);
1622
- scanned.scan_evidence.forEach(line => console.log(` - ${line}`));
1623
- console.log('');
1624
- }
1625
-
1626
- // Combine data
1627
- const data = {
1628
- project_name: scanned?.project_name || path.basename(targetDir),
1629
- description: scanned?.description || 'A software project',
1630
- project_type: scanned?.project_type || 'web-app',
1631
- primary_language: scanned?.primary_language || 'typescript',
1632
- frameworks: scanned?.frameworks || [],
1633
- database: scanned?.database || 'none',
1634
- uses_docker: scanned?.uses_docker ?? true,
1635
- cloud: scanned?.cloud || 'none',
1636
- package_manager: scanned?.package_manager || 'auto-detect',
1637
- test_framework: scanned?.test_framework || 'auto-detect',
1638
- max_file_lines: scanned?.max_file_lines || '300'
1639
- };
1640
-
1641
- data.database = data.database || scanned?.database || 'none';
1642
- data.uses_docker = typeof data.uses_docker === 'boolean' ? data.uses_docker : (scanned?.uses_docker ?? true);
1643
- data.cloud = data.cloud || scanned?.cloud || 'none';
1644
- data.package_manager = data.package_manager || scanned?.package_manager || 'auto-detect';
1645
- data.test_framework = data.test_framework || scanned?.test_framework || 'auto-detect';
1646
- data.max_file_lines = data.max_file_lines || scanned?.max_file_lines || '300';
1647
- data.framework_details = scanned?.framework_details || [];
1648
- data.scan_evidence = scanned?.scan_evidence || [];
1649
- data.app_root = scanned?.app_root || '.';
1650
-
1651
- data.infrastructure = [];
1652
- if (data.uses_docker) data.infrastructure.push('docker');
1653
- if (data.cloud !== 'none') data.infrastructure.push(data.cloud);
1654
-
1655
- const shouldSetupMcp = !skipMcpSetup;
1656
-
1657
- console.log(`\n${pc.bold(pc.cyan('Generating Files'))}`);
1658
-
1659
- // Shared entry files are written after the .agent folder is available.
1660
-
1661
- // Copy .agent folder
1662
- const { copied, skipped } = copyAgentFolder();
1663
- if (copied > 0) {
1664
- console.log(` ${pc.green('OK')} Copied ${pc.bold('.agent/')} (${copied} file${copied !== 1 ? 's' : ''} added${skipped > 0 ? `, ${skipped} skipped` : ''})`);
1665
- } else if (skipped > 0) {
1666
- console.log(` ${pc.yellow('~')} ${pc.bold('.agent/')} already exists - ${skipped} file${skipped !== 1 ? 's' : ''} skipped (no overwrite)`);
1667
- }
1668
-
1669
- const nativeSkills = copySelectedSkillFolders(data, assumeYes);
1670
- if (nativeSkills.copied > 0) {
1671
- console.log(` ${pc.green('OK')} Copied native skills to ${pc.bold('~/.codex/skills/')} and ${pc.bold('.claude/skills/')} (${nativeSkills.skills.join(', ')})`);
1672
- } else if (nativeSkills.skipped > 0) {
1673
- console.log(` ${pc.yellow('~')} Native skills already exist - ${nativeSkills.skipped} file${nativeSkills.skipped !== 1 ? 's' : ''} skipped`);
1674
- }
1675
-
1676
-
1677
- const generatedFiles = [
1678
- ['AGENTS.md', generateSharedAgentsMd(data)],
1679
- ['CLAUDE.md', generateSharedClaudeMd(data)],
1680
- ['GEMINI.md', generateSharedGeminiMd()],
1681
- ['.cursorrules', generateSharedCursorrules(data)],
1682
- [path.join('.agent', 'docs', 'project.md'), generateProjectDoc(data)],
1683
- [path.join('.agent', 'docs', 'architecture.md'), generateArchitectureDoc(data)],
1684
- [path.join('.agent', 'docs', 'conventions.md'), generateConventionsDoc(data)],
1685
- [path.join('.agent', 'docs', 'workflow.md'), generateWorkflowDoc()],
1686
- [path.join('.agent', 'docs', 'tooling.md'), generateToolingDoc(data)]
1687
- ];
1688
-
1689
- for (const [relativePath, content] of generatedFiles) {
1690
- const wrote = await writeGeneratedFile(relativePath, content, assumeYes);
1691
- if (wrote) console.log(` ${pc.green('OK')} Generated ${pc.bold(relativePath)}`);
1692
- else console.log(` ${pc.yellow('~')} Skipped ${pc.bold(relativePath)}`);
1693
- }
1694
-
1695
- if (shouldSetupMcp) {
1696
- console.log(`\n${pc.bold(pc.cyan('Configuring MCP'))}`);
1697
- for (const result of setupMcpServers()) {
1698
- const marker = result.ok ? pc.green('OK') : pc.yellow('~');
1699
- console.log(` ${marker} ${result.message}`);
1700
- }
1701
- }
1702
-
1703
- console.log(`\n${pc.bold(pc.green('Done!'))}
1704
-
1705
- ${pc.bold('Project:')} ${data.project_name}
1706
- ${pc.bold('Stack:')} ${data.primary_language} | ${(data.frameworks || []).join(', ') || 'no framework'}
1707
-
1708
- ${pc.bold('Generated:')}
1709
- - ${pc.bold('AGENTS.md')} shared entry for Codex, Antigravity, Claude Code, and Cursor
1710
- - ${pc.bold('CLAUDE.md')} Claude Code entry that imports AGENTS.md
1711
- - ${pc.bold('GEMINI.md')} Antigravity entry
1712
- - ${pc.bold('.cursorrules')} Cursor entry
1713
- - ${pc.bold('.agent/docs/')} scan-based project rules
1714
- - ${pc.bold('.agent/')} skills, workflows, agents, and rules
1715
- - ${pc.bold('~/.codex/skills/')} selected Codex skills installed globally (visible in $ menu)
1716
- - ${pc.bold('.claude/skills/')} selected Claude Code native skills
1717
-
1718
- ${pc.bold('MCP/tooling setup:')}
1719
- - Codegraph CLI checked or installed; MCP configured for Codex, Gemini/Antigravity, and Claude Code
1720
- - Context7 MCP configured for Codex and Gemini/Antigravity
1721
- - Playwright MCP configured for Codex, Gemini/Antigravity, and Claude Code
1722
- - Browser install hint: ${pc.bold(resolveToolingSetup(data).playwrightCommand)}
1723
- - Codegraph index hint: run ${pc.bold('codegraph init -i')} when a project index is missing, then keep ${pc.bold('.codegraph/')} uncommitted
1724
-
1725
- ${pc.bold('Next steps:')}
1726
- 1. Copy the prompt below into your AI editor and describe what the project does
1727
- 2. Commit ${pc.bold('AGENTS.md')}, ${pc.bold('CLAUDE.md')}, ${pc.bold('GEMINI.md')}, ${pc.bold('.cursorrules')}, and ${pc.bold('.agent/')}
1728
- 3. Open the project in Codex, Antigravity, Claude Code, or Cursor
1729
-
1730
- ${pc.bold('Copy this prompt into your AI editor:')}
1731
- ${pc.dim('---')}
1732
- Read CLAUDE.md (if using Claude Code), AGENTS.md, and all files under .agent/docs/.
1733
- Ask me what this project does and any important conventions I want preserved.
1734
- Then scan this repository.
1735
- Update CLAUDE.md, AGENTS.md, .cursorrules and .agent/docs/project.md, .agent/docs/architecture.md, .agent/docs/conventions.md, .agent/docs/workflow.md, and .agent/docs/tooling.md with factual project-specific rules.
1736
- Do not implement product code.
1737
- Remove TODO: refine only when backed by evidence from the codebase.
1738
- ${pc.dim('---')}
1739
- `);
1797
+ writeJsonFile(filePath, data);
1798
+ return { ok: true, message: `configured Definition-of-Done Stop hook in ${filePath}` };
1740
1799
  }
1741
1800
 
1742
- main().catch(err => {
1743
- console.error(pc.red('\nError during init:'), err);
1744
- process.exit(1);
1745
- });
1801
+ function setupMcpServers() {
1802
+ const results = [];
1803
+ results.push(ensureCodegraphCli());
1804
+ results.push(ensureContext7Cli());
1805
+ results.push(ensurePlaywrightMcpCli());
1806
+
1807
+ const codexConfig = homePath('.codex', 'config.toml');
1808
+ if (codexConfig) results.push(appendMcpTomlIfMissing(codexConfig));
1809
+
1810
+ const geminiConfig = homePath('.gemini', 'config', 'mcp_config.json');
1811
+ if (geminiConfig) results.push(mergeMcpJson(geminiConfig, false));
1812
+
1813
+ const antigravityIdeConfig = homePath('.gemini', 'antigravity-ide', 'mcp_config.json');
1814
+ if (antigravityIdeConfig) results.push(mergeMcpJson(antigravityIdeConfig, false));
1815
+
1816
+ const antigravityConfig = homePath('.gemini', 'antigravity', 'mcp_config.json');
1817
+ if (antigravityConfig && fs.existsSync(path.dirname(antigravityConfig))) {
1818
+ results.push(mergeMcpJson(antigravityConfig, false));
1819
+ }
1820
+
1821
+ const claudeConfig = homePath('.claude.json');
1822
+ if (claudeConfig) results.push(mergeMcpJson(claudeConfig, true));
1823
+
1824
+ const claudeSettings = homePath('.claude', 'settings.json');
1825
+ if (claudeSettings) results.push(mergeMcpJson(claudeSettings, true));
1826
+
1827
+ return results;
1828
+ }
1829
+
1830
+ // --- Main CLI ---
1831
+
1832
+ async function main() {
1833
+ const rawArgs = process.argv.slice(2);
1834
+ const command = rawArgs[0] && !rawArgs[0].startsWith('-') ? rawArgs[0] : 'init';
1835
+ const args = command === 'init' ? rawArgs.slice(rawArgs[0] === 'init' ? 1 : 0) : rawArgs.slice(1);
1836
+
1837
+ if (rawArgs.includes('--version') || rawArgs.includes('-v')) {
1838
+ console.log(packageJson.version);
1839
+ return;
1840
+ }
1841
+
1842
+ if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
1843
+ printHelp();
1844
+ return;
1845
+ }
1846
+
1847
+ if (command !== 'init') {
1848
+ console.error(pc.red(`Unknown command: ${command}`));
1849
+ printHelp();
1850
+ process.exit(1);
1851
+ }
1852
+
1853
+ const assumeYes = args.includes('--yes') || args.includes('-y');
1854
+ const skipMcpSetup = args.includes('--no-setup-mcp') || process.env.THACHVD_KIT_SKIP_MCP_SETUP === '1';
1855
+
1856
+ console.log(pc.bold(pc.cyan('='.repeat(50))));
1857
+ console.log(' ' + pc.bold('thachvd-kit') + ' - AI Project Bootstrap');
1858
+ console.log(' Generates shared agent rules and configures MCP tooling');
1859
+ console.log(pc.bold(pc.cyan('='.repeat(50))));
1860
+
1861
+ console.log(pc.dim(' Scanning current project files for a baseline...\n'));
1862
+ const scanned = scanProject();
1863
+
1864
+ console.log(` ${pc.bold('Detected context:')}`);
1865
+ formatScanPreviewLines(scanned).forEach(([label, value]) => {
1866
+ console.log(` - ${label}: ${value}`);
1867
+ });
1868
+ console.log('');
1869
+ if ((scanned.scan_evidence || []).length > 0) {
1870
+ console.log(` ${pc.bold('Evidence:')}`);
1871
+ scanned.scan_evidence.forEach(line => console.log(` - ${line}`));
1872
+ console.log('');
1873
+ }
1874
+
1875
+ // Combine data
1876
+ const data = {
1877
+ project_name: scanned?.project_name || path.basename(targetDir),
1878
+ description: scanned?.description || 'A software project',
1879
+ project_type: scanned?.project_type || 'web-app',
1880
+ primary_language: scanned?.primary_language || 'typescript',
1881
+ frameworks: scanned?.frameworks || [],
1882
+ database: scanned?.database || 'none',
1883
+ uses_docker: scanned?.uses_docker ?? true,
1884
+ cloud: scanned?.cloud || 'none',
1885
+ package_manager: scanned?.package_manager || 'auto-detect',
1886
+ test_framework: scanned?.test_framework || 'auto-detect',
1887
+ max_file_lines: scanned?.max_file_lines || '300'
1888
+ };
1889
+
1890
+ data.database = data.database || scanned?.database || 'none';
1891
+ data.uses_docker = typeof data.uses_docker === 'boolean' ? data.uses_docker : (scanned?.uses_docker ?? true);
1892
+ data.cloud = data.cloud || scanned?.cloud || 'none';
1893
+ data.package_manager = data.package_manager || scanned?.package_manager || 'auto-detect';
1894
+ data.test_framework = data.test_framework || scanned?.test_framework || 'auto-detect';
1895
+ data.max_file_lines = data.max_file_lines || scanned?.max_file_lines || '300';
1896
+ data.framework_details = scanned?.framework_details || [];
1897
+ data.scan_evidence = scanned?.scan_evidence || [];
1898
+ data.app_root = scanned?.app_root || '.';
1899
+
1900
+ data.infrastructure = [];
1901
+ if (data.uses_docker) data.infrastructure.push('docker');
1902
+ if (data.cloud !== 'none') data.infrastructure.push(data.cloud);
1903
+
1904
+ const shouldSetupMcp = !skipMcpSetup;
1905
+
1906
+ console.log(`\n${pc.bold(pc.cyan('Generating Files'))}`);
1907
+
1908
+ // Shared entry files are written after the .agent folder is available.
1909
+
1910
+ // Copy .agent folder
1911
+ const { copied, skipped } = copyAgentFolder();
1912
+ if (copied > 0) {
1913
+ console.log(` ${pc.green('OK')} Copied ${pc.bold('.agent/')} (${copied} file${copied !== 1 ? 's' : ''} added${skipped > 0 ? `, ${skipped} skipped` : ''})`);
1914
+ } else if (skipped > 0) {
1915
+ console.log(` ${pc.yellow('~')} ${pc.bold('.agent/')} already exists - ${skipped} file${skipped !== 1 ? 's' : ''} skipped (no overwrite)`);
1916
+ }
1917
+
1918
+ const nativeSkills = copySelectedSkillFolders(data, assumeYes);
1919
+ if (nativeSkills.copied > 0) {
1920
+ console.log(` ${pc.green('OK')} Copied native skills to ${pc.bold('~/.codex/skills/')} and ${pc.bold('.claude/skills/')} (${nativeSkills.skills.join(', ')})`);
1921
+ } else if (nativeSkills.skipped > 0) {
1922
+ console.log(` ${pc.yellow('~')} Native skills already exist - ${nativeSkills.skipped} file${nativeSkills.skipped !== 1 ? 's' : ''} skipped`);
1923
+ }
1924
+
1925
+
1926
+ const generatedFiles = [
1927
+ ['AGENTS.md', generateSharedAgentsMd(data)],
1928
+ ['CLAUDE.md', generateSharedClaudeMd()],
1929
+ ['GEMINI.md', generateSharedGeminiMd()],
1930
+ ['.cursorrules', generateSharedCursorrules(data)],
1931
+ [path.join('.agent', 'docs', 'project.md'), generateProjectDoc(data)],
1932
+ [path.join('.agent', 'docs', 'architecture.md'), generateArchitectureDoc(data)],
1933
+ [path.join('.agent', 'docs', 'conventions.md'), generateConventionsDoc(data)],
1934
+ [path.join('.agent', 'docs', 'workflow.md'), generateWorkflowDoc()],
1935
+ [path.join('.agent', 'docs', 'tooling.md'), generateToolingDoc(data)],
1936
+ [path.join('.agent', 'docs', 'getting-started.md'), generateGettingStartedDoc()]
1937
+ ];
1938
+
1939
+ for (const [relativePath, content] of generatedFiles) {
1940
+ const wrote = await writeGeneratedFile(relativePath, content, assumeYes);
1941
+ if (wrote) console.log(` ${pc.green('OK')} Generated ${pc.bold(relativePath)}`);
1942
+ else console.log(` ${pc.yellow('~')} Skipped ${pc.bold(relativePath)}`);
1943
+ }
1944
+
1945
+ console.log(`\n${pc.bold(pc.cyan('Configuring Claude Code hooks'))}`);
1946
+ const hookResult = mergeClaudeProjectHooks(path.join(targetDir, '.claude', 'settings.json'));
1947
+ console.log(` ${hookResult.ok ? pc.green('OK') : pc.yellow('~')} ${hookResult.message}`);
1948
+
1949
+ if (shouldSetupMcp) {
1950
+ console.log(`\n${pc.bold(pc.cyan('Configuring MCP'))}`);
1951
+ for (const result of setupMcpServers()) {
1952
+ const marker = result.ok ? pc.green('OK') : pc.yellow('~');
1953
+ console.log(` ${marker} ${result.message}`);
1954
+ }
1955
+ }
1956
+
1957
+ console.log(`\n${pc.bold(pc.green('Done!'))}
1958
+
1959
+ ${pc.bold('Project:')} ${data.project_name}
1960
+ ${pc.bold('Stack:')} ${data.primary_language} | ${(data.frameworks || []).join(', ') || 'no framework'}
1961
+
1962
+ ${pc.bold('Generated:')}
1963
+ - ${pc.bold('AGENTS.md')} shared entry for Codex, Antigravity, Claude Code, and Cursor
1964
+ - ${pc.bold('CLAUDE.md')} Claude Code entry that imports AGENTS.md
1965
+ - ${pc.bold('GEMINI.md')} Antigravity entry
1966
+ - ${pc.bold('.cursorrules')} Cursor entry
1967
+ - ${pc.bold('.agent/docs/')} scan-based project rules, including ${pc.bold('getting-started.md')} (standard flow vs fast path)
1968
+ - ${pc.bold('.agent/')} skills, workflows, agents, and rules
1969
+ - ${pc.bold('~/.codex/skills/')} selected Codex skills installed globally (visible in $ menu)
1970
+ - ${pc.bold('.claude/skills/')} selected Claude Code native skills
1971
+ - ${pc.bold('.claude/settings.json')} Definition-of-Done Stop hook (Claude Code only — blocks reporting a feature/refactor "done" without a plan + review pass)
1972
+
1973
+ ${pc.bold('MCP/tooling setup:')}
1974
+ - Codegraph CLI checked or installed; MCP configured for Codex, Gemini/Antigravity, and Claude Code
1975
+ - Context7 MCP configured for Codex and Gemini/Antigravity
1976
+ - Playwright MCP configured for Codex, Gemini/Antigravity, and Claude Code
1977
+ - Browser install hint: ${pc.bold(resolveToolingSetup(data).playwrightCommand)}
1978
+ - Codegraph index hint: run ${pc.bold('codegraph init -i')} when a project index is missing, then keep ${pc.bold('.codegraph/')} uncommitted
1979
+
1980
+ ${pc.bold('Next steps:')}
1981
+ 1. Read ${pc.bold('.agent/docs/getting-started.md')} for the standard flow vs fast path
1982
+ 2. Copy the prompt below into your AI editor and describe what the project does
1983
+ 3. Commit ${pc.bold('AGENTS.md')}, ${pc.bold('CLAUDE.md')}, ${pc.bold('GEMINI.md')}, ${pc.bold('.cursorrules')}, ${pc.bold('.agent/')}, and ${pc.bold('.claude/settings.json')}
1984
+ 4. Open the project in Codex, Antigravity, Claude Code, or Cursor
1985
+
1986
+ ${pc.bold('Copy this prompt into your AI editor:')}
1987
+ ${pc.dim('---')}
1988
+ Read CLAUDE.md (if using Claude Code), AGENTS.md, and all files under .agent/docs/.
1989
+ Ask me what this project does and any important conventions I want preserved.
1990
+ Then scan this repository.
1991
+ Update CLAUDE.md, AGENTS.md, .cursorrules and .agent/docs/project.md, .agent/docs/architecture.md, .agent/docs/conventions.md, .agent/docs/workflow.md, and .agent/docs/tooling.md with factual project-specific rules.
1992
+ Do not implement product code.
1993
+ Remove TODO: refine only when backed by evidence from the codebase.
1994
+ ${pc.dim('---')}
1995
+ `);
1996
+ }
1997
+
1998
+ main().catch(err => {
1999
+ console.error(pc.red('\nError during init:'), err);
2000
+ process.exit(1);
2001
+ });
1746
2002