ultimate-pi 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/.agents/skills/harness-decisions/SKILL.md +68 -2
  2. package/.agents/skills/harness-git-commit/SKILL.md +72 -0
  3. package/.agents/skills/harness-governor/SKILL.md +2 -2
  4. package/.agents/skills/harness-ls-lint-setup/SKILL.md +59 -0
  5. package/.agents/skills/harness-plan/SKILL.md +13 -11
  6. package/.agents/skills/harness-review/SKILL.md +1 -1
  7. package/.agents/skills/harness-sentrux-repair/SKILL.md +48 -0
  8. package/.agents/skills/sentrux/SKILL.md +4 -2
  9. package/.agents/skills/wiki-save/SKILL.md +1 -1
  10. package/.pi/PACKAGING.md +6 -0
  11. package/.pi/SYSTEM.md +21 -3
  12. package/.pi/agents/harness/ls-lint-steward.md +49 -0
  13. package/.pi/agents/harness/planning/decompose.md +4 -4
  14. package/.pi/agents/harness/reviewing/evaluator.md +1 -1
  15. package/.pi/agents/harness/running/executor.md +1 -1
  16. package/.pi/agents/harness/sentrux-repair-advisor.md +50 -0
  17. package/.pi/agents/pi-pi/prompt-expert.md +17 -2
  18. package/.pi/auto-commit.json +9 -2
  19. package/.pi/extensions/debate-orchestrator.ts +3 -0
  20. package/.pi/extensions/harness-anchored-edit.ts +7 -9
  21. package/.pi/extensions/harness-ask-user.ts +13 -34
  22. package/.pi/extensions/harness-debate-tools.ts +43 -4
  23. package/.pi/extensions/harness-live-widget.ts +28 -19
  24. package/.pi/extensions/harness-run-context.ts +278 -115
  25. package/.pi/extensions/harness-web-tools.ts +598 -471
  26. package/.pi/extensions/ls-lint-rules-sync.ts +103 -0
  27. package/.pi/extensions/observation-bus.ts +4 -0
  28. package/.pi/extensions/policy-gate.ts +270 -229
  29. package/.pi/extensions/sentrux-rules-sync.ts +2 -0
  30. package/.pi/extensions/soundboard.ts +48 -48
  31. package/.pi/harness/README.md +4 -0
  32. package/.pi/harness/agents.manifest.json +15 -7
  33. package/.pi/harness/agents.policy.yaml +49 -82
  34. package/.pi/harness/docs/adrs/0052-ls-lint-naming-lifecycle.md +45 -0
  35. package/.pi/harness/docs/adrs/0052-sentrux-structured-repair.md +38 -0
  36. package/.pi/harness/docs/adrs/0053-plan-task-clarification-gate.md +39 -0
  37. package/.pi/harness/docs/adrs/0054-harness-native-ask-user.md +40 -0
  38. package/.pi/harness/docs/adrs/0055-auto-commit-coauthor-lifecycle.md +40 -0
  39. package/.pi/harness/docs/adrs/README.md +5 -0
  40. package/.pi/harness/docs/practice-map.md +10 -5
  41. package/.pi/harness/evals/smoke/ls-lint-stub.json +10 -0
  42. package/.pi/harness/evolution/self-healing-rules.json +16 -0
  43. package/.pi/harness/ls-lint/naming.manifest.json +128 -0
  44. package/.pi/harness/sentrux/architecture.manifest.json +1 -1
  45. package/.pi/harness/specs/auto-commit.schema.json +63 -0
  46. package/.pi/harness/specs/ls-lint-manifest-proposal.schema.json +80 -0
  47. package/.pi/harness/specs/ls-lint-signal.schema.json +47 -0
  48. package/.pi/harness/specs/naming-manifest.schema.json +54 -0
  49. package/.pi/harness/specs/plan-task-clarification.schema.json +88 -0
  50. package/.pi/harness/specs/sentrux-diagnostics.schema.json +173 -0
  51. package/.pi/harness/specs/sentrux-repair-plan.schema.json +133 -0
  52. package/.pi/harness/specs/sentrux-report.schema.json +119 -0
  53. package/.pi/harness/specs/sentrux-signal.schema.json +34 -1
  54. package/.pi/lib/agents-policy.d.mts +26 -51
  55. package/.pi/lib/agents-policy.mjs +41 -28
  56. package/.pi/lib/agt/build-evaluation-context.ts +136 -64
  57. package/.pi/lib/ask-user/constants.mjs +3 -0
  58. package/.pi/lib/ask-user/constants.ts +4 -0
  59. package/.pi/lib/ask-user/contracts/glimpse-parse.ts +56 -0
  60. package/.pi/lib/ask-user/contracts/glimpse-payload-build.ts +58 -0
  61. package/.pi/lib/ask-user/contracts/glimpse-payload.ts +38 -0
  62. package/.pi/lib/ask-user/core/questionnaire.ts +74 -0
  63. package/.pi/lib/ask-user/dialog.ts +2 -314
  64. package/.pi/lib/ask-user/fallback.ts +2 -78
  65. package/.pi/lib/ask-user/format.ts +85 -0
  66. package/.pi/lib/ask-user/glimpseui.d.ts +10 -0
  67. package/.pi/lib/ask-user/index.ts +114 -0
  68. package/.pi/lib/ask-user/merge-task-clarification.ts +98 -0
  69. package/.pi/lib/ask-user/policy.mjs +43 -0
  70. package/.pi/lib/ask-user/policy.ts +104 -0
  71. package/.pi/lib/ask-user/presenters/glimpse.ts +130 -0
  72. package/.pi/lib/ask-user/presenters/headless.ts +131 -0
  73. package/.pi/lib/ask-user/presenters/select.ts +60 -0
  74. package/.pi/lib/ask-user/presenters/tui.ts +373 -0
  75. package/.pi/lib/ask-user/presenters/types.ts +13 -0
  76. package/.pi/lib/ask-user/render.ts +40 -9
  77. package/.pi/lib/ask-user/schema.ts +66 -13
  78. package/.pi/lib/ask-user/types.ts +60 -3
  79. package/.pi/lib/ask-user/validate-core.mjs +193 -7
  80. package/.pi/lib/ask-user/validate.ts +53 -34
  81. package/.pi/lib/harness-anchored-edit/package.json +3 -0
  82. package/.pi/lib/harness-artifact-gate.ts +75 -21
  83. package/.pi/lib/harness-auto-commit-config.mjs +321 -0
  84. package/.pi/lib/harness-lens/clients/lsp/client.ts +62 -39
  85. package/.pi/lib/harness-lens/clients/tool-policy.ts +73 -181
  86. package/.pi/lib/harness-lens/index.ts +241 -108
  87. package/.pi/lib/harness-lens/tools/lsp-navigation.ts +10 -8
  88. package/.pi/lib/harness-repair-brief.ts +84 -25
  89. package/.pi/lib/harness-run-context.ts +42 -52
  90. package/.pi/lib/harness-sentrux-parse.mjs +272 -0
  91. package/.pi/lib/harness-sentrux-root.mjs +78 -0
  92. package/.pi/lib/harness-slash-completions.ts +116 -0
  93. package/.pi/lib/harness-spawn-topology.ts +121 -87
  94. package/.pi/lib/harness-subagent-submit-registry.ts +10 -0
  95. package/.pi/lib/harness-subagents-bridge.ts +4 -1
  96. package/.pi/lib/harness-ui-state.ts +95 -48
  97. package/.pi/lib/plan-approval/dialog.ts +5 -0
  98. package/.pi/lib/plan-approval/validate.ts +1 -1
  99. package/.pi/lib/plan-approval-readiness.ts +32 -0
  100. package/.pi/lib/plan-debate-gate.ts +154 -114
  101. package/.pi/lib/plan-task-clarification.ts +158 -0
  102. package/.pi/prompts/harness-auto.md +2 -2
  103. package/.pi/prompts/harness-ls-lint-steward.md +43 -0
  104. package/.pi/prompts/harness-plan.md +58 -8
  105. package/.pi/prompts/harness-review.md +40 -6
  106. package/.pi/prompts/harness-run.md +33 -11
  107. package/.pi/prompts/harness-setup.md +72 -3
  108. package/.pi/prompts/harness-steer.md +2 -1
  109. package/.pi/prompts/wiki-save.md +5 -4
  110. package/.pi/scripts/README.md +8 -0
  111. package/.pi/scripts/generate-agents-policy-yaml.mjs +14 -2
  112. package/.pi/scripts/harness-auto-commit-bootstrap.mjs +96 -0
  113. package/.pi/scripts/harness-cli-verify.sh +47 -0
  114. package/.pi/scripts/harness-git-churn.mjs +77 -0
  115. package/.pi/scripts/harness-git-commit.mjs +173 -0
  116. package/.pi/scripts/harness-ls-lint-bootstrap.mjs +142 -0
  117. package/.pi/scripts/harness-ls-lint-cli.mjs +184 -0
  118. package/.pi/scripts/harness-seed-project-contracts.mjs +47 -0
  119. package/.pi/scripts/harness-sentrux-diagnostics.mjs +230 -0
  120. package/.pi/scripts/harness-sentrux-report.mjs +256 -0
  121. package/.pi/scripts/harness-verify.mjs +288 -125
  122. package/.pi/scripts/ls-lint-rules-sync.mjs +265 -0
  123. package/.pi/scripts/run-tests.mjs +1 -0
  124. package/.pi/settings.example.json +1 -0
  125. package/.sentrux/rules.toml +1 -1
  126. package/AGENTS.md +1 -0
  127. package/CHANGELOG.md +25 -0
  128. package/README.md +13 -4
  129. package/package.json +5 -1
  130. package/vendor/pi-vcc/src/hooks/before-compact.ts +86 -60
@@ -13,6 +13,7 @@ Read **harness-orchestration** and **harness-review** skills before spawning.
13
13
 
14
14
  ## Allowed subagents
15
15
 
16
+ - `harness/sentrux-repair-advisor` (Phase 1b — structural repair plan from OSS diagnostics; before benchmark evaluator)
16
17
  - `harness/reviewing/evaluator` (`mode: benchmark` then `mode: verdict`)
17
18
  - `harness/reviewing/adversary` (independent red team)
18
19
  - `harness/reviewing/tie-breaker` (escalation only when adversary blocks and eval was `conditional_pass`; skip when `--quick`)
@@ -53,15 +54,24 @@ Ownership: this command **auto-claims** the run for the current Pi session unles
53
54
  node "$UP_PKG/.pi/scripts/harness-verify.mjs"
54
55
  ```
55
56
 
56
- When `HARNESS_SENTRUX_REQUIRED=true`, after verify succeeds:
57
+ **Sentrux single-scan rule:** run capture **once** per review unless `artifacts/sentrux-report.json` is missing or `HARNESS_SENTRUX_RESCAN=1`.
58
+
59
+ When `HARNESS_SENTRUX_REQUIRED=true` (or report missing), after verify succeeds:
57
60
 
58
61
  ```bash
59
- node "$UP_PKG/.pi/scripts/harness-sentrux-cli.mjs" gate
62
+ node "$UP_PKG/.pi/scripts/harness-sentrux-report.mjs" --out "<run_dir>" --run-id "<run_id>" --signal
63
+ node "$UP_PKG/.pi/scripts/harness-sentrux-diagnostics.mjs" --report "<run_dir>/artifacts/sentrux-report.json" --out "<run_dir>" --churn
60
64
  ```
61
65
 
62
- Compare to baseline from `/harness-run` (`harness-sentrux-cli.mjs gate --save`). The wrapper resolves the project root before invoking Sentrux so `.sentrux/rules.toml` is found from run directories. If CLI missing, record `gate_status: not_installed`.
66
+ Otherwise read existing `artifacts/sentrux-report.json`, `artifacts/sentrux-diagnostics.json`, and `artifacts/sentrux-signal.yaml` from `/harness-run`. If CLI missing (127), record `gate_status: not_installed`. Append or refresh session entry `harness-sentrux-signal`.
67
+
68
+ When `HARNESS_LS_LINT_REQUIRED=true`:
69
+
70
+ ```bash
71
+ node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs" --json
72
+ ```
63
73
 
64
- Ensure `artifacts/sentrux-signal.yaml` exists under the run dir (written during `/harness-run`). If missing, write it from the latest `sentrux check` / `gate` output. Append or refresh session entry `harness-sentrux-signal`.
74
+ Ensure `artifacts/ls-lint-signal.yaml` exists (from `/harness-run` or write from CLI output). Append or refresh `harness-ls-lint-signal`.
65
75
 
66
76
  Run project tests if the approved `PlanPacket` or spawn context lists a test command. Capture stdout paths only — do not paste full logs into the next spawn.
67
77
 
@@ -72,10 +82,34 @@ schema_version: "1.0.0"
72
82
  harness_verify: pass|fail
73
83
  sentrux_check: pass|fail|skipped|not_installed
74
84
  sentrux_gate: pass|degraded|skipped|not_installed
85
+ ls_lint: pass|fail|skipped|not_installed
86
+ ls_lint_violations: 0
75
87
  notes: "…"
76
88
  ```
77
89
 
78
- `harness_artifact_ready({ paths: ["artifacts/benchmark-log.yaml", "artifacts/sentrux-signal.yaml"] })` when written.
90
+ `harness_artifact_ready({ paths: ["artifacts/benchmark-log.yaml", "artifacts/sentrux-report.json", "artifacts/sentrux-diagnostics.json", "artifacts/sentrux-signal.yaml", "artifacts/ls-lint-signal.yaml"] })` when written.
91
+
92
+ ## Phase 1b — Sentrux repair advisor (subagent)
93
+
94
+ **Practice:** Close the loop from fitness-function observation → bounded repair directives (ADR 0052). Skip when `artifacts/sentrux-repair-plan.yaml` already exists and `HARNESS_SENTRUX_RESCAN` is unset.
95
+
96
+ Spawn when **any**:
97
+
98
+ - `artifacts/sentrux-report.json` → `check.check_pass` is false, or
99
+ - `gate.status` is `degraded`, or
100
+ - `artifacts/sentrux-diagnostics.json` lists non-empty `diagnostics.complex_functions` or boundary/layer violations
101
+
102
+ ```
103
+ subagent({
104
+ agentScope: "both",
105
+ agent: "harness/sentrux-repair-advisor",
106
+ task: "<HarnessSpawnContext run_dir + plan_packet_path + paths: sentrux-report.json, sentrux-diagnostics.json, sentrux-signal.yaml — read only; emit repair plan>"
107
+ })
108
+ ```
109
+
110
+ Subagent calls **`submit_sentrux_repair_plan`** → `artifacts/sentrux-repair-plan.yaml`.
111
+
112
+ `harness_artifact_ready({ paths: ["artifacts/sentrux-repair-plan.yaml"] })` when written.
79
113
 
80
114
  ## Phase 2 — Measure actuals vs plan (benchmark evaluator)
81
115
 
@@ -85,7 +119,7 @@ notes: "…"
85
119
  subagent({
86
120
  agentScope: "both",
87
121
  agent: "harness/reviewing/evaluator",
88
- task: "<HarnessSpawnContext mode benchmark + plan_packet_path + run_dir + acceptance_checks + paths: benchmark-log.yaml, sentrux-signal.yaml — treat Sentrux fields as measured structural actuals, not executor goals>"
122
+ task: "<HarnessSpawnContext mode benchmark + plan_packet_path + run_dir + acceptance_checks + paths: benchmark-log.yaml, sentrux-signal.yaml, ls-lint-signal.yaml — treat Sentrux/ls-lint fields as measured structural actuals, not executor goals>"
89
123
  })
90
124
  ```
91
125
 
@@ -1,6 +1,5 @@
1
1
  ---
2
2
  description: Execute only against an approved PlanPacket with strict phase gates.
3
- argument-hint: ""
4
3
  ---
5
4
 
6
5
  # harness-run
@@ -38,6 +37,14 @@ The wrapper passes the resolved project root explicitly so Sentrux can find `.se
38
37
 
39
38
  Do **not** ask the executor to optimize Sentrux metrics — observation is for `/harness-review` only.
40
39
 
40
+ When `HARNESS_LS_LINT_REQUIRED=true`, record a pre-execute filename baseline:
41
+
42
+ ```bash
43
+ node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs" --json
44
+ ```
45
+
46
+ Note `violation_count` in run notes (do not block execute on pre-existing violations unless chair policy says otherwise).
47
+
41
48
  ## Orchestration — Single jelled implementer
42
49
 
43
50
  **Practice:** Peopleware — one accountable team owns delivery; generator–evaluator separation (executor does not self-certify).
@@ -58,29 +65,44 @@ subagent({ agentScope: "both", agent: "harness/running/executor", task: "<Harnes
58
65
 
59
66
  **Practice:** Monitoring actuals vs baseline — in-process fitness functions after generator work.
60
67
 
61
- After executor subprocess completes:
68
+ After executor subprocess completes, run **one** Sentrux capture (OSS CLI parse — no MCP/Pro):
69
+
70
+ ```bash
71
+ node "$UP_PKG/.pi/scripts/harness-sentrux-report.mjs" --out "<run_dir>" --run-id "<run_id>" --signal
72
+ node "$UP_PKG/.pi/scripts/harness-sentrux-diagnostics.mjs" --report "<run_dir>/artifacts/sentrux-report.json" --out "<run_dir>" --churn
73
+ ```
74
+
75
+ - If `sentrux-report.json` → `check.check_pass` is false or `gate.status` is `degraded` → set `execution_status: scope_drift` (or `blocked` if unrecoverable); parent runs **`/harness-review`** next (not immediate replan).
76
+ - `harness-sentrux-report.mjs --signal` writes `artifacts/sentrux-signal.yaml` (schema `1.1.0`) with `report_path`, `diagnostics_path`, `quality_signal`, `violation_count`, `degraded_reasons` when present.
77
+ - If `sentrux` is not installed (exit 127), record `gate_status: not_installed` via minimal `write_harness_yaml` and continue.
78
+
79
+ Append session custom entry `harness-sentrux-signal` mirroring the signal file (observation bus / telemetry).
80
+
81
+ `harness_artifact_ready({ paths: ["artifacts/sentrux-report.json", "artifacts/sentrux-diagnostics.json", "artifacts/sentrux-signal.yaml"] })` when written.
82
+
83
+ When `HARNESS_LS_LINT_REQUIRED=true`, after executor completes:
62
84
 
63
85
  ```bash
64
- node "$UP_PKG/.pi/scripts/harness-sentrux-cli.mjs" check
65
- node "$UP_PKG/.pi/scripts/harness-sentrux-cli.mjs" gate
86
+ node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs" --json
66
87
  ```
67
88
 
68
- - If `sentrux check` exits non-zero or `gate` reports degradation set `execution_status: scope_drift` (or `blocked` if unrecoverable); parent runs **`/harness-review`** next (not immediate replan).
69
- - Write `artifacts/sentrux-signal.yaml` via `write_harness_yaml`:
89
+ - If `lint_pass` is falseinclude in `validation_summary`; prefer `scope_drift` when new violations vs pre-run baseline.
90
+ - Write `artifacts/ls-lint-signal.yaml` via `write_harness_yaml`:
70
91
 
71
92
  ```yaml
72
93
  schema_version: "1.0.0"
73
94
  run_id: "<run_id>"
74
- check_pass: true|false
75
- gate_status: pass|degraded|skipped|not_installed
76
- quality_signal_summary: "<one line from CLI output>"
95
+ lint_pass: true|false
96
+ violation_count: 0
97
+ status: pass|fail|skipped|not_installed
98
+ quality_signal_summary: "<one line>"
77
99
  recorded_at: "<ISO8601>"
78
100
  phase: execute
79
101
  ```
80
102
 
81
- - Append session custom entry `harness-sentrux-signal` with the same fields (observation bus / telemetry).
103
+ - Append session custom entry `harness-ls-lint-signal` with the same fields.
82
104
 
83
- `harness_artifact_ready({ paths: ["artifacts/sentrux-signal.yaml"] })` when written.
105
+ `harness_artifact_ready({ paths: ["artifacts/ls-lint-signal.yaml"] })` when written.
84
106
 
85
107
  ## Parent rules
86
108
 
@@ -15,11 +15,12 @@ Bootstraps the complete ultimate-pi agentic harness: Graphify knowledge graph, C
15
15
  |---------|------------------|
16
16
  | `UP_PKG="$(pwd)"` in an **external** repo | Wrong — scripts live in the npm package. Resolve via `harness-resolve-up-pkg.mjs` (see Step 0). |
17
17
  | Re-running 2.1–2.8 manually after CLI verify | Wasteful — trust `harness-cli-verify.sh` output; only fix reported ✗ lines. |
18
- | Overwriting `AGENTS.md` after graphify | Graphify appends a section — **merge**, do not replace (Step 4.3). |
18
+ | Overwriting `AGENTS.md` after graphify | Graphify appends a section — **merge**, do not replace (Step 4.5). |
19
19
  | `sentrux-rules-sync` without project manifest | Use **`harness-sentrux-bootstrap.mjs`** (Step 4.2) — seeds manifest + idempotent rules sync. |
20
20
  | Re-running bootstrap with `--force` on unchanged manifest | Wasteful but safe — default bootstrap skips when hash unchanged; `--force` only after manifest edits. |
21
21
  | `graph.json` uses `links`, not `edges` | Step 6 stats: `g.get('edges', g.get('links', []))`. |
22
22
  | Guessing harness-web / `.env` defaults when `ask_user` is available | **Mandatory `ask_user`** at Step 4.0 unless `--non-interactive`. |
23
+ | WSL2 / SSH without WebView | Set `HARNESS_ASK_USER_UI=tui` in project `.env` (or rely on `auto` TUI fallback). Glimpse needs a display (WSLg or X11). |
23
24
  | `sudo apt-get` without passwordless sudo | Skip — report manual fix; do not block the rest of setup. |
24
25
  | `graphify codex install` | **Never run** — it writes `.codex/hooks.json`. Harness targets pi only (`graphify install --platform pi`). |
25
26
  | Overwriting `.env` | Use `harness-sync-env.mjs` — never rewrite; append missing keys only. |
@@ -155,7 +156,7 @@ bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh"
155
156
  # Reinstall everything: bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh" --force
156
157
  ```
157
158
 
158
- **Required (script must exit 0):** scrapling + harness-web smoke, ctx7, ast-grep (`sg`), sentrux (when harness manifest present).
159
+ **Required (script must exit 0):** scrapling + harness-web smoke, ctx7, ast-grep (`sg`), sentrux (when harness manifest present), ls-lint (when naming manifest present).
159
160
 
160
161
  **Warnings allowed:** biome (optional; skipped for non-JS/TS repos or if install fails), gh (if not authenticated), agent-browser (if OS libs need manual `sudo apt-get install`), cocoindex-code (empty corpus on tiny repos; first `[full]` install downloads local embedding model).
161
162
 
@@ -326,6 +327,12 @@ sentrux plugin add-standard 2>/dev/null || echo "Plugins already installed or fa
326
327
 
327
328
  **Rules.toml bootstrap runs in Step 4.2** (idempotent, merge-safe). Sentrux CLI workflows use the package **`sentrux`** skill (`.agents/skills/sentrux`); no symlink into `.pi/skills/` required.
328
329
 
330
+ ### 2.9 — ls-lint (Filename / Directory Naming)
331
+
332
+ Installed and smoke-tested by `harness-cli-verify.sh` (`npm install -g @ls-lint/ls-lint@2.3.1`).
333
+
334
+ **`.ls-lint.yml` bootstrap runs in Step 4.3** (idempotent, merge-safe). Use skill **`harness-ls-lint-setup`**; sync via `/harness-ls-lint-sync` in pi.
335
+
329
336
  ## Step 3 — Pi Extension Packages
330
337
 
331
338
  Bundled extensions load from the installed `ultimate-pi` package. The harness lens wrapper at `.pi/extensions/harness-lens.ts` loads `.pi/extensions/lib/harness-lens/` for edit autopatch, secrets blocking, deferred format, and LSP tools. Structural search uses shell `sg` (installed globally by setup); architecture gates use Sentrux. See [ADR 0045](.pi/harness/docs/adrs/0045-harness-lens-minimal-contract.md).
@@ -454,6 +461,18 @@ Rules:
454
461
  - Re-runs only add keys from `$UP_PKG/.pi/harness/env.harness.template` that are absent (managed block at EOF).
455
462
  - Ensure `.env` is gitignored (Step 4.1).
456
463
 
464
+ ### 4.0c — ask_user UI (optional)
465
+
466
+ Harness `ask_user` supports terminal (TUI), headless (CI), and Glimpse WebView (`HARNESS_ASK_USER_UI=auto|tui|glimpse|headless`). Dependencies install with `.pi/npm` during pi package install.
467
+
468
+ | Environment | Recommendation |
469
+ |-------------|----------------|
470
+ | **WSL2 without WSLg / no DISPLAY** | `HARNESS_ASK_USER_UI=tui` in `.env` (default `auto` already falls back) |
471
+ | **Desktop Linux / macOS / WSLg** | `auto` or `glimpse` for richer questionnaires |
472
+ | **CI / `--non-interactive`** | Prompts skipped; do not expect WebView |
473
+
474
+ Append `HARNESS_ASK_USER_UI=tui` to `.env` when WebView is unavailable. The first real `ask_user` reports `ui_backend` and `ui_degraded` in tool details. See ADR 0054.
475
+
457
476
  Template keys (placeholders — user fills secrets): `HARNESS_TELEMETRY_ENABLED`, `HARNESS_WEB_*`, `HARNESS_VCC_COMPACTION`, `HARNESS_VCC_DEBUG`, plus commented optional PostHog / Graphify vars.
458
477
 
459
478
  ### 4.1 — .gitignore Entries
@@ -484,6 +503,10 @@ Ensure `.gitignore` contains harness runtime entries (see repo root `.gitignore`
484
503
  .sentrux/*
485
504
  !.sentrux/
486
505
  !.sentrux/rules.toml
506
+
507
+ # ls-lint sync meta (.ls-lint.yml is committed)
508
+ .ls-lint/*
509
+ !.ls-lint/
487
510
  ```
488
511
 
489
512
  ### 4.2 — Sentrux rules bootstrap (required)
@@ -521,7 +544,52 @@ Set up structural regression baseline (optional):
521
544
  node "$UP_PKG/.pi/scripts/harness-sentrux-cli.mjs" gate --save 2>/dev/null || echo "Baseline will be saved on first gate run"
522
545
  ```
523
546
 
524
- ### 4.3 — Project AGENTS.md
547
+ ### 4.3 — ls-lint naming bootstrap (required)
548
+
549
+ **Skill:** invoke **harness-ls-lint-setup** before hand-editing `.ls-lint.yml` or `naming.manifest.json`.
550
+
551
+ From **project root**, run the bundled bootstrap (seeds manifest when missing, syncs `.ls-lint.yml` without clobbering custom YAML):
552
+
553
+ ```bash
554
+ node "$UP_PKG/.pi/scripts/harness-ls-lint-bootstrap.mjs"
555
+ # After editing naming.manifest.json:
556
+ node "$UP_PKG/.pi/scripts/harness-ls-lint-bootstrap.mjs" --force
557
+ # In pi: /harness-ls-lint-sync (always --force sync)
558
+ ```
559
+
560
+ | Command | When |
561
+ |---------|------|
562
+ | `harness-ls-lint-bootstrap.mjs` (no flags) | `/harness-setup`, first install, re-run safe |
563
+ | `harness-ls-lint-bootstrap.mjs --force` | Manifest rules/ignores changed |
564
+ | `ls-lint-rules-sync.mjs --check` | CI / harness-verify drift only |
565
+ | `harness-ls-lint-cli.mjs` | Root-resolving filename checks from harness run dirs |
566
+ | `/harness-ls-lint-sync` | Interactive re-sync from pi |
567
+
568
+ Verify naming:
569
+
570
+ ```bash
571
+ node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs" && echo "✓ ls-lint pass" || echo "✗ ls-lint failed"
572
+ ```
573
+
574
+ ### 4.4 — Auto-commit co-author bootstrap (required)
575
+
576
+ **Skill:** invoke **harness-git-commit** before any agent commit.
577
+
578
+ From **project root**:
579
+
580
+ ```bash
581
+ node "$UP_PKG/.pi/scripts/harness-auto-commit-bootstrap.mjs"
582
+ ```
583
+
584
+ | Command | When |
585
+ |---------|------|
586
+ | `harness-auto-commit-bootstrap.mjs` | `/harness-setup`, first install, re-run safe |
587
+ | `harness-git-commit.mjs --dry-run --subject "…"` | Preview message + trailer |
588
+ | `harness-git-commit.mjs --type … --scope … --subject "…"` | Commit after `git add` |
589
+
590
+ Edit `.pi/auto-commit.json` to customize `message.template` or `coAuthor` (project overrides package defaults).
591
+
592
+ ### 4.5 — Project AGENTS.md
525
593
 
526
594
  **Do not overwrite** an existing `AGENTS.md` — graphify bootstrap may have appended a `## Graphify` section. If missing, create minimal onboarding content; if present, only add harness subsections that are absent.
527
595
 
@@ -652,6 +720,7 @@ Output summary table:
652
720
  | ast-grep | ✓/✗ | AST-aware code search (`sg`)
653
721
  | gh CLI | ✓/✗ | Auth: yes/no |
654
722
  | sentrux | ✓/✗ | CLI + plugins; rules via Step 4.2 bootstrap |
723
+ | ls-lint | ✓/✗ | CLI; `.ls-lint.yml` via Step 4.3 bootstrap |
655
724
  | Sentrux rules.toml | ✓/✗ | `.sentrux/rules.toml` synced from manifest |
656
725
  | pi extensions | ✓/✗ | bundled extensions + harness lens wrapper |
657
726
  | harness lens | ✓/✗ | `.pi/extensions/harness-lens.ts`; PostHog owns lens telemetry; complements Sentrux architecture signal |
@@ -15,12 +15,13 @@ Thin orchestrator for the **steer loop** (ADR 0044). Run only after `/harness-re
15
15
 
16
16
  ## Steps
17
17
 
18
- 1. Read `artifacts/review-outcome.yaml`, `artifacts/repair-brief.yaml`, `plan_packet_path` (paths only — do not paste bodies into tool args).
18
+ 1. Read `artifacts/review-outcome.yaml`, `artifacts/repair-brief.yaml`, `plan_packet_path` (paths only — do not paste bodies into tool args). When present, `repair-brief.yaml` already merges `artifacts/sentrux-repair-plan.yaml` (`[sentrux:…]` directives).
19
19
  2. Update `artifacts/steer-state.yaml` (`attempt`, `max_attempts`, `active: true`).
20
20
  3. Set policy phase to **execute** before spawning executor (required for mutating tools).
21
21
  4. One `ask_user` steer gate unless `run-context.steer_approved` is already true.
22
22
  5. Spawn **`harness/running/executor`** with `HarnessSpawnContext.mode: repair` and `repair_brief_path: artifacts/repair-brief.yaml`. Repair uses the same hash-anchored `read`/`edit`, batching, and pre-handoff verification rules as `/harness-run` (ADR 0051).
23
23
  6. Optional: `node "$UP_PKG/.pi/scripts/harness-sentrux-cli.mjs" gate --save` after repair to refresh baseline (ADR 0044).
24
+ 7. Optional: `node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs"` after repair to confirm filename conventions (ADR 0052).
24
25
  7. `next_command`: **`/harness-review`** (always re-verify; tiered adversary on attempts 2+ per practice-map).
25
26
 
26
27
  ## Forbidden
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: Save the current conversation or a specific insight as a structured note in the knowledge graph.
3
+ argument-hint: "[name|session|decision <name>]"
3
4
  ---
4
5
 
5
6
  Read the `graphify` skill for context on graphify-out/ structure.
@@ -9,10 +10,10 @@ so it can be graphified and queried. Then run `graphify ./raw --update` to
9
10
  incorporate it into the knowledge graph.
10
11
 
11
12
  Usage:
12
- - `/save` — analyze the full conversation and save the most valuable content
13
- - `/save [name]` — save with a specific note title
14
- - `/save session` — save a complete session summary
15
- - `/save decision [name]` — save as a design/governance decision (also mirror into `.pi/harness/incidents/` when incident tracking is required)
13
+ - `/wiki-save` — analyze the full conversation and save the most valuable content
14
+ - `/wiki-save [name]` — save with a specific note title
15
+ - `/wiki-save session` — save a complete session summary
16
+ - `/wiki-save decision [name]` — save as a design/governance decision (also mirror into `.pi/harness/incidents/` when incident tracking is required)
16
17
 
17
18
  Save to: `./raw/[sanitized-name].md`
18
19
  Then: `graphify ./raw --update`
@@ -28,7 +28,15 @@ From **Typescript extensions**, use `resolveHarnessScript()` / `getHarnessPackag
28
28
  | Sentrux rules re-sync after manifest edit | `node "$UP_PKG/.pi/scripts/harness-sentrux-bootstrap.mjs" --force` or `/harness-sentrux-sync` |
29
29
  | Sentrux rules drift check (CI) | `node "$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs" --check` |
30
30
  | Sentrux run/review check or gate (root-resolving) | `node "$UP_PKG/.pi/scripts/harness-sentrux-cli.mjs" check` / `gate [--save]` |
31
+ | Sentrux single-scan report + signal (ADR 0052) | `node "$UP_PKG/.pi/scripts/harness-sentrux-report.mjs" --out <run_dir> --run-id <id> --signal` |
32
+ | Sentrux diagnostics synthesis | `node "$UP_PKG/.pi/scripts/harness-sentrux-diagnostics.mjs" --report <run_dir>/artifacts/sentrux-report.json --out <run_dir> [--churn]` |
33
+ | ls-lint naming bootstrap (harness-setup) | `node "$UP_PKG/.pi/scripts/harness-ls-lint-bootstrap.mjs"` |
34
+ | ls-lint naming re-sync after manifest edit | `node "$UP_PKG/.pi/scripts/harness-ls-lint-bootstrap.mjs" --force` or `/harness-ls-lint-sync` |
35
+ | ls-lint config drift check (CI) | `node "$UP_PKG/.pi/scripts/ls-lint-rules-sync.mjs" --check` |
36
+ | ls-lint filename check (root-resolving) | `node "$UP_PKG/.pi/scripts/harness-ls-lint-cli.mjs` [`--json`] |
31
37
  | Resolve package root (`UP_PKG`) | `node "$UP_PKG/.pi/scripts/harness-resolve-up-pkg.mjs"` |
38
+ | Auto-commit config bootstrap | `node "$UP_PKG/.pi/scripts/harness-auto-commit-bootstrap.mjs"` |
39
+ | Git commit + co-author trailer | `node "$UP_PKG/.pi/scripts/harness-git-commit.mjs" --subject "…"` [`--dry-run`] |
32
40
  | Project `.env` (append-only) | `node "$UP_PKG/.pi/scripts/harness-sync-env.mjs"` (`--create-missing` after user confirms) |
33
41
  | Harness lens extension | `.pi/extensions/harness-lens.ts` → `.pi/lib/harness-lens/index.ts` (loaded by `.pi/extensions`; PostHog owns lens telemetry) |
34
42
 
@@ -32,6 +32,8 @@ const SUBMIT_BY_AGENT = {
32
32
  "harness/trace-librarian": ["submit_human_required"],
33
33
  "harness/incident-recorder": ["submit_human_required"],
34
34
  "harness/sentrux-steward": ["submit_sentrux_manifest_proposal"],
35
+ "harness/sentrux-repair-advisor": ["submit_sentrux_repair_plan"],
36
+ "harness/ls-lint-steward": ["submit_ls_lint_manifest_proposal"],
35
37
  };
36
38
 
37
39
  function parseFrontmatter(content) {
@@ -48,7 +50,12 @@ function kindFor(id) {
48
50
  if (id === "harness/reviewing/tie-breaker") return "tie_breaker";
49
51
  if (id === "harness/trace-librarian") return "trace";
50
52
  if (id === "harness/incident-recorder") return "incident";
51
- if (id === "harness/sentrux-steward" || id === "harness/sentrux-bootstrap")
53
+ if (id === "harness/sentrux-repair-advisor") return "evaluator";
54
+ if (
55
+ id === "harness/sentrux-steward" ||
56
+ id === "harness/sentrux-bootstrap" ||
57
+ id === "harness/ls-lint-steward"
58
+ )
52
59
  return "planner";
53
60
  return "other";
54
61
  }
@@ -79,7 +86,12 @@ async function main() {
79
86
 
80
87
  const kinds = {
81
88
  planner: { tools: KIND_BASE.planner, extensions: false, read_only: true },
82
- executor: { tools: KIND_BASE.executor, extensions: true, read_only: false },
89
+ executor: {
90
+ tools: KIND_BASE.executor,
91
+ extensions: true,
92
+ extension_bundle: "executor",
93
+ read_only: false,
94
+ },
83
95
  evaluator: { tools: KIND_BASE.evaluator, extensions: false, read_only: true },
84
96
  adversary: { tools: KIND_BASE.adversary, extensions: false, read_only: true },
85
97
  tie_breaker: {
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Idempotent auto-commit config bootstrap for harness projects.
4
+ *
5
+ * Seeds PROJECT/.pi/auto-commit.json from the ultimate-pi package template when missing.
6
+ *
7
+ * Usage:
8
+ * node "$UP_PKG/.pi/scripts/harness-auto-commit-bootstrap.mjs" [PROJECT_ROOT] [--check]
9
+ */
10
+
11
+ import { readFile, writeFile, mkdir, access, copyFile } from "node:fs/promises";
12
+ import { constants } from "node:fs";
13
+ import { join, dirname, basename } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ import { validateAutoCommitConfig } from "../lib/harness-auto-commit-config.mjs";
16
+
17
+ const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
18
+ const UP_PKG = join(SCRIPT_DIR, "..", "..");
19
+
20
+ const args = process.argv.slice(2).filter((a) => !a.startsWith("-"));
21
+ const checkOnly = process.argv.includes("--check");
22
+ const PROJECT_ROOT = args[0] || process.cwd();
23
+ const CONFIG_PATH = join(PROJECT_ROOT, ".pi", "auto-commit.json");
24
+ const TEMPLATE_PATH = join(UP_PKG, ".pi", "auto-commit.json");
25
+
26
+ async function fileExists(path) {
27
+ try {
28
+ await access(path, constants.R_OK);
29
+ return true;
30
+ } catch {
31
+ return false;
32
+ }
33
+ }
34
+
35
+ async function resolveScopeDefault(root) {
36
+ const pkgPath = join(root, "package.json");
37
+ if (await fileExists(pkgPath)) {
38
+ try {
39
+ const pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
40
+ if (typeof pkg.name === "string" && pkg.name.trim()) {
41
+ return pkg.name.trim().replace(/^@/, "").split("/").pop() ?? pkg.name;
42
+ }
43
+ } catch {
44
+ /* ignore */
45
+ }
46
+ }
47
+ return basename(root) || "project";
48
+ }
49
+
50
+ async function main() {
51
+ if (!(await fileExists(TEMPLATE_PATH))) {
52
+ console.error(
53
+ "harness-auto-commit-bootstrap: missing package template",
54
+ TEMPLATE_PATH,
55
+ );
56
+ process.exit(1);
57
+ }
58
+
59
+ if (await fileExists(CONFIG_PATH)) {
60
+ if (checkOnly) {
61
+ const config = JSON.parse(await readFile(CONFIG_PATH, "utf-8"));
62
+ validateAutoCommitConfig(config);
63
+ console.log(`harness-auto-commit-bootstrap: ok ${CONFIG_PATH}`);
64
+ return;
65
+ }
66
+ console.log(
67
+ "harness-auto-commit-bootstrap: config present (edit .pi/auto-commit.json to customize)",
68
+ );
69
+ return;
70
+ }
71
+
72
+ if (checkOnly) {
73
+ console.error(
74
+ `harness-auto-commit-bootstrap: missing ${CONFIG_PATH} (run without --check to seed)`,
75
+ );
76
+ process.exit(1);
77
+ }
78
+
79
+ await mkdir(dirname(CONFIG_PATH), { recursive: true });
80
+ await copyFile(TEMPLATE_PATH, CONFIG_PATH);
81
+ const config = JSON.parse(await readFile(CONFIG_PATH, "utf-8"));
82
+ const scope = await resolveScopeDefault(PROJECT_ROOT);
83
+ if (config.message && typeof config.message === "object") {
84
+ config.message.scopeDefault = scope;
85
+ }
86
+ validateAutoCommitConfig(config);
87
+ await writeFile(CONFIG_PATH, `${JSON.stringify(config, null, "\t")}\n`, "utf-8");
88
+ console.log(
89
+ `harness-auto-commit-bootstrap: seeded -> ${CONFIG_PATH} (message.scopeDefault: ${scope})`,
90
+ );
91
+ }
92
+
93
+ main().catch((err) => {
94
+ console.error(err);
95
+ process.exit(1);
96
+ });
@@ -324,6 +324,37 @@ verify_gh() {
324
324
  fi
325
325
  }
326
326
 
327
+ verify_ls_lint() {
328
+ log "[ls-lint]"
329
+ npm_global_install "@ls-lint/ls-lint@2.3.1" "ls-lint" || {
330
+ fail "ls-lint npm install"
331
+ return
332
+ }
333
+ if ! ls-lint --version &>/dev/null; then
334
+ fail "ls-lint --version failed"
335
+ return
336
+ fi
337
+ _bootstrap="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)/harness-ls-lint-bootstrap.mjs"
338
+ if [ -f "$_bootstrap" ]; then
339
+ node "$_bootstrap" --force 2>/dev/null ||
340
+ warn "ls-lint bootstrap failed (see harness-ls-lint-setup skill)"
341
+ fi
342
+ _cli="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)/harness-ls-lint-cli.mjs"
343
+ if [ -f "$_cli" ]; then
344
+ if node "$_cli" 2>/dev/null; then
345
+ pass "ls-lint $(ls-lint --version 2>/dev/null | head -1)"
346
+ else
347
+ fail "ls-lint filename check failed (fix violations or tune naming.manifest.json)"
348
+ fi
349
+ else
350
+ if ls-lint 2>/dev/null; then
351
+ pass "ls-lint $(ls-lint --version 2>/dev/null | head -1)"
352
+ else
353
+ fail "ls-lint check failed"
354
+ fi
355
+ fi
356
+ }
357
+
327
358
  verify_sentrux() {
328
359
  log "[sentrux]"
329
360
  if ! have_cmd sentrux || [ "$FORCE" = true ]; then
@@ -361,7 +392,23 @@ verify_cocoindex
361
392
  verify_biome
362
393
  verify_sg
363
394
  verify_gh
395
+ verify_auto_commit() {
396
+ log "[auto-commit]"
397
+ _git_commit="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)/harness-git-commit.mjs"
398
+ if [ ! -f "$_git_commit" ]; then
399
+ warn "harness-git-commit.mjs missing (package incomplete)"
400
+ return
401
+ fi
402
+ if node "$_git_commit" --print-message --subject "harness-cli-verify" 2>/dev/null | grep -qi 'Co-authored-by:'; then
403
+ pass "harness-git-commit (co-author trailer)"
404
+ else
405
+ fail "harness-git-commit --print-message missing Co-authored-by trailer"
406
+ fi
407
+ }
408
+
364
409
  verify_sentrux
410
+ verify_ls_lint
411
+ verify_auto_commit
365
412
 
366
413
  log ""
367
414
  if [ "$FAILURES" -gt 0 ]; then
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Optional git churn map (path → commit count) for Sentrux hotspot scoring.
4
+ *
5
+ * Usage:
6
+ * node harness-git-churn.mjs [--root <PROJECT_ROOT>] [--days 14]
7
+ */
8
+
9
+ import { spawn } from "node:child_process";
10
+ import { resolveSentruxProjectRoot, takeRootArg } from "../lib/harness-sentrux-root.mjs";
11
+
12
+ function runGit(args, cwd) {
13
+ return new Promise((resolve, reject) => {
14
+ const child = spawn("git", args, { cwd, env: process.env });
15
+ let stdout = "";
16
+ let stderr = "";
17
+ child.stdout?.on("data", (c) => {
18
+ stdout += c.toString();
19
+ });
20
+ child.stderr?.on("data", (c) => {
21
+ stderr += c.toString();
22
+ });
23
+ child.on("error", reject);
24
+ child.on("close", (code) => {
25
+ if (code !== 0) {
26
+ reject(new Error(stderr.trim() || `git exit ${code}`));
27
+ return;
28
+ }
29
+ resolve(stdout);
30
+ });
31
+ });
32
+ }
33
+
34
+ /**
35
+ * @param {string} projectRoot
36
+ * @param {{ days?: number }} opts
37
+ * @returns {Promise<Record<string, number>>}
38
+ */
39
+ export async function loadGitChurn(projectRoot, opts = {}) {
40
+ const days = opts.days ?? 14;
41
+ const since = `${days} days ago`;
42
+ const stdout = await runGit(
43
+ [
44
+ "log",
45
+ `--since=${since}`,
46
+ "--name-only",
47
+ "--pretty=format:",
48
+ ],
49
+ projectRoot,
50
+ );
51
+ const counts = {};
52
+ for (const line of stdout.split(/\r?\n/)) {
53
+ const path = line.trim();
54
+ if (!path || path.startsWith(".")) continue;
55
+ counts[path] = (counts[path] || 0) + 1;
56
+ }
57
+ return counts;
58
+ }
59
+
60
+ async function main() {
61
+ const { args, explicitRoot } = takeRootArg(process.argv.slice(2));
62
+ let days = 14;
63
+ for (let i = 0; i < args.length; i++) {
64
+ if (args[i] === "--days") days = Number.parseInt(args[++i] || "14", 10);
65
+ }
66
+ const root = await resolveSentruxProjectRoot(explicitRoot);
67
+ const map = await loadGitChurn(root, { days });
68
+ process.stdout.write(`${JSON.stringify(map, null, 2)}\n`);
69
+ }
70
+
71
+ const isMain = process.argv[1]?.endsWith("harness-git-churn.mjs");
72
+ if (isMain) {
73
+ main().catch((err) => {
74
+ console.error(err.message || err);
75
+ process.exit(1);
76
+ });
77
+ }