phasegate 0.152.8 → 0.152.9

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/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.152.9] - 2026-05-13
11
+
12
+ ### Added
13
+
14
+ - **WI-171 / WI-172 / WI-173 / WI-174 — user onboarding and agent-driven setup** — adds first-run recipes and troubleshooting guides, managed `AGENTS.md` / `CLAUDE.md` setup sections, dedicated AGENTS lesson pointer refresh, `setup:agent` setup planning/apply flow, and `config:plan` configuration-change intent planning.
15
+
10
16
  ## [0.152.8] - 2026-05-13
11
17
 
12
18
  ### Changed
package/README.md CHANGED
@@ -60,6 +60,8 @@ The point is not just to fail the edit. The error gives the AI agent enough stru
60
60
 
61
61
  ## Quick Start
62
62
 
63
+ For a guided first run, start with [Getting Started](docs/guide/getting-started.md). It maps new repo, existing repo, CI-only, agent-hook, and strict rollout paths to the next command and success state. <!-- @work-item-id WI-171 -->
64
+
63
65
  ### Requirements
64
66
 
65
67
  Node.js >= 18, npm >= 9, TypeScript 5.x
@@ -98,7 +100,16 @@ npx phasegate install --apply
98
100
  npx phasegate doctor
99
101
  ```
100
102
 
101
- `install` merges PhaseGate into the current project without discarding existing Claude/Codex hooks or Husky scripts. It reports planned changes before writing, adds package scripts and the `phasegate` devDependency, creates agent skill links, writes the CI workflow when missing, and records managed files in `.phasegate/manifest.json`. If an existing file needs a forced managed update, run `npx phasegate install --apply --force`; PhaseGate backs up replaced files under `.phasegate/backups/`.
103
+ `install` merges PhaseGate into the current project without discarding existing Claude/Codex hooks or Husky scripts. It reports planned changes before writing, adds package scripts and the `phasegate` devDependency, creates agent skill links, writes `AGENTS.md` / `CLAUDE.md` PhaseGate managed sections for the selected agent targets, writes the CI workflow when missing, and records managed files in `.phasegate/manifest.json`. If an existing file needs a forced managed update, run `npx phasegate install --apply --force`; PhaseGate backs up replaced files under `.phasegate/backups/`. <!-- @work-item-id WI-174 -->
104
+
105
+ For agent-driven setup planning, use:
106
+
107
+ ```bash
108
+ npx phasegate setup:agent --intent recommended --dry-run --json
109
+ npx phasegate config:plan --intent codex-hooks --dry-run --json
110
+ ```
111
+
112
+ The first command reports detected setup state, missing questions, planned managed targets, rollback, and validation. The second maps a configuration change intent to files, commands, risks, and checks. <!-- @work-item-id WI-172, WI-173 -->
102
113
 
103
114
  To remove PhaseGate from that project later, run:
104
115
 
@@ -507,6 +518,8 @@ README keeps only the entry points most users need. The full public/compatibilit
507
518
  | `doctor` | Diagnose silent or partial installations (`--json`, `--strict`, `--report-out <path>`). `--report-out` is an explicit file path, not `reporting.outputDir`. |
508
519
  | `uninstall --dry-run` / `--apply` | Remove PhaseGate-managed files and managed blocks using `.phasegate/manifest.json`, preserving user content. |
509
520
  | `reconcile --dry-run` / `--apply` | Update PhaseGate-managed files to the current package templates and refresh manifest hashes. |
521
+ | `setup:agent --dry-run` / `--apply` | Diagnose repository setup and produce or apply an agent-readable setup plan with questions, risks, rollback, and validation. |
522
+ | `config:plan --intent <intent>` | Map a safe configuration-change intent to target files, commands, risks, rollback, and validation. |
510
523
  | `lint` / `phasegate:lint` | Run L1 Biome AST checks. The `phasegate:*` form is a binary subcommand, not an npm script unless `package.json` defines it locally. |
511
524
  | `validate --layer <L1-L4\|all>` | Run validators for the specified layer (`--layer L0` prints runtime hook guidance). `--fail-on-warning` / `--no-fail-on-warning` override config. |
512
525
  | `ci-check` | Full CI check (L2-L4; disabled L4 is reported as skipped). Supports `--quick`, `--fail-on-reject`, `--dry-run`, and `--files`. |
@@ -547,6 +560,9 @@ See the [CLI Reference](docs/guide/cli-reference.md) for the complete catalog an
547
560
  Detailed guides are available under `docs/guide/`:
548
561
 
549
562
  - [Installation](docs/guide/installation.md) -- Detailed install and setup instructions
563
+ - [Getting Started](docs/guide/getting-started.md) -- First-run, daily-use, CI-use, and agent-use paths
564
+ - [Recipes](docs/guide/recipes.md) -- Focused onboarding and configuration recipes
565
+ - [Troubleshooting](docs/guide/troubleshooting.md) -- Doctor finding, repairHint, suggestedSkill, and setup recovery guide
550
566
  - [Configuration](docs/guide/configuration.md) -- `phasegate.config.json` full reference
551
567
  - [CLI Reference](docs/guide/cli-reference.md) -- All CLI commands and options
552
568
  - [Skills Overview](docs/guide/skills-overview.md) -- 30 skills with AIDLC execution order
@@ -23,10 +23,12 @@ Command names in this document are split into three surfaces:
23
23
  | Command | Description |
24
24
  |---|---|
25
25
  | `init --name <name>` | Legacy-compatible bootstrap for new projects: deploy skills, generate config, and optionally add hooks/CI. Options: `--preset <full\|standard\|minimal\|custom>`, `--skills <core\|all>`, `--agent <claude\|codex\|both>`, `--workflow <standard\|strict>`, `--with-husky`, `--with-ci`, `--yes`. |
26
- | `install --dry-run` / `--apply` | Idempotently merge PhaseGate into an existing project, preserve user content, add package scripts/devDependency, and write `.phasegate/manifest.json`. `--force` replaces managed targets after backup. |
26
+ | `install --dry-run` / `--apply` | Idempotently merge PhaseGate into an existing project, preserve user content, add package scripts/devDependency, create selected `AGENTS.md` / `CLAUDE.md` managed sections, and write `.phasegate/manifest.json`. `--agent <claude\|codex\|both>`, `--skills <core\|all>`, and `--workflow <standard\|strict>` affect rendered agent context; `--force` replaces managed targets after backup. |
27
27
  | `doctor` | Diagnose silent or partial installations and report repair hints (`--json`, `--strict`, `--report-out <path>`). `--report-out` writes exactly to the supplied path, not to `reporting.outputDir`. |
28
28
  | `uninstall --dry-run` / `--apply` | Remove PhaseGate-managed files and managed blocks using `.phasegate/manifest.json`; `--force` handles managed conflict cases. |
29
29
  | `reconcile --dry-run` / `--apply` | Update PhaseGate-managed files to current package templates and refresh manifest hashes; `--force` allows managed-file replacement with backup. |
30
+ | `setup:agent` | Agent-readable setup planner and optional apply path. Options: `--intent <minimal\|recommended\|strict\|ci-only\|agent-hooks\|retrofit>`, `--agent <claude\|codex\|both>`, `--workflow <standard\|strict>`, `--with-husky`, `--with-ci`, `--dry-run`, `--apply`, `--json`. <!-- @work-item-id WI-172 --> |
31
+ | `config:plan` | Agent-readable configuration change planner. Options: `--intent <l4-strict\|codex-hooks\|ci-fail-on-warning\|baseline-reset\|quick-mode-strict>`, `--dry-run`, `--json`. <!-- @work-item-id WI-173 --> |
30
32
  | `update-skills` | Compatibility alias for `reconcile`; use `reconcile` for new automation. |
31
33
  | `scaffold-wi <unit> <type>` | Create `docs/inception/{unit}/WI-XXX/description.md` using the next free WI number. |
32
34
  | `emit-agent-rules` | Print the AGENTS.md / CLAUDE.md WI workflow rules block. |
@@ -374,7 +376,7 @@ ISSUE-005 P3-10 で明確化された境界:
374
376
  |---|---|---|
375
377
  | `ci:generate-template` | `--preset <id>`(省略時 `standard`) `--type <type>` `--render` `--json` | Generate CI/CD template |
376
378
  | `ci:migrate-agents-md` | `--dry-run` `--validate-only` `--json` | Migrate AGENTS.md to pointer format |
377
- | `ci:auto-refresh-agent-context` | `--dry-run` `--apply` `--json` | Refresh AGENTS.md pointers and CLAUDE.md standard sections |
379
+ | `ci:auto-refresh-agent-context` | `--dry-run` `--apply` `--json` | Refresh AGENTS.md lesson pointers in a dedicated section and CLAUDE.md standard sections without replacing user-owned agent instructions |
378
380
  | `refresh-claude-md` | `--dry-run` `--apply` `--json` | Refresh CLAUDE.md while preserving the user-owned section |
379
381
  | `p2:check-agent-context` | `--threshold-days <n>` `--json` | Check AGENTS.md / CLAUDE.md freshness |
380
382
  | `ci:check-repetition` | `--code <errorCode>` `--reset` `--json` | Detect repetitive errors |
@@ -8,6 +8,15 @@ This file is the **Single Source of Truth** for all quality configuration in a P
8
8
 
9
9
  It is not the whole setup state. Hook JSON, Husky scripts, CI workflow files, skill links, `.phasegate/manifest.json`, runtime reports, and Codex user-level feature flags are tracked separately. Use [Setup Artifacts](setup-artifacts.md) when auditing whether a project is fully installed. <!-- @work-item-id WI-152 -->
10
10
 
11
+ For agent-assisted changes, preview the intent before editing the config:
12
+
13
+ ```bash
14
+ npx phasegate config:plan --intent l4-strict --dry-run --json
15
+ npx phasegate config:plan --intent quick-mode-strict --dry-run --json
16
+ ```
17
+
18
+ The plan identifies target fields, managed artifacts, commands, validation, risks, and rollback so an agent can explain the change before applying it. <!-- @work-item-id WI-173 -->
19
+
11
20
  ### Full Reference
12
21
 
13
22
  ```jsonc
@@ -0,0 +1,64 @@
1
+ # Getting Started
2
+
3
+ <!-- @work-item-id WI-171 -->
4
+
5
+ Use this page when you want the shortest path from "PhaseGate is installed" to "the next command is obvious".
6
+
7
+ ## First Run
8
+
9
+ Start with one question: what kind of repository are you setting up?
10
+
11
+ | Answer | Command | Success state |
12
+ |---|---|---|
13
+ | New project with agent hooks | `npx phasegate init --name <project> --agent both --with-husky --with-ci` | `phasegate.config.json`, skills, hooks, agent context files, Husky, and CI targets exist |
14
+ | Existing repository | `npx phasegate install --dry-run` then `npx phasegate install --apply` | Existing hooks/scripts are preserved and `.phasegate/manifest.json` records managed targets |
15
+ | CI-only rollout | `npx phasegate setup:agent --intent ci-only --with-ci --dry-run --json` | The plan explains CI changes without requiring local hooks |
16
+ | Codex-only project | `npx phasegate init --agent codex --with-husky` | `.codex/hooks.json`, `AGENTS.md`, `.codex/skills`, and pre-commit backstop are present |
17
+ | Strict validation rollout | `npx phasegate setup:agent --intent strict --dry-run --json` | The plan lists strict checks, L4 risk, rollback, and validation commands |
18
+
19
+ After any setup path:
20
+
21
+ ```bash
22
+ npx phasegate doctor
23
+ npx phasegate phasegate:check-ready
24
+ npx phasegate validate --layer L2 --format human
25
+ ```
26
+
27
+ The first successful run is:
28
+
29
+ - `doctor` has no unexpected red finding for the targets you chose.
30
+ - `phasegate:check-ready` exits successfully.
31
+ - L2 validators pass or report only issues you intentionally left for a later rollout.
32
+ - The active agent can read `AGENTS.md` or `CLAUDE.md` and see the PhaseGate managed instructions.
33
+
34
+ ## Daily Use
35
+
36
+ ```bash
37
+ npx phasegate work-items:status --dry-run
38
+ npx phasegate validate --layer L2 --format human
39
+ npx phasegate phasegate:status --json
40
+ ```
41
+
42
+ Use `work-items:status` before commit when a WI is close to completion. Use `phasegate:status --json` when an agent needs machine-readable hook, baseline, and validator health.
43
+
44
+ ## Agent Use
45
+
46
+ ```bash
47
+ npx phasegate setup:agent --dry-run --json
48
+ npx phasegate config:plan --intent codex-hooks --dry-run --json
49
+ ```
50
+
51
+ `setup:agent` reads repository setup state and returns missing targets, questions, risk, rollback, and validation steps. `config:plan` maps natural-language change intents such as "enable Codex hooks" or "make L4 stricter" to concrete files, commands, and checks.
52
+
53
+ ## CI Use
54
+
55
+ ```bash
56
+ npx phasegate ci:generate-template --type aidlc-gate --render
57
+ npx phasegate validate --layer all --format ci
58
+ ```
59
+
60
+ For warning-as-failure rollout, preview the change first:
61
+
62
+ ```bash
63
+ npx phasegate config:plan --intent ci-fail-on-warning --dry-run --json
64
+ ```
@@ -17,7 +17,7 @@ Or add it directly to your `package.json`:
17
17
  ```json
18
18
  {
19
19
  "devDependencies": {
20
- "phasegate": "^0.152.8"
20
+ "phasegate": "^0.152.9"
21
21
  }
22
22
  }
23
23
  ```
@@ -38,7 +38,7 @@ npx phasegate init --name <project-name>
38
38
 
39
39
  This deploys 30 skills to `skills/`, creates the agent-facing skill links (for example `.claude/skills/` or `.codex/skills/`), and generates `phasegate.config.json`.
40
40
 
41
- `init` is the legacy-compatible bootstrap path for new projects. Use `install` when the project may already have hooks, package scripts, or CI files that should be preserved.
41
+ `init` is the legacy-compatible bootstrap path for new projects. It also runs the structured install path for the selected agent target so `CLAUDE.md` and/or `AGENTS.md` receive a PhaseGate managed section. Use `install` when the project may already have hooks, package scripts, or CI files that should be preserved. <!-- @work-item-id WI-174 -->
42
42
 
43
43
  For Codex, project initialization stops at the project boundary. After `npx phasegate init --agent codex`, enable the Codex CLI feature flag manually:
44
44
 
@@ -56,7 +56,16 @@ npx phasegate install --apply
56
56
  npx phasegate doctor
57
57
  ```
58
58
 
59
- `install --dry-run` reports whether each target will be created, merged, skipped, or refused. `install --apply` performs the merge, adds package scripts and the `phasegate` devDependency, creates `.claude/skills` and `.codex/skills` links, writes `.github/workflows/phasegate-aidlc-gate.yml` when CI is enabled, and records managed entries in `.phasegate/manifest.json`. See [Setup Artifacts](setup-artifacts.md) for the full managed target, generated artifact, runtime state, legacy artifact, and user-level setting inventory. <!-- @work-item-id WI-152 --> <!-- @work-item-id WI-169 -->
59
+ `install --dry-run` reports whether each target will be created, merged, skipped, or refused. `install --apply` performs the merge, adds package scripts and the `phasegate` devDependency, creates `.claude/skills` and `.codex/skills` links, writes `CLAUDE.md` / `AGENTS.md` managed sections for selected agent targets, writes `.github/workflows/phasegate-aidlc-gate.yml` when CI is enabled, and records managed entries in `.phasegate/manifest.json`. See [Setup Artifacts](setup-artifacts.md) for the full managed target, generated artifact, runtime state, legacy artifact, and user-level setting inventory. <!-- @work-item-id WI-152 --> <!-- @work-item-id WI-169 --> <!-- @work-item-id WI-174 -->
60
+
61
+ For agent-readable planning before writing files:
62
+
63
+ ```bash
64
+ npx phasegate setup:agent --intent recommended --dry-run --json
65
+ npx phasegate setup:agent --intent strict --with-ci --with-husky --dry-run --json
66
+ ```
67
+
68
+ The setup plan includes detected state, questions, planned changes, risks, rollback, and validation commands. <!-- @work-item-id WI-172 -->
60
69
 
61
70
  If a managed update must replace existing custom content, use:
62
71
 
@@ -73,7 +82,7 @@ npx phasegate uninstall --dry-run
73
82
  npx phasegate uninstall --apply
74
83
  ```
75
84
 
76
- `uninstall` reads `.phasegate/manifest.json`, deletes files that PhaseGate created, removes only PhaseGate-managed portions from merged JSON, Husky, and `package.json` files, and archives the manifest as `.phasegate/uninstalled-<timestamp>.json`. If a managed file was modified after install, `uninstall --apply` refuses that entry until you rerun with `--force`, which creates a backup under `.phasegate/backups/uninstall-<timestamp>/`.
85
+ `uninstall` reads `.phasegate/manifest.json`, deletes files that PhaseGate created, removes only PhaseGate-managed portions from merged JSON, markdown agent context files, Husky, and `package.json` files, and archives the manifest as `.phasegate/uninstalled-<timestamp>.json`. If a managed file was modified after install, `uninstall --apply` refuses that entry until you rerun with `--force`, which creates a backup under `.phasegate/backups/uninstall-<timestamp>/`. <!-- @work-item-id WI-174 -->
77
86
 
78
87
  After upgrading PhaseGate, reconcile existing managed files with the bundled templates from the new version:
79
88
 
@@ -0,0 +1,65 @@
1
+ # Recipes
2
+
3
+ <!-- @work-item-id WI-171, WI-172, WI-173 -->
4
+
5
+ ## First-Run Recipe
6
+
7
+ ```bash
8
+ npm install --save-dev phasegate
9
+ npx phasegate setup:agent --intent recommended --dry-run --json
10
+ npx phasegate install --apply
11
+ npx phasegate doctor
12
+ ```
13
+
14
+ Use this when you want an existing repository to keep user-owned hooks, scripts, and CI files. The dry-run explains the managed targets before any file is written.
15
+
16
+ ## Retrofit Recipe
17
+
18
+ ```bash
19
+ npx phasegate setup:agent --intent retrofit --dry-run --json
20
+ npx phasegate install --dry-run
21
+ npx phasegate install --apply
22
+ npx phasegate baseline --dry-run
23
+ ```
24
+
25
+ Use this when a repository already has meaningful history or custom automation. Treat any refused target as an agent-assisted review task instead of forcing it blindly.
26
+
27
+ ## Agent Hooks Recipe
28
+
29
+ ```bash
30
+ npx phasegate setup:agent --intent agent-hooks --agent both --with-husky --dry-run --json
31
+ npx phasegate install --agent both --apply
32
+ codex features enable codex_hooks
33
+ npx phasegate doctor --json
34
+ ```
35
+
36
+ The repository-managed portion covers `.claude/settings.json`, `.codex/hooks.json`, `CLAUDE.md`, `AGENTS.md`, skills links, and the Husky backstop. The Codex user-level feature flag remains a local manual setting.
37
+
38
+ ## CI Recipe
39
+
40
+ ```bash
41
+ npx phasegate setup:agent --intent ci-only --with-ci --dry-run --json
42
+ npx phasegate install --apply
43
+ npx phasegate ci:generate-template --type aidlc-gate --render
44
+ ```
45
+
46
+ Use this when local hooks are not part of the rollout. The plan still includes validation and rollback steps so the agent can explain what changed.
47
+
48
+ ## Strict L4 Recipe
49
+
50
+ ```bash
51
+ npx phasegate config:plan --intent l4-strict --dry-run --json
52
+ npx phasegate validate --layer L4 --fail-on-warning --format human
53
+ ```
54
+
55
+ Only enable fail-on-warning after reviewing the drift, consistency, dead-code, pointer, and freshness findings. The plan output identifies the config fields and validations the agent should cite in its change summary.
56
+
57
+ ## Configuration Change Recipe
58
+
59
+ ```bash
60
+ npx phasegate config:plan --intent quick-mode-strict --dry-run --json
61
+ npx phasegate check-change-category --paths <changed-files> --format json
62
+ npx phasegate ci-check --quick --dry-run
63
+ ```
64
+
65
+ Use `config:plan` before changing `phasegate.config.json`. It separates repo-managed artifacts from user-level settings and lists the checks needed after the change.
@@ -10,7 +10,7 @@ PhaseGate setup is more than `phasegate.config.json`. A healthy installation is
10
10
 
11
11
  | Class | Examples | Owner | Lifecycle |
12
12
  |---|---|---|---|
13
- | Managed target | `.claude/settings.json`, `.codex/hooks.json`, `.husky/pre-commit`, `.husky/commit-msg`, `.husky/pre-push`, `.github/workflows/phasegate-aidlc-gate.yml`, `.claude/skills`, `.codex/skills`, `package.json` PhaseGate scripts/devDependency | PhaseGate managed block or symlink plus user content | Created or merged by `install`, refreshed by `reconcile`, removed or reversed by `uninstall` |
13
+ | Managed target | `.claude/settings.json`, `.codex/hooks.json`, `CLAUDE.md`, `AGENTS.md`, `.husky/pre-commit`, `.husky/commit-msg`, `.husky/pre-push`, `.github/workflows/phasegate-aidlc-gate.yml`, `.claude/skills`, `.codex/skills`, `package.json` PhaseGate scripts/devDependency | PhaseGate managed block or symlink plus user content | Created or merged by `install`, refreshed by `reconcile`, removed or reversed by `uninstall` |
14
14
  | Configuration | `phasegate.config.json`, `package.json` | User owned, PhaseGate assisted | Created by `init`; `install` may merge scripts/devDependency into `package.json` |
15
15
  | Generated artifact | `.phasegate/manifest.json`, `.phasegate/backups/*`, `.phasegate/uninstalled-*.json`, `.phasegate/baseline.json` | PhaseGate | Written by lifecycle commands and validators; safe to regenerate only through the owning command |
16
16
  | Runtime state/report | `.phasegate/hook-skip-events.jsonl`, explicit `doctor --report-out <path>` output, `reports/regression/*`, resolved `reporting.outputDir` reports | PhaseGate command output | Produced while hooks, doctor, and validation commands run |
@@ -22,12 +22,15 @@ PhaseGate setup is more than `phasegate.config.json`. A healthy installation is
22
22
  `install --apply` and `reconcile --apply` manage only explicit targets. The current structured lifecycle covers:
23
23
 
24
24
  - Agent hook JSON: `.claude/settings.json`, `.codex/hooks.json`
25
+ - Agent context files: `CLAUDE.md` and `AGENTS.md` managed sections. `AGENT.md` singular is not a PhaseGate managed target; treat it as user-owned content or migrate it manually. <!-- @work-item-id WI-174 -->
25
26
  - Husky scripts when requested: `.husky/pre-commit`, `.husky/commit-msg`, `.husky/pre-push`
26
27
  - CI workflow when requested: `.github/workflows/phasegate-aidlc-gate.yml`
27
28
  - Agent skill links: `.claude/skills`, `.codex/skills`
28
29
  - Package metadata: PhaseGate scripts and `devDependencies.phasegate` in `package.json`
29
30
  - Manifest: `.phasegate/manifest.json`
30
31
 
32
+ `AGENTS.md` has two PhaseGate sections with separate ownership. `<!-- phasegate:managed-section:start -->` contains standard setup/WI workflow instructions. `<!-- phasegate:lesson-pointers:start -->` is reserved for `ci:auto-refresh-agent-context` lesson pointers. Refreshing lesson pointers must not replace the standard managed section or user-owned content. <!-- @work-item-id WI-174 -->
33
+
31
34
  `init --with-ci` still deploys the legacy-compatible template set, including `.github/workflows/aidlc-gate.yml`, `.github/workflows/consistency-check.yml`, and `.github/workflows/agent-context-refresh.yml`. Structured `install` uses `.github/workflows/phasegate-aidlc-gate.yml` so it can coexist with existing project CI without taking over a generic workflow filename.
32
35
 
33
36
  ## Doctor Findings
@@ -0,0 +1,60 @@
1
+ # Troubleshooting
2
+
3
+ <!-- @work-item-id WI-171, WI-172, WI-173 -->
4
+
5
+ Start with:
6
+
7
+ ```bash
8
+ npx phasegate doctor --json
9
+ ```
10
+
11
+ Each finding has a severity, a repair mode, and optional next-step fields.
12
+
13
+ | Field | Meaning |
14
+ |---|---|
15
+ | `severity` | `red` blocks the expected setup state; `warn` needs review but may be acceptable for partial rollout |
16
+ | `repairMode` | `mechanical` can be handled by PhaseGate commands; `ai-assisted` needs an agent to preserve user intent; `manual` needs human review |
17
+ | `repairHint` | Copyable command for mechanical repair |
18
+ | `suggestedSkill` | Agent skill to invoke when a merge or setup choice needs reasoning |
19
+
20
+ ## Common Findings
21
+
22
+ | Finding | First action |
23
+ |---|---|
24
+ | `claude-hook-missing` | `npx phasegate install --agent claude --dry-run` |
25
+ | `codex-hook-missing` | `npx phasegate install --agent codex --dry-run` |
26
+ | `husky-pre-commit-missing` | `npx phasegate setup:agent --intent agent-hooks --with-husky --dry-run --json` |
27
+ | `ci-workflow-missing` | `npx phasegate setup:agent --intent ci-only --with-ci --dry-run --json` |
28
+ | agent context drift | `npx phasegate reconcile --dry-run` |
29
+
30
+ ## Refused Managed Target
31
+
32
+ If `install`, `reconcile`, or `uninstall` refuses a target, do not immediately force it. Inspect the diff and ask the agent to explain:
33
+
34
+ - which file is repo-managed and which part is user-owned;
35
+ - why the target cannot be merged mechanically;
36
+ - what backup and rollback path will exist if `--force` is used;
37
+ - which validation commands will be run afterward.
38
+
39
+ ## Codex Hooks Do Not Fire
40
+
41
+ Check both project and user-level state:
42
+
43
+ ```bash
44
+ npx phasegate doctor --json
45
+ codex features enable codex_hooks
46
+ npx phasegate phasegate:status --json
47
+ ```
48
+
49
+ Native Codex `apply_patch` writes are validated by the pre-commit backstop. Bash-based writes can be blocked before execution when hooks are enabled.
50
+
51
+ ## Agent Setup Is Ambiguous
52
+
53
+ Use the planner instead of guessing:
54
+
55
+ ```bash
56
+ npx phasegate setup:agent --intent retrofit --dry-run --json
57
+ npx phasegate config:plan --intent codex-hooks --dry-run --json
58
+ ```
59
+
60
+ The planner output is intentionally agent-readable: detected state, questions, planned targets, risks, rollback, and validation commands are all explicit.
@@ -0,0 +1,45 @@
1
+ # AGENTS.md
2
+
3
+ <!-- @work-item-id WI-174 -->
4
+
5
+ <!-- phasegate:managed-section:start -->
6
+ ## PhaseGate Managed Instructions
7
+
8
+ ### Required Documents
9
+
10
+ - `docs/folder_management_rules.md`
11
+ - `docs/principles/architecture-philosophy.md`
12
+ - `docs/principles/testing-rules.md`
13
+
14
+ ### Workflow
15
+
16
+ - Create or update the relevant `docs/inception/**/WI-XXX/` work item before planning, design, implementation, or tests.
17
+ - Reflect accepted design into `docs/product/...` with `@work-item-id WI-XXX` before changing source files.
18
+ - Run the relevant PhaseGate checks after changing docs, source, hooks, skills, or setup artifacts.
19
+ - Do not bypass git hooks unless the user explicitly approves the reason, residual risk, and replacement validation.
20
+
21
+ ### Setup State
22
+
23
+ - Agent target: `{{PHASEGATE_AGENT}}`
24
+ - Skill set: `{{PHASEGATE_SKILLS_MODE}}`
25
+ - Workflow mode: `{{PHASEGATE_WORKFLOW}}`
26
+ - Husky hooks: `{{PHASEGATE_HUSKY_STATE}}`
27
+ - CI workflow: `{{PHASEGATE_CI_STATE}}`
28
+
29
+ ### Common Commands
30
+
31
+ {{PHASEGATE_COMMANDS}}
32
+
33
+ ### Codex Notes
34
+
35
+ - Enable native hook execution with `codex features enable codex_hooks` when Codex hooks are installed.
36
+ - Keep local-only Codex settings outside repository-managed targets unless PhaseGate explicitly reports them as managed.
37
+ <!-- phasegate:managed-section:end -->
38
+
39
+ <!-- phasegate:lesson-pointers:start -->
40
+ <!-- lesson pointers are managed by phasegate ci:auto-refresh-agent-context -->
41
+ <!-- phasegate:lesson-pointers:end -->
42
+
43
+ <!-- phasegate:user-section:start -->
44
+ Project-specific agent instructions go here.
45
+ <!-- phasegate:user-section:end -->
@@ -1,5 +1,8 @@
1
1
  # CLAUDE.md
2
2
 
3
+ <!-- @work-item-id WI-174 -->
4
+
5
+ <!-- phasegate:managed-section:start -->
3
6
  ## 必読ドキュメント
4
7
 
5
8
  - `docs/folder_management_rules.md`
@@ -27,3 +30,4 @@
27
30
  ## Agent Context Refresh
28
31
 
29
32
  Run `phasegate ci:auto-refresh-agent-context --dry-run` to preview updates and `phasegate ci:auto-refresh-agent-context --apply` to write AGENTS.md / CLAUDE.md.
33
+ <!-- phasegate:managed-section:end -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phasegate",
3
- "version": "0.152.8",
3
+ "version": "0.152.9",
4
4
  "packageManager": "pnpm@10.30.1",
5
5
  "description": "Phasegate — AI-agnostic quality defense toolkit. Enforces structural integrity between design intent and code.",
6
6
  "license": "MIT",
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @layer infrastructure
3
3
  * @unit ci-governance
4
+ * @work-item-id WI-174
4
5
  *
5
6
  * AgentsMdPort実装(AGENTS.mdファイルI/O)
6
7
  */
@@ -13,6 +14,7 @@ import { PointerEntry } from '../../domain/value-objects/pointer-entry.js';
13
14
 
14
15
  export class AgentsMdFileAdapter implements AgentsMdPort {
15
16
  private readonly filePath: string;
17
+ private lastReadContent: string | null = null;
16
18
 
17
19
  constructor(baseDir: string) {
18
20
  this.filePath = path.join(baseDir, 'AGENTS.md');
@@ -21,8 +23,10 @@ export class AgentsMdFileAdapter implements AgentsMdPort {
21
23
  async read(): Promise<AgentsMdPointer> {
22
24
  try {
23
25
  const content = await fs.readFile(this.filePath, 'utf-8');
26
+ this.lastReadContent = content;
24
27
  return this.parseAgentsMd(content);
25
28
  } catch {
29
+ this.lastReadContent = null;
26
30
  return AgentsMdPointer.create();
27
31
  }
28
32
  }
@@ -36,7 +40,7 @@ export class AgentsMdFileAdapter implements AgentsMdPort {
36
40
  before = 0;
37
41
  }
38
42
 
39
- const content = this.serializeAgentsMd(pointer);
43
+ const content = this.serializeAgentsMd(pointer, this.lastReadContent ?? null);
40
44
  await fs.writeFile(this.filePath, content, 'utf-8');
41
45
  const after = content.split('\n').length;
42
46
 
@@ -81,11 +85,28 @@ export class AgentsMdFileAdapter implements AgentsMdPort {
81
85
  return AgentsMdPointer.create(pointers, adrLinks);
82
86
  }
83
87
 
84
- private serializeAgentsMd(pointer: AgentsMdPointer): string {
85
- const lines: string[] = ['# AGENTS.md', ''];
88
+ private serializeAgentsMd(pointer: AgentsMdPointer, existing: string | null): string {
89
+ const section = this.serializeLessonPointerSection(pointer);
90
+ if (existing !== null && existing.trim().length > 0) {
91
+ const start = '<!-- phasegate:lesson-pointers:start -->';
92
+ const end = '<!-- phasegate:lesson-pointers:end -->';
93
+ const pattern = new RegExp(`${this.escapeRegExp(start)}[\\s\\S]*?${this.escapeRegExp(end)}`);
94
+ if (pattern.test(existing)) {
95
+ return existing.replace(pattern, section.trim()).replace(/\s*$/, '\n');
96
+ }
97
+ return `${existing.replace(/\s*$/, '\n\n')}${section}`;
98
+ }
99
+ return ['# AGENTS.md', '', section].join('\n');
100
+ }
101
+
102
+ private serializeLessonPointerSection(pointer: AgentsMdPointer): string {
103
+ const lines: string[] = [
104
+ '<!-- phasegate:lesson-pointers:start -->',
105
+ '## PhaseGate Lesson Pointers',
106
+ '',
107
+ ];
86
108
 
87
109
  if (pointer.pointers.length > 0) {
88
- lines.push('## Pointers', '');
89
110
  for (const entry of pointer.pointers) {
90
111
  if (entry.isCommand()) {
91
112
  lines.push(`- [cmd:${entry.key}](${entry.command ?? ''}) ${entry.description}`);
@@ -97,13 +118,18 @@ export class AgentsMdFileAdapter implements AgentsMdPort {
97
118
  }
98
119
 
99
120
  if (pointer.adrLinks.length > 0) {
100
- lines.push('## ADR Links', '');
121
+ lines.push('### ADR Links', '');
101
122
  for (const adr of pointer.adrLinks) {
102
123
  lines.push(`- ADR: ${adr}`);
103
124
  }
104
125
  lines.push('');
105
126
  }
106
127
 
128
+ lines.push('<!-- phasegate:lesson-pointers:end -->', '');
107
129
  return lines.join('\n');
108
130
  }
131
+
132
+ private escapeRegExp(value: string): string {
133
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
134
+ }
109
135
  }
@@ -1,6 +1,7 @@
1
1
  // @unit installation
2
2
  // @layer application
3
3
  // @work-item-id WI-146
4
+ // @work-item-id WI-174
4
5
 
5
6
  import { mkdir, readFile, writeFile, copyFile, chmod, access, lstat, readlink, symlink } from "node:fs/promises";
6
7
  import { dirname, join } from "node:path";
@@ -12,7 +13,7 @@ import type { ManifestRepositoryPort } from "../ports/manifest-repository-port.j
12
13
  import type { HashCalculatorPort } from "../ports/hash-calculator-port.js";
13
14
 
14
15
  type InstallAction = "missing" | "will-merge" | "will-skip" | "will-overwrite";
15
- type StrategyType = "json" | "shell" | "yaml-add" | "package-json";
16
+ type StrategyType = "json" | "shell" | "yaml-add" | "package-json" | "markdown-managed";
16
17
 
17
18
  export interface InstallPlanItem {
18
19
  readonly path: string;
@@ -36,6 +37,9 @@ export interface RunInstallInput {
36
37
  readonly includeCodex?: boolean;
37
38
  readonly includeHusky?: boolean;
38
39
  readonly includeCi?: boolean;
40
+ readonly skillSet?: "core" | "all";
41
+ readonly workflow?: "standard" | "strict";
42
+ readonly agent?: "claude" | "codex" | "both";
39
43
  }
40
44
 
41
45
  export interface RunInstallResult {
@@ -58,6 +62,8 @@ const PHASEGATE_SCRIPT_VERSION = "^0.0.0";
58
62
 
59
63
  const SHELL_BEGIN = "# === phasegate managed (BEGIN) ===";
60
64
  const SHELL_END = "# === phasegate managed (END) ===";
65
+ const MARKDOWN_BEGIN = "<!-- phasegate:managed-section:start -->";
66
+ const MARKDOWN_END = "<!-- phasegate:managed-section:end -->";
61
67
 
62
68
  function isRecord(value: unknown): value is Record<string, unknown> {
63
69
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -131,6 +137,50 @@ function mergeShell(existing: string | null, incoming: string): string {
131
137
  return `${existing.replace(/\s*$/, "\n\n")}${block}\n`;
132
138
  }
133
139
 
140
+ function managedMarkdownBlock(content: string): string {
141
+ const start = content.indexOf(MARKDOWN_BEGIN);
142
+ const end = content.indexOf(MARKDOWN_END);
143
+ if (start === -1 || end === -1 || end < start) return content.trim();
144
+ return content.slice(start, end + MARKDOWN_END.length).trim();
145
+ }
146
+
147
+ function mergeManagedMarkdown(existing: string | null, incoming: string): string {
148
+ const block = managedMarkdownBlock(incoming);
149
+ if (existing === null || existing.trim().length === 0) return `${incoming.trim()}\n`;
150
+ const pattern = new RegExp(`${escapeRegExp(MARKDOWN_BEGIN)}[\\s\\S]*?${escapeRegExp(MARKDOWN_END)}`);
151
+ if (pattern.test(existing)) return existing.replace(pattern, block).replace(/\s*$/, "\n");
152
+ return `${block}\n\n${existing.replace(/\s*$/, "\n")}`;
153
+ }
154
+
155
+ function renderAgentContextTemplate(
156
+ template: string,
157
+ options: {
158
+ readonly agent: "claude" | "codex" | "both";
159
+ readonly skillSet: "core" | "all";
160
+ readonly workflow: "standard" | "strict";
161
+ readonly includeHusky: boolean;
162
+ readonly includeCi: boolean;
163
+ },
164
+ ): string {
165
+ const commands = [
166
+ "- `phasegate doctor`",
167
+ "- `phasegate phasegate:check-ready`",
168
+ "- `phasegate validate --layer L2 --format human`",
169
+ "- `phasegate setup:agent --dry-run`",
170
+ "- `phasegate config:plan --intent l4-strict --dry-run`",
171
+ ].join("\n");
172
+ return template
173
+ .replaceAll("{{PHASEGATE_AGENT}}", options.agent)
174
+ .replaceAll("{{PHASEGATE_SKILLS_MODE}}", options.skillSet)
175
+ .replaceAll("{{PHASEGATE_WORKFLOW}}", options.workflow)
176
+ .replaceAll("{{PHASEGATE_HUSKY_STATE}}", options.includeHusky ? "managed" : "not managed by this setup run")
177
+ .replaceAll("{{PHASEGATE_CI_STATE}}", options.includeCi ? "managed" : "not managed by this setup run")
178
+ .replaceAll("{{PHASEGATE_COMMANDS}}", commands)
179
+ .replaceAll("{{PHASEGATE_SKILLS}}", options.skillSet === "core" ? "- core skills" : "- all bundled skills")
180
+ .replaceAll("{{PHASEGATE_PRESETS}}", "- `minimal`\n- `standard`\n- `full`\n- `custom`")
181
+ .replaceAll("{{PHASEGATE_USER_SECTION}}", "Project-specific agent instructions go here.");
182
+ }
183
+
134
184
  function escapeRegExp(value: string): string {
135
185
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
136
186
  }
@@ -192,6 +242,9 @@ export class RunInstallUseCase {
192
242
  const includeCodex = input.includeCodex ?? true;
193
243
  const includeHusky = input.includeHusky ?? true;
194
244
  const includeCi = input.includeCi ?? true;
245
+ const skillSet = input.skillSet ?? "all";
246
+ const workflow = input.workflow ?? "standard";
247
+ const agent = input.agent ?? (includeClaude && includeCodex ? "both" : includeCodex ? "codex" : "claude");
195
248
  const targets = this.createTargets({ includeClaude, includeCodex, includeHusky, includeCi });
196
249
  const existingManifest = await this.manifestRepository.load(input.projectRoot);
197
250
  const baseManifest = existingManifest ?? DeploymentManifest.create(input.phasegateVersion);
@@ -205,7 +258,10 @@ export class RunInstallUseCase {
205
258
  for (const target of targets) {
206
259
  const absolutePath = join(input.projectRoot, target.path);
207
260
  const before = await readTextOrNull(absolutePath);
208
- const template = await readFile(join(input.harnessRoot, target.templatePath), "utf8");
261
+ const rawTemplate = await readFile(join(input.harnessRoot, target.templatePath), "utf8");
262
+ const template = target.strategy === "markdown-managed"
263
+ ? renderAgentContextTemplate(rawTemplate, { agent, skillSet, workflow, includeHusky, includeCi })
264
+ : rawTemplate;
209
265
  const repairMode = this.repairMode(target, before);
210
266
  const next = this.merge(target, before, template, input.phasegateVersion);
211
267
  const didChange = before !== next;
@@ -300,10 +356,26 @@ export class RunInstallUseCase {
300
356
  }): readonly InstallTarget[] {
301
357
  return [
302
358
  ...(options.includeClaude
303
- ? [{ path: ".claude/settings.json", strategy: "json" as const, templatePath: "templates/.claude/settings.json" }]
359
+ ? [
360
+ { path: ".claude/settings.json", strategy: "json" as const, templatePath: "templates/.claude/settings.json" },
361
+ {
362
+ path: "CLAUDE.md",
363
+ strategy: "markdown-managed" as const,
364
+ templatePath: "docs/templates/agent-context/CLAUDE.md.template.md",
365
+ block: { start: MARKDOWN_BEGIN, end: MARKDOWN_END, content: "phasegate CLAUDE.md managed section" },
366
+ },
367
+ ]
304
368
  : []),
305
369
  ...(options.includeCodex
306
- ? [{ path: ".codex/hooks.json", strategy: "json" as const, templatePath: "templates/.codex/hooks.json" }]
370
+ ? [
371
+ { path: ".codex/hooks.json", strategy: "json" as const, templatePath: "templates/.codex/hooks.json" },
372
+ {
373
+ path: "AGENTS.md",
374
+ strategy: "markdown-managed" as const,
375
+ templatePath: "docs/templates/agent-context/AGENTS.md.template.md",
376
+ block: { start: MARKDOWN_BEGIN, end: MARKDOWN_END, content: "phasegate AGENTS.md managed section" },
377
+ },
378
+ ]
307
379
  : []),
308
380
  ...(options.includeHusky
309
381
  ? [
@@ -346,6 +418,7 @@ export class RunInstallUseCase {
346
418
  private repairMode(target: InstallTarget, before: string | null): RepairMode {
347
419
  if (target.strategy === "shell") return shellRepairMode(before);
348
420
  if (target.strategy === "json") return jsonRepairMode(before);
421
+ if (target.strategy === "markdown-managed") return "mechanical";
349
422
  return "mechanical";
350
423
  }
351
424
 
@@ -358,6 +431,7 @@ export class RunInstallUseCase {
358
431
  private merge(target: InstallTarget, before: string | null, template: string, version: string): string {
359
432
  if (target.strategy === "yaml-add") return before ?? template;
360
433
  if (target.strategy === "shell") return mergeShell(before, template);
434
+ if (target.strategy === "markdown-managed") return mergeManagedMarkdown(before, template);
361
435
  if (target.strategy === "package-json") {
362
436
  const existing = before === null ? {} : (JSON.parse(before) as unknown);
363
437
  const merged = mergePackageJson(isRecord(existing) ? existing : {}, version || PHASEGATE_SCRIPT_VERSION);
@@ -1,6 +1,7 @@
1
1
  // @unit installation
2
2
  // @layer application
3
3
  // @work-item-id WI-148
4
+ // @work-item-id WI-174
4
5
 
5
6
  import { access, chmod, copyFile, lstat, mkdir, readFile, readlink, symlink, writeFile } from "node:fs/promises";
6
7
  import { dirname, join, relative, resolve } from "node:path";
@@ -12,7 +13,7 @@ import type { HashCalculatorPort } from "../ports/hash-calculator-port.js";
12
13
  import type { ManifestRepositoryPort } from "../ports/manifest-repository-port.js";
13
14
 
14
15
  type ReconcileAction = "missing-manifest" | "update" | "add" | "link" | "skip" | "refuse";
15
- type StrategyType = "json" | "shell" | "yaml-add" | "package-json" | "symlink" | "unknown";
16
+ type StrategyType = "json" | "shell" | "yaml-add" | "package-json" | "markdown-managed" | "symlink" | "unknown";
16
17
 
17
18
  export interface ReconcilePlanItem {
18
19
  readonly path: string;
@@ -52,6 +53,8 @@ interface ReconcileTarget {
52
53
  const SKILL_HINT = "invoke /phasegate-config-doctor";
53
54
  const SHELL_BEGIN = "# === phasegate managed (BEGIN) ===";
54
55
  const SHELL_END = "# === phasegate managed (END) ===";
56
+ const MARKDOWN_BEGIN = "<!-- phasegate:managed-section:start -->";
57
+ const MARKDOWN_END = "<!-- phasegate:managed-section:end -->";
55
58
 
56
59
  function isRecord(value: unknown): value is Record<string, unknown> {
57
60
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -136,6 +139,41 @@ function reconcileShell(existing: string | null, incoming: string): string {
136
139
  return `${existing.replace(/\s*$/, "\n\n")}${incomingBlock}\n`;
137
140
  }
138
141
 
142
+ function managedMarkdownBlock(content: string): string {
143
+ const start = content.indexOf(MARKDOWN_BEGIN);
144
+ const end = content.indexOf(MARKDOWN_END);
145
+ if (start === -1 || end === -1 || end < start) return content.trim();
146
+ return content.slice(start, end + MARKDOWN_END.length).trim();
147
+ }
148
+
149
+ function reconcileManagedMarkdown(existing: string | null, incoming: string): string {
150
+ const block = managedMarkdownBlock(incoming);
151
+ if (existing === null || existing.trim().length === 0) return `${incoming.trim()}\n`;
152
+ const pattern = new RegExp(`${escapeRegExp(MARKDOWN_BEGIN)}[\\s\\S]*?${escapeRegExp(MARKDOWN_END)}`);
153
+ if (pattern.test(existing)) return existing.replace(pattern, block).replace(/\s*$/, "\n");
154
+ return `${block}\n\n${existing.replace(/\s*$/, "\n")}`;
155
+ }
156
+
157
+ function renderAgentContextTemplate(template: string): string {
158
+ const commands = [
159
+ "- `phasegate doctor`",
160
+ "- `phasegate phasegate:check-ready`",
161
+ "- `phasegate validate --layer L2 --format human`",
162
+ "- `phasegate setup:agent --dry-run`",
163
+ "- `phasegate config:plan --intent l4-strict --dry-run`",
164
+ ].join("\n");
165
+ return template
166
+ .replaceAll("{{PHASEGATE_AGENT}}", "both")
167
+ .replaceAll("{{PHASEGATE_SKILLS_MODE}}", "all")
168
+ .replaceAll("{{PHASEGATE_WORKFLOW}}", "standard")
169
+ .replaceAll("{{PHASEGATE_HUSKY_STATE}}", "managed")
170
+ .replaceAll("{{PHASEGATE_CI_STATE}}", "managed")
171
+ .replaceAll("{{PHASEGATE_COMMANDS}}", commands)
172
+ .replaceAll("{{PHASEGATE_SKILLS}}", "- all bundled skills")
173
+ .replaceAll("{{PHASEGATE_PRESETS}}", "- `minimal`\n- `standard`\n- `full`\n- `custom`")
174
+ .replaceAll("{{PHASEGATE_USER_SECTION}}", "Project-specific agent instructions go here.");
175
+ }
176
+
139
177
  function reconcilePackageJson(existing: Record<string, unknown>, version: string): Record<string, unknown> {
140
178
  const devDependencies = isRecord(existing.devDependencies) ? existing.devDependencies : {};
141
179
  const scripts = isRecord(existing.scripts) ? existing.scripts : {};
@@ -259,7 +297,8 @@ export class RunReconcileUseCase {
259
297
  if (before === null) return this.planMissingTarget(input, target);
260
298
  const currentHash = this.hashCalculator.compute(before);
261
299
  const matchesManifest = currentHash.equals(entry.hash);
262
- const template = target.templatePath ? await readFile(join(input.harnessRoot, target.templatePath), "utf8") : "";
300
+ const rawTemplate = target.templatePath ? await readFile(join(input.harnessRoot, target.templatePath), "utf8") : "";
301
+ const template = target.strategy === "markdown-managed" ? renderAgentContextTemplate(rawTemplate) : rawTemplate;
263
302
  const next = entry.mode === "created" && target.strategy !== "package-json"
264
303
  ? template
265
304
  : this.reconcileContent(target, before, template, input.phasegateVersion);
@@ -290,7 +329,8 @@ export class RunReconcileUseCase {
290
329
  if (target.strategy === "symlink") return this.planSymlink(input.projectRoot, target.path);
291
330
  const absolutePath = this.resolveProjectPath(input.projectRoot, target.path);
292
331
  const before = await readTextOrNull(absolutePath);
293
- const template = target.templatePath ? await readFile(join(input.harnessRoot, target.templatePath), "utf8") : "";
332
+ const rawTemplate = target.templatePath ? await readFile(join(input.harnessRoot, target.templatePath), "utf8") : "";
333
+ const template = target.strategy === "markdown-managed" ? renderAgentContextTemplate(rawTemplate) : rawTemplate;
294
334
  const next = before === null && target.strategy !== "package-json"
295
335
  ? template
296
336
  : this.reconcileContent(target, before, template, input.phasegateVersion);
@@ -350,6 +390,7 @@ export class RunReconcileUseCase {
350
390
  private reconcileContent(target: ReconcileTarget, before: string | null, template: string, version: string): string {
351
391
  if (target.strategy === "yaml-add") return template;
352
392
  if (target.strategy === "shell") return reconcileShell(before, template);
393
+ if (target.strategy === "markdown-managed") return reconcileManagedMarkdown(before, template);
353
394
  if (target.strategy === "package-json") {
354
395
  const existing = before === null ? {} : (JSON.parse(before) as unknown);
355
396
  return `${JSON.stringify(reconcilePackageJson(isRecord(existing) ? existing : {}, version), null, 2)}\n`;
@@ -362,7 +403,19 @@ export class RunReconcileUseCase {
362
403
  private createTargets(): readonly ReconcileTarget[] {
363
404
  return [
364
405
  { path: ".claude/settings.json", strategy: "json", templatePath: "templates/.claude/settings.json" },
406
+ {
407
+ path: "CLAUDE.md",
408
+ strategy: "markdown-managed",
409
+ templatePath: "docs/templates/agent-context/CLAUDE.md.template.md",
410
+ block: { start: MARKDOWN_BEGIN, end: MARKDOWN_END, content: "phasegate CLAUDE.md managed section" },
411
+ },
365
412
  { path: ".codex/hooks.json", strategy: "json", templatePath: "templates/.codex/hooks.json" },
413
+ {
414
+ path: "AGENTS.md",
415
+ strategy: "markdown-managed",
416
+ templatePath: "docs/templates/agent-context/AGENTS.md.template.md",
417
+ block: { start: MARKDOWN_BEGIN, end: MARKDOWN_END, content: "phasegate AGENTS.md managed section" },
418
+ },
366
419
  {
367
420
  path: ".husky/pre-commit",
368
421
  strategy: "shell",
@@ -401,7 +454,7 @@ export class RunReconcileUseCase {
401
454
 
402
455
  private managedBlockFor(path: string, strategy: StrategyType): ManagedBlockInput | null {
403
456
  if (strategy === "shell") return { start: SHELL_BEGIN, end: SHELL_END, content: `phasegate ${path} managed block` };
404
- if (strategy === "json" || strategy === "package-json") {
457
+ if (strategy === "json" || strategy === "package-json" || strategy === "markdown-managed") {
405
458
  return { start: "phasegate structured merge", end: "phasegate structured merge", content: `${strategy}:${path}` };
406
459
  }
407
460
  return null;
@@ -1,6 +1,7 @@
1
1
  // @unit installation
2
2
  // @layer application
3
3
  // @work-item-id WI-147
4
+ // @work-item-id WI-174
4
5
 
5
6
  import { access, copyFile, lstat, mkdir, readFile, readlink, rm, rmdir, writeFile } from "node:fs/promises";
6
7
  import { dirname, join, relative, resolve } from "node:path";
@@ -10,7 +11,7 @@ import type { HashCalculatorPort } from "../ports/hash-calculator-port.js";
10
11
  import type { ManifestRepositoryPort } from "../ports/manifest-repository-port.js";
11
12
 
12
13
  type UninstallAction = "missing-manifest" | "delete" | "unlink" | "reverse-merge" | "skip" | "refuse";
13
- type StrategyType = "created" | "json" | "shell" | "package-json" | "symlink" | "yaml-add" | "unknown";
14
+ type StrategyType = "created" | "json" | "shell" | "package-json" | "markdown-managed" | "symlink" | "yaml-add" | "unknown";
14
15
 
15
16
  export interface UninstallPlanItem {
16
17
  readonly path: string;
@@ -42,6 +43,8 @@ export interface RunUninstallResult {
42
43
  const SKILL_HINT = "invoke /phasegate-config-doctor";
43
44
  const SHELL_BEGIN = "# === phasegate managed (BEGIN) ===";
44
45
  const SHELL_END = "# === phasegate managed (END) ===";
46
+ const MARKDOWN_BEGIN = "<!-- phasegate:managed-section:start -->";
47
+ const MARKDOWN_END = "<!-- phasegate:managed-section:end -->";
45
48
  const PHASEGATE_SCRIPT_PREFIX = "phasegate:";
46
49
 
47
50
  function isRecord(value: unknown): value is Record<string, unknown> {
@@ -108,6 +111,11 @@ export function reverseShellMerge(currentContent: string): string {
108
111
  return currentContent.replace(pattern, "\n").replace(/\n{3,}/g, "\n\n").replace(/\s*$/, "\n").replace(/^\n/, "");
109
112
  }
110
113
 
114
+ export function reverseManagedMarkdown(currentContent: string): string {
115
+ const pattern = new RegExp(`\\n?${escapeRegExp(MARKDOWN_BEGIN)}[\\s\\S]*?${escapeRegExp(MARKDOWN_END)}\\n?`);
116
+ return currentContent.replace(pattern, "\n").replace(/\n{3,}/g, "\n\n").replace(/\s*$/, "\n").replace(/^\n/, "");
117
+ }
118
+
111
119
  export function reversePackageJsonMerge(currentContent: string): string {
112
120
  const parsed = JSON.parse(currentContent) as unknown;
113
121
  const result = isRecord(parsed) ? { ...parsed } : {};
@@ -300,6 +308,7 @@ export class RunUninstallUseCase {
300
308
 
301
309
  private async reverseMerged(harnessRoot: string, path: string, currentContent: string, strategy: StrategyType): Promise<string> {
302
310
  if (strategy === "shell") return currentContent.includes(SHELL_BEGIN) ? reverseShellMerge(currentContent) : currentContent;
311
+ if (strategy === "markdown-managed") return currentContent.includes(MARKDOWN_BEGIN) ? reverseManagedMarkdown(currentContent) : currentContent;
303
312
  if (strategy === "package-json") return reversePackageJsonMerge(currentContent);
304
313
  if (strategy === "json") return reverseJsonMerge(currentContent, await readFile(join(harnessRoot, this.templateFor(path)), "utf8"));
305
314
  throw new Error(`Unsupported merged strategy: ${strategy}`);
@@ -309,6 +318,7 @@ export class RunUninstallUseCase {
309
318
  if (mode === "symlink") return "symlink";
310
319
  if (mode === "created") return path.endsWith(".yml") || path.endsWith(".yaml") ? "yaml-add" : "created";
311
320
  if (path === "package.json") return "package-json";
321
+ if (path === "AGENTS.md" || path === "CLAUDE.md") return "markdown-managed";
312
322
  if (path.endsWith(".json")) return "json";
313
323
  if (path.startsWith(".husky/")) return "shell";
314
324
  return "unknown";
@@ -317,6 +327,8 @@ export class RunUninstallUseCase {
317
327
  private templateFor(path: string): string {
318
328
  if (path === ".claude/settings.json") return "templates/.claude/settings.json";
319
329
  if (path === ".codex/hooks.json") return "templates/.codex/hooks.json";
330
+ if (path === "CLAUDE.md") return "docs/templates/agent-context/CLAUDE.md.template.md";
331
+ if (path === "AGENTS.md") return "docs/templates/agent-context/AGENTS.md.template.md";
320
332
  throw new Error(`No template for ${path}`);
321
333
  }
322
334
 
@@ -12,6 +12,13 @@ export interface InstallHandlerInput {
12
12
  readonly apply: boolean;
13
13
  readonly force: boolean;
14
14
  readonly json: boolean;
15
+ readonly includeClaude?: boolean;
16
+ readonly includeCodex?: boolean;
17
+ readonly includeHusky?: boolean;
18
+ readonly includeCi?: boolean;
19
+ readonly skillSet?: "core" | "all";
20
+ readonly workflow?: "standard" | "strict";
21
+ readonly agent?: "claude" | "codex" | "both";
15
22
  }
16
23
 
17
24
  export interface InstallHandlerResult {
@@ -3,6 +3,7 @@
3
3
  * @layer presentation
4
4
  * @work-item-id WI-090 / WI-091
5
5
  * @work-item-id WI-113 / WI-142
6
+ * @work-item-id WI-171 / WI-172 / WI-173
6
7
  *
7
8
  * Phasegate CLI エントリポイント。
8
9
  * 各Unitの Composition Root からハンドラーを取得し、コマンドに応じてディスパッチする。
@@ -155,6 +156,8 @@ Setup:
155
156
  install Install phasegate managed files (--dry-run|--apply, --force)
156
157
  uninstall Uninstall phasegate managed files (--dry-run|--apply, --force)
157
158
  reconcile Reconcile phasegate managed files (--dry-run|--apply, --force)
159
+ setup:agent Diagnose repo setup and produce/apply an agent-readable setup plan
160
+ config:plan Produce an agent-readable configuration change plan
158
161
 
159
162
  Commands:
160
163
  enable-feature <name> Enable a harness feature
@@ -193,6 +196,8 @@ Commands:
193
196
  ci:auto-refresh-agent-context Refresh AGENTS.md / CLAUDE.md (--dry-run, --apply, --json)
194
197
  refresh-claude-md Refresh CLAUDE.md standard sections (--dry-run, --apply, --json)
195
198
  p2:check-agent-context Check AGENTS.md / CLAUDE.md freshness (--threshold-days <n>, --json)
199
+ setup:agent Plan agent-driven setup (--intent <minimal|recommended|strict|ci-only|agent-hooks|retrofit>, --agent <claude|codex|both>, --dry-run|--apply, --json)
200
+ config:plan Plan safe config changes (--intent <l4-strict|codex-hooks|ci-fail-on-warning|baseline-reset|quick-mode-strict>, --dry-run, --json)
196
201
  ci:check-repetition Check error repetition (--code <errorCode>, --reset, --json)
197
202
  baseline Create retrofit baseline snapshot (--dry-run, --force, --paths <glob,glob,...>, --json)
198
203
  scaffold-design Scaffold a design doc (--unit <id>, --phase <logical|domain|uiux|unit-test|it-test>, --force, --json)
@@ -482,8 +487,38 @@ Options:
482
487
  --dry-run Preview target actions without writing (default)
483
488
  --apply Write merge results and manifest
484
489
  --force Force ai-assisted/manual targets after backing up existing files
490
+ --agent <claude|codex|both> Agent context and hook targets (default: both)
491
+ --skills <core|all> Rendered agent context skill mode (default: all)
492
+ --workflow <standard|strict> Rendered agent context workflow mode (default: standard)
493
+ --with-husky Include Husky hook targets
494
+ --with-ci Include GitHub Actions target
485
495
  --json Output machine-readable JSON
486
496
  --help, -h Show this help`,
497
+ "setup:agent": `Usage: phasegate setup:agent [options]
498
+
499
+ Diagnose repository setup and produce an agent-readable setup plan.
500
+
501
+ Options:
502
+ --intent <minimal|recommended|strict|ci-only|agent-hooks|retrofit>
503
+ --agent <claude|codex|both>
504
+ --workflow <standard|strict>
505
+ --with-husky
506
+ --with-ci
507
+ --dry-run
508
+ --apply
509
+ --json
510
+ --help, -h Show this help`,
511
+ "config:plan": `Usage: phasegate config:plan --intent <intent> [options]
512
+
513
+ Produce an agent-readable configuration change plan.
514
+
515
+ Intents:
516
+ l4-strict, codex-hooks, ci-fail-on-warning, baseline-reset, quick-mode-strict
517
+
518
+ Options:
519
+ --dry-run
520
+ --json
521
+ --help, -h Show this help`,
487
522
  reconcile: `Usage: phasegate reconcile [options]
488
523
 
489
524
  Reconcile PhaseGate-managed files with the current bundled templates.
@@ -685,6 +720,9 @@ function parseCoverageThreshold(raw: string | undefined): number {
685
720
  }
686
721
 
687
722
  type InitPhasePreset = "full" | "standard" | "minimal" | "custom";
723
+ type AgentTarget = "claude" | "codex" | "both";
724
+ type SetupIntent = "minimal" | "recommended" | "strict" | "ci-only" | "agent-hooks" | "retrofit";
725
+ type ConfigChangeIntent = "l4-strict" | "codex-hooks" | "ci-fail-on-warning" | "baseline-reset" | "quick-mode-strict";
688
726
 
689
727
  function parseInitPhasePreset(value: string | undefined): InitPhasePreset | undefined {
690
728
  if (value === undefined) return undefined;
@@ -694,6 +732,149 @@ function parseInitPhasePreset(value: string | undefined): InitPhasePreset | unde
694
732
  return undefined;
695
733
  }
696
734
 
735
+ function parseAgentTarget(value: string | undefined, fallback: AgentTarget = "both"): AgentTarget {
736
+ if (value === "claude" || value === "codex" || value === "both") return value;
737
+ return fallback;
738
+ }
739
+
740
+ function parseSetupIntent(value: string | undefined): SetupIntent {
741
+ if (
742
+ value === "minimal" ||
743
+ value === "recommended" ||
744
+ value === "strict" ||
745
+ value === "ci-only" ||
746
+ value === "agent-hooks" ||
747
+ value === "retrofit"
748
+ ) {
749
+ return value;
750
+ }
751
+ return "recommended";
752
+ }
753
+
754
+ function parseConfigChangeIntent(value: string | undefined): ConfigChangeIntent {
755
+ if (
756
+ value === "l4-strict" ||
757
+ value === "codex-hooks" ||
758
+ value === "ci-fail-on-warning" ||
759
+ value === "baseline-reset" ||
760
+ value === "quick-mode-strict"
761
+ ) {
762
+ return value;
763
+ }
764
+ return "l4-strict";
765
+ }
766
+
767
+ async function projectFileExists(rootDir: string, relativePath: string): Promise<boolean> {
768
+ try {
769
+ await fsReadFile(join(rootDir, relativePath));
770
+ return true;
771
+ } catch {
772
+ return false;
773
+ }
774
+ }
775
+
776
+ async function buildAgentSetupPlan(rootDir: string, input: {
777
+ readonly intent: SetupIntent;
778
+ readonly agent: AgentTarget;
779
+ readonly withHusky: boolean;
780
+ readonly withCi: boolean;
781
+ readonly workflow: WorkflowMode;
782
+ }) {
783
+ const checks = {
784
+ packageJson: await projectFileExists(rootDir, "package.json"),
785
+ phasegateConfig: await projectFileExists(rootDir, "phasegate.config.json"),
786
+ claudeSettings: await projectFileExists(rootDir, ".claude/settings.json"),
787
+ codexHooks: await projectFileExists(rootDir, ".codex/hooks.json"),
788
+ agentsMd: await projectFileExists(rootDir, "AGENTS.md"),
789
+ claudeMd: await projectFileExists(rootDir, "CLAUDE.md"),
790
+ huskyPreCommit: await projectFileExists(rootDir, ".husky/pre-commit"),
791
+ ciWorkflow: await projectFileExists(rootDir, ".github/workflows/phasegate-aidlc-gate.yml"),
792
+ };
793
+ const includeClaude = input.agent === "claude" || input.agent === "both";
794
+ const includeCodex = input.agent === "codex" || input.agent === "both";
795
+ const changes = [
796
+ !checks.packageJson ? "Add phasegate devDependency and phasegate scripts to package.json." : "Keep existing package.json and merge missing phasegate scripts only.",
797
+ !checks.phasegateConfig ? `Create phasegate.config.json for ${input.workflow} workflow.` : "Keep existing phasegate.config.json; review config:plan before changing policy.",
798
+ includeClaude ? "Create or refresh .claude/settings.json and CLAUDE.md managed section." : null,
799
+ includeCodex ? "Create or refresh .codex/hooks.json and AGENTS.md managed section." : null,
800
+ input.withHusky ? "Create or refresh Husky pre-commit, commit-msg, and pre-push backstops." : "Leave Husky hooks unmanaged in this setup run.",
801
+ input.withCi ? "Create or refresh GitHub Actions PhaseGate workflow." : "Leave CI workflow unmanaged in this setup run.",
802
+ ].filter((item): item is string => item !== null);
803
+ const questions = [
804
+ input.intent === "recommended" ? "Do you want both Claude and Codex context files, or only the agent you actively use?" : null,
805
+ input.intent === "retrofit" ? "Should existing hooks/workflows be preserved as user-owned content or migrated into PhaseGate managed blocks?" : null,
806
+ input.intent === "ci-only" ? "Should local hooks remain disabled while CI enforces the same checks?" : null,
807
+ input.workflow !== "strict" ? "Do you want strict WI/product reflection enforcement now, or after the first green run?" : null,
808
+ ].filter((item): item is string => item !== null);
809
+ return {
810
+ intent: input.intent,
811
+ agent: input.agent,
812
+ detected: checks,
813
+ questions,
814
+ changes,
815
+ risks: [
816
+ "Existing user content outside PhaseGate managed markers is preserved.",
817
+ "Manual review is still required when a managed target has complex user edits and --force is not used.",
818
+ ],
819
+ rollback: [
820
+ "Run phasegate uninstall --dry-run to preview reversal.",
821
+ "Run phasegate uninstall --apply after reviewing the managed targets.",
822
+ "Backups are written under .phasegate/backups when force is used on changed managed files.",
823
+ ],
824
+ validation: [
825
+ "phasegate doctor",
826
+ "phasegate phasegate:check-ready",
827
+ "phasegate validate --layer L2 --format human",
828
+ ],
829
+ };
830
+ }
831
+
832
+ function buildConfigChangePlan(intent: ConfigChangeIntent) {
833
+ const catalog: Record<ConfigChangeIntent, {
834
+ readonly targets: readonly string[];
835
+ readonly commands: readonly string[];
836
+ readonly validations: readonly string[];
837
+ readonly risks: readonly string[];
838
+ }> = {
839
+ "l4-strict": {
840
+ targets: ["phasegate.config.json: layers.L4.enabled", "phasegate.config.json: layers.L4.failOnWarning"],
841
+ commands: ["phasegate validate --layer L4 --fail-on-warning --format human"],
842
+ validations: ["phasegate phasegate:detect-drift --json", "phasegate phasegate:check-ready"],
843
+ risks: ["L4 findings may be advisory today but become blocking when fail-on-warning is enabled."],
844
+ },
845
+ "codex-hooks": {
846
+ targets: [".codex/hooks.json", "AGENTS.md", ".codex/skills"],
847
+ commands: ["phasegate install --agent codex --apply", "codex features enable codex_hooks"],
848
+ validations: ["phasegate doctor --json", "phasegate phasegate:status --json"],
849
+ risks: ["Codex apply_patch writes still require the pre-commit backstop for full coverage."],
850
+ },
851
+ "ci-fail-on-warning": {
852
+ targets: [".github/workflows/phasegate-aidlc-gate.yml", "phasegate.config.json"],
853
+ commands: ["phasegate install --with-ci --apply", "phasegate validate --layer L4 --fail-on-warning"],
854
+ validations: ["phasegate doctor", "phasegate ci:generate-template --type aidlc-gate --render"],
855
+ risks: ["Existing warning-only projects may start failing CI after rollout."],
856
+ },
857
+ "baseline-reset": {
858
+ targets: [".phasegate/baseline.json"],
859
+ commands: ["phasegate baseline --dry-run", "phasegate baseline --force --json"],
860
+ validations: ["phasegate phasegate:status --json", "phasegate phasegate:check-ready"],
861
+ risks: ["A reset can hide historical drift if reviewed without the generated diff."],
862
+ },
863
+ "quick-mode-strict": {
864
+ targets: ["phasegate.config.json: quickMode"],
865
+ commands: ["phasegate check-change-category --paths <changed-files> --format json"],
866
+ validations: ["phasegate ci-check --quick --dry-run", "phasegate phasegate:check-ready"],
867
+ risks: ["More changes will require Full Mode validation before commit."],
868
+ },
869
+ };
870
+ return {
871
+ intent,
872
+ ...catalog[intent],
873
+ diffExplanation: "Review the listed targets first, apply through PhaseGate managed commands where possible, then run the validations in order.",
874
+ rollback: "Use git diff for config changes; use phasegate uninstall/reconcile dry-runs for managed setup targets.",
875
+ };
876
+ }
877
+
697
878
  type RuleSeverity = "error" | "warning" | "off";
698
879
 
699
880
  function toRuleSeverity(value: string): RuleSeverity {
@@ -999,6 +1180,9 @@ async function main(): Promise<void> {
999
1180
  includeCodex: deployCodex,
1000
1181
  includeHusky: withHusky,
1001
1182
  includeCi: withCi,
1183
+ skillSet,
1184
+ workflow,
1185
+ agent,
1002
1186
  });
1003
1187
  console.log(
1004
1188
  `✓ Skills deployed to ${result.targetDir} (${result.deployedSkills.length} skills, set: ${skillSet})`,
@@ -1196,7 +1380,7 @@ async function main(): Promise<void> {
1196
1380
  }
1197
1381
 
1198
1382
  case "install": {
1199
- const KNOWN_INSTALL_FLAGS = ["--dry-run", "--apply", "--force", "--json"];
1383
+ const KNOWN_INSTALL_FLAGS = ["--dry-run", "--apply", "--force", "--json", "--agent", "--skills", "--workflow", "--with-husky", "--with-ci"];
1200
1384
  const flagError = validateKnownFlags(args, KNOWN_INSTALL_FLAGS);
1201
1385
  if (flagError) {
1202
1386
  console.error(flagError);
@@ -1204,6 +1388,19 @@ async function main(): Promise<void> {
1204
1388
  }
1205
1389
  const apply = hasFlag(args, "--apply");
1206
1390
  const dryRun = hasFlag(args, "--dry-run") || !apply;
1391
+ const agent = parseAgentTarget(parseFlag(args, "--agent"), "both");
1392
+ const skillSetRaw = parseFlag(args, "--skills") ?? "all";
1393
+ if (skillSetRaw !== "core" && skillSetRaw !== "all") {
1394
+ console.error(`Invalid --skills value: "${skillSetRaw}". Use "core" or "all".`);
1395
+ process.exit(2);
1396
+ }
1397
+ const workflowRaw = parseFlag(args, "--workflow");
1398
+ if (workflowRaw !== undefined && workflowRaw !== "standard" && workflowRaw !== "strict") {
1399
+ console.error(`Invalid --workflow value: "${workflowRaw}". Use "standard" or "strict".`);
1400
+ process.exit(2);
1401
+ }
1402
+ const includeClaude = agent === "claude" || agent === "both";
1403
+ const includeCodex = agent === "codex" || agent === "both";
1207
1404
  const mod = createInstallationModule();
1208
1405
  const phasegateVersion = await getHarnessVersion(harnessRoot);
1209
1406
  const result = await mod.installHandler.execute({
@@ -1213,6 +1410,13 @@ async function main(): Promise<void> {
1213
1410
  dryRun,
1214
1411
  apply,
1215
1412
  force: hasFlag(args, "--force"),
1413
+ includeClaude,
1414
+ includeCodex,
1415
+ includeHusky: true,
1416
+ includeCi: true,
1417
+ skillSet: skillSetRaw,
1418
+ workflow: parseWorkflowMode(workflowRaw),
1419
+ agent,
1216
1420
  json,
1217
1421
  });
1218
1422
  console.log(result.stdout);
@@ -1220,6 +1424,94 @@ async function main(): Promise<void> {
1220
1424
  break;
1221
1425
  }
1222
1426
 
1427
+ case "setup:agent": {
1428
+ const KNOWN_SETUP_AGENT_FLAGS = ["--intent", "--agent", "--workflow", "--with-husky", "--with-ci", "--dry-run", "--apply", "--force", "--json"];
1429
+ const flagError = validateKnownFlags(args, KNOWN_SETUP_AGENT_FLAGS);
1430
+ if (flagError) {
1431
+ console.error(flagError);
1432
+ process.exit(2);
1433
+ }
1434
+ const intent = parseSetupIntent(parseFlag(args, "--intent"));
1435
+ const agent = parseAgentTarget(parseFlag(args, "--agent"), "both");
1436
+ const workflow = parseWorkflowMode(parseFlag(args, "--workflow") ?? (intent === "strict" ? "strict" : "standard"));
1437
+ const withCi = hasFlag(args, "--with-ci") || intent === "ci-only" || intent === "strict";
1438
+ const withHusky = hasFlag(args, "--with-husky") || intent === "agent-hooks" || intent === "strict";
1439
+ const plan = await buildAgentSetupPlan(rootDir, { intent, agent, withHusky, withCi, workflow });
1440
+ const apply = hasFlag(args, "--apply");
1441
+ let installResult: unknown = null;
1442
+ let bootstrapResult: unknown = null;
1443
+ if (apply) {
1444
+ const skillResult = await deploySkills(harnessRoot, rootDir, "all");
1445
+ const packageResult = await ensurePhasegatePackageDependency(rootDir, skillResult.version);
1446
+ const configResult = await initHarnessConfig(rootDir, "my-project", workflow === "strict" ? "full" : "standard", {
1447
+ ciEnabled: withCi,
1448
+ workflow,
1449
+ });
1450
+ bootstrapResult = {
1451
+ skillsDeployed: skillResult.deployedSkills.length,
1452
+ packageDependency: packageResult,
1453
+ configCreated: configResult.created,
1454
+ };
1455
+ const mod = createInstallationModule();
1456
+ const phasegateVersion = await getHarnessVersion(harnessRoot);
1457
+ installResult = await mod.runInstallUseCase.execute({
1458
+ projectRoot: rootDir,
1459
+ harnessRoot,
1460
+ phasegateVersion,
1461
+ dryRun: false,
1462
+ apply: true,
1463
+ force: hasFlag(args, "--force"),
1464
+ includeClaude: agent === "claude" || agent === "both",
1465
+ includeCodex: agent === "codex" || agent === "both",
1466
+ includeHusky: withHusky,
1467
+ includeCi: withCi,
1468
+ skillSet: "all",
1469
+ workflow,
1470
+ agent,
1471
+ });
1472
+ }
1473
+ const output = { plan, applied: apply, bootstrapResult, installResult };
1474
+ if (json) {
1475
+ console.log(JSON.stringify(output, null, 2));
1476
+ } else {
1477
+ console.log(`phasegate setup:agent ${apply ? "apply" : "dry-run"} (${intent}, ${agent})`);
1478
+ for (const change of plan.changes) console.log(`- ${change}`);
1479
+ if (plan.questions.length > 0) {
1480
+ console.log("");
1481
+ console.log("Questions:");
1482
+ for (const question of plan.questions) console.log(`- ${question}`);
1483
+ }
1484
+ console.log("");
1485
+ console.log("Validation:");
1486
+ for (const command of plan.validation) console.log(`- ${command}`);
1487
+ }
1488
+ process.exit(0);
1489
+ break;
1490
+ }
1491
+
1492
+ case "config:plan": {
1493
+ const KNOWN_CONFIG_PLAN_FLAGS = ["--intent", "--dry-run", "--json"];
1494
+ const flagError = validateKnownFlags(args, KNOWN_CONFIG_PLAN_FLAGS);
1495
+ if (flagError) {
1496
+ console.error(flagError);
1497
+ process.exit(2);
1498
+ }
1499
+ const plan = buildConfigChangePlan(parseConfigChangeIntent(parseFlag(args, "--intent")));
1500
+ if (json) {
1501
+ console.log(JSON.stringify(plan, null, 2));
1502
+ } else {
1503
+ console.log(`phasegate config:plan (${plan.intent})`);
1504
+ console.log("Targets:");
1505
+ for (const target of plan.targets) console.log(`- ${target}`);
1506
+ console.log("Commands:");
1507
+ for (const command of plan.commands) console.log(`- ${command}`);
1508
+ console.log("Validation:");
1509
+ for (const validation of plan.validations) console.log(`- ${validation}`);
1510
+ }
1511
+ process.exit(0);
1512
+ break;
1513
+ }
1514
+
1223
1515
  case "uninstall": {
1224
1516
  const KNOWN_UNINSTALL_FLAGS = ["--dry-run", "--apply", "--force", "--json"];
1225
1517
  const flagError = validateKnownFlags(args, KNOWN_UNINSTALL_FLAGS);
@@ -39,6 +39,7 @@ phasegate を導入した直後の config は単純な default で、実プロ
39
39
  | Codex hooks | `.codex/hooks.json` | managed hook JSON と Codex hook 配線確認 |
40
40
  | Husky scripts | `.husky/pre-commit`, `.husky/commit-msg`, `.husky/pre-push` | pre-commit backstop と bypass audit の確認 |
41
41
  | CI workflows | `.github/workflows/*` | `phasegate-aidlc-gate.yml` や既存 workflow との競合確認 |
42
+ | agent context | `AGENTS.md`, `CLAUDE.md` | PhaseGate managed section、lesson pointer section、user-owned content の境界確認 |
42
43
 
43
44
  **schema は必要なときだけ Read** (enum 違反疑い時など): `node_modules/phasegate/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json` (or `harness-config-v2.schema.json` if v2)。
44
45
 
@@ -131,6 +132,9 @@ product-architect で Unit を作り、いくつかの logical_design を書い
131
132
  - reconcile / uninstall が refuse → user modified managed target として扱い、`--force` のリスクと backup path を説明して承認を取る
132
133
  - Codex の `codex_hooks` feature flag は user-level setting。project-local `install` では変更されないため、必要なら `codex features enable codex_hooks` を案内
133
134
  - Codex native `apply_patch` bypass は hook で完全捕捉できない。`.husky/pre-commit` の `phasegate pre-commit` が backstop になるため、Husky 配線を診断対象に含める
135
+ - 初回 setup / retrofit / CI-only / agent-hooks の判断が曖昧な場合は `npx phasegate setup:agent --dry-run --json` を先に使い、検出済み状態、質問、変更案、rollback、validation を根拠として提案する。<!-- @work-item-id WI-172 -->
136
+ - 「L4 を厳しめにして」「Codex hook を有効にして」「CI で warning を fail にして」などの自然言語依頼は、`npx phasegate config:plan --intent <intent> --dry-run --json` で対象ファイル、コマンド、リスク、検証を確認してから diff を提案する。<!-- @work-item-id WI-173 -->
137
+ - `AGENTS.md` は標準運用ルールの managed section と lesson pointer section を分ける。`ci:auto-refresh-agent-context --apply` は lesson pointers 専用 section を更新し、標準運用ルールや user-owned content を置換してはいけない。<!-- @work-item-id WI-174 -->
134
138
 
135
139
  ### Step 3: 診断レポート
136
140
 
@@ -123,12 +123,17 @@ docs/guide/ # phasegate リポジトリ自体 (dogfood)
123
123
  - 「.phasegate/manifest.json や hook-skip-events は何?」
124
124
 
125
125
  **参照先**:
126
+ - 最短導線: `docs/guide/getting-started.md`
127
+ - recipes: `docs/guide/recipes.md`
128
+ - troubleshooting: `docs/guide/troubleshooting.md`
126
129
  - 新規導入: `docs/guide/installation.md`
127
130
  - 既存プロジェクト導入: `docs/guide/retrofit-adoption.md`
128
131
  - setup artifact / doctor finding / legacy artifact: `docs/guide/setup-artifacts.md`
129
132
 
130
133
  `setup-artifacts.md` は managed target / generated artifact / runtime state / legacy artifact / user-level setting の分類を持つ。`doctor --report-out` は明示 path への出力で、`.phasegate/last-doctor-report.json` は固定生成物ではない点もここを参照する。<!-- @work-item-id WI-153 -->
131
134
 
135
+ `setup:agent` は初回 setup / retrofit / CI-only / agent hook 有効化の agent-readable planner、`config:plan` は安全な設定変更 intent planner。質問が「次に何を実行するか」「この変更はどの file/validation に対応するか」に寄っている場合は、これらの guide と CLI を案内する。<!-- @work-item-id WI-171, WI-172, WI-173 -->
136
+
132
137
  ### 8. skill 一覧と使い分け
133
138
 
134
139
  ユーザー質問例: