ultimate-pi 0.5.0 → 0.6.1

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.
@@ -40,7 +40,7 @@ Custom TOML **outside** `# --- harness:managed:start/end ---` is preserved on ev
40
40
  node "$UP_PKG/.pi/scripts/harness-sentrux-bootstrap.mjs"
41
41
  ```
42
42
  3. Optional: `sentrux plugin add-standard` (language plugins; harness-setup Step 2.8).
43
- 4. Merge sentrux MCP into `.pi/mcp.json` if missing (harness-setup Step 4.2).
43
+ 4. Symlink **sentrux** skill into `.pi/skills/` if missing (see harness-setup Step 4.2).
44
44
  5. `sentrux check .` — fix violations or tune manifest `max_cc` / layers.
45
45
  6. Commit `.sentrux/rules.toml` and project-specific `architecture.manifest.json`.
46
46
 
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: sentrux
3
+ description: |
4
+ Architectural quality sensor for AI-assisted code — rules, modularity, session baselines,
5
+ and degradation detection via the Sentrux CLI (not MCP in Pi sessions).
6
+ Use when the user mentions sentrux, quality signal, architectural health, gate, check rules,
7
+ modularity, session baseline, degradation, structural drift, or before/after agent work on
8
+ a harness project. Triggers on: sentrux check, sentrux gate, rules.toml, quality gate.
9
+ ---
10
+
11
+ # sentrux (CLI + harness)
12
+
13
+ [Sentrux](https://github.com/sentrux/sentrux) scans project structure, enforces `.sentrux/rules.toml`, and compares sessions with **gate** baselines. In **Pi**, use the **`sentrux` binary and bash** — Pi does **not** load `.pi/mcp.json`, so Sentrux MCP tools are unavailable in Pi agent sessions.
14
+
15
+ ## Install (once per machine)
16
+
17
+ | Platform | Command |
18
+ |----------|---------|
19
+ | macOS | `brew install sentrux/tap/sentrux` |
20
+ | Linux | `curl -fsSL https://raw.githubusercontent.com/sentrux/sentrux/main/install.sh \| sh` |
21
+
22
+ Verify:
23
+
24
+ ```bash
25
+ command -v sentrux && sentrux --version
26
+ ```
27
+
28
+ Harness setup also checks via `bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh"` (resolve `UP_PKG` in `.pi/scripts/README.md`).
29
+
30
+ Optional language plugins (52 tree-sitter parsers):
31
+
32
+ ```bash
33
+ sentrux plugin add-standard
34
+ ```
35
+
36
+ ## Core workflows (project root)
37
+
38
+ Run from the **target repo root** (where `.sentrux/rules.toml` lives).
39
+
40
+ | When | Command | Notes |
41
+ |------|---------|-------|
42
+ | CI / pre-commit | `sentrux check .` | Exit 0 = pass, 1 = violations |
43
+ | Before agent work | `sentrux gate --save .` | Save session baseline |
44
+ | After agent work | `sentrux gate .` | Detect degradation vs baseline |
45
+ | Explore structure | `sentrux` or `sentrux .` | GUI treemap (optional) |
46
+
47
+ Typical agent loop:
48
+
49
+ ```bash
50
+ sentrux gate --save .
51
+ # … agent edits …
52
+ sentrux check . # rules still pass?
53
+ sentrux gate . # structural regression?
54
+ ```
55
+
56
+ If `check` fails, fix violations or tune manifest constraints (see **Rules** below). If `gate` reports degradation, inspect changed modules before merging.
57
+
58
+ ## Rules (`.sentrux/rules.toml`)
59
+
60
+ Committed rules file at repo root. Harness projects sync it from `.pi/harness/sentrux/architecture.manifest.json`.
61
+
62
+ | Task | Skill / command |
63
+ |------|-----------------|
64
+ | First bootstrap, manifest → rules | **harness-sentrux-setup** — `node "$UP_PKG/.pi/scripts/harness-sentrux-bootstrap.mjs"` |
65
+ | Manifest edited | bootstrap `--force` or `/harness-sentrux-sync` |
66
+ | CI drift only | `node "$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs" --check` |
67
+
68
+ Custom TOML outside `# --- harness:managed:start/end ---` is preserved on sync. Do **not** hand-edit managed blocks without updating the manifest.
69
+
70
+ ## Harness integration
71
+
72
+ | Piece | Role |
73
+ |-------|------|
74
+ | `sentrux-rules-sync` extension | Session start: warns if `rules.toml` drifts; auto-sync after plan/merge phases |
75
+ | `/harness-sentrux-sync` | Force-regenerate rules from manifest (pi command) |
76
+ | `harness-verify.mjs` | Runs `sentrux check .` when rules present |
77
+ | **observation-bus** | Maps `harness-sentrux-signal` custom entries → evaluator observations |
78
+ | **harness-eval** | Evaluate phase may require a Sentrux quality signal (stub or future MCP) per ADR 0006 |
79
+
80
+ High level: **execute** uses CLI gate/check around edits; **evaluate** consumes observation-bus quality signals (`harness-sentrux-signal`) alongside tests and policy. Record CLI outcomes in session notes when no bus entry exists yet.
81
+
82
+ ## Related skills
83
+
84
+ - **harness-sentrux-setup** — manifest seeding, rules bootstrap, sync semantics (do not duplicate here)
85
+ - **harness-eval** — verdict + Sentrux signal requirements
86
+ - **harness-governor** — when to re-sync after architecture changes
87
+
88
+ ## Do not
89
+
90
+ - Assume Sentrux **MCP** tools (`scan`, `session_start`, `health`, etc.) exist in **Pi** — they do not; use CLI only
91
+ - Edit or rely on `.pi/mcp.json` for Pi sessions
92
+ - Duplicate bootstrap/sync steps from **harness-sentrux-setup**
93
+ - Skip `sentrux check .` after large refactors when `.sentrux/rules.toml` exists
94
+
95
+ ## References
96
+
97
+ - ADR 0006 — `.pi/harness/docs/adrs/0006-sentrux-dual-layer.md`
98
+ - ADR 0009 — `.pi/harness/docs/adrs/0009-sentrux-rules-lifecycle.md`
99
+ - `CONTRIBUTING.md` — Sentrux quick start
@@ -1,30 +1,44 @@
1
1
  # ultimate-pi harness — local secrets and paths (gitignored .env)
2
- # Fill in values below; re-run /harness-setup to add newly introduced keys only.
2
+ # Created by /harness-setup (harness-sync-env.mjs). Re-run setup to append newly introduced keys only.
3
3
 
4
- # Telemetry (set false to disable harness PostHog events)
4
+ # --- Telemetry ---
5
+ # Harness domain events (harness-telemetry.ts); set false to disable harness_* only
5
6
  HARNESS_TELEMETRY_ENABLED=true
6
7
 
7
- # harness-web (Scrapling scrape + pluggable search)
8
+ # --- harness-web (Scrapling scrape + pluggable search) ---
8
9
  HARNESS_WEB_FETCH_MODE=stealth
9
10
  HARNESS_WEB_SEARCH_ENGINE=ddg_html
10
- # SearXNG (when HARNESS_WEB_SEARCH_ENGINE=searxng):
11
+ # When HARNESS_WEB_SEARCH_ENGINE=searxng (bootstrap via harness-searxng-bootstrap.mjs):
11
12
  # HARNESS_WEB_SEARXNG_URL=http://127.0.0.1:8080
12
13
  # HARNESS_WEB_PROXY=
13
14
  # HARNESS_WEB_RATE_LIMIT_MS=2000
14
15
  # HARNESS_WEB_TIMEOUT_MS=30000
15
16
 
16
- # PostHog (optional)
17
+ # --- VCC compaction (env-only; no JSON config files) ---
18
+ # Default: VCC handles /compact and auto-compaction. Set false for Pi LLM compaction:
19
+ # HARNESS_VCC_COMPACTION=false
20
+ # HARNESS_VCC_DEBUG=true
21
+
22
+ # --- PostHog (optional) ---
23
+ # Project key — required for harness_* telemetry when HARNESS_TELEMETRY_ENABLED=true
17
24
  # POSTHOG_API_KEY=
25
+ # POSTHOG_HOST=https://us.i.posthog.com
26
+ # POSTHOG_ENABLED=true
18
27
  # POSTHOG_PROJECT_NAME=ultimate-pi
19
28
  # POSTHOG_PRIVACY_MODE=false
29
+ # Personal API key — PostHog MCP / posthog-analyst skill only
30
+ # POSTHOG_PERSONAL_API_KEY=
31
+ # POSTHOG_MCP_FEATURES=llm_analytics
20
32
 
21
- # Graphify semantic extract (optional; `graphify update .` needs no key)
33
+ # --- Graphify semantic extract (optional; `graphify update .` needs no key) ---
22
34
  # GEMINI_API_KEY=
23
35
  # GOOGLE_API_KEY=
24
36
  # OPENAI_API_KEY=
37
+ # OPENAI_API_BASE=
25
38
 
26
- # Pi VCC compaction config path (project-relative)
27
- PI_VCC_CONFIG_PATH=.pi/pi-vcc-config.json
39
+ # --- Wiki / Obsidian vault (optional) ---
40
+ VAULT_WIKI_PATH=vault/wiki
28
41
 
29
- # Wiki / vault (optional — Obsidian layer)
30
- # VAULT_WIKI_PATH=vault/wiki
42
+ # --- Sentrux gate (optional) ---
43
+ # Require Sentrux stub for harness-verify (see .pi/scripts/harness-verify.mjs)
44
+ # HARNESS_SENTRUX_REQUIRED=true
@@ -306,7 +306,7 @@ if gh auth status &>/dev/null; then
306
306
  fi
307
307
  ```
308
308
 
309
- ### 2.8 — sentrux (Architectural Quality Gate + MCP Sensor)
309
+ ### 2.8 — sentrux (Architectural Quality Gate)
310
310
 
311
311
  ```bash
312
312
  if ! command -v sentrux &>/dev/null || [ "$FORCE" = "true" ]; then
@@ -319,7 +319,7 @@ Install all 52 language plugins:
319
319
  sentrux plugin add-standard 2>/dev/null || echo "Plugins already installed or failed"
320
320
  ```
321
321
 
322
- Configure MCP server in `.pi/mcp.json` (see Step 4.2). **Rules.toml bootstrap runs in Step 4.3** (idempotent, merge-safe).
322
+ Ensure the **sentrux** Pi skill is linked (see Step 4.2). **Rules.toml bootstrap runs in Step 4.3** (idempotent, merge-safe).
323
323
 
324
324
  ## Step 3 — Pi Extension Packages
325
325
 
@@ -496,28 +496,27 @@ Ensure `.gitignore` contains:
496
496
  !.sentrux/rules.toml
497
497
  ```
498
498
 
499
- ### 4.2 — MCP Server Configuration
499
+ ### 4.2 — Sentrux Pi skill
500
500
 
501
- Add sentrux MCP server to `.pi/mcp.json`:
502
- ```json
503
- {
504
- "mcpServers": {
505
- "context-mode": {
506
- "command": "context-mode"
507
- },
508
- "sentrux": {
509
- "command": "sentrux",
510
- "args": ["--mcp"]
511
- }
512
- }
513
- }
501
+ Pi does **not** load `.pi/mcp.json`. Agents use Sentrux via the **CLI** and the **`sentrux`** skill.
502
+
503
+ From **project root**, ensure the skill is discoverable (idempotent):
504
+
505
+ ```bash
506
+ UP_PKG="$(node -p "require('path').dirname(require.resolve('ultimate-pi/package.json'))")"
507
+ SKILL_SRC="$UP_PKG/.agents/skills/sentrux"
508
+ SKILL_DST=".pi/skills/sentrux"
509
+ if [ -d "$SKILL_SRC" ] && [ ! -e "$SKILL_DST" ]; then
510
+ ln -s "../../.agents/skills/sentrux" "$SKILL_DST"
511
+ echo "✓ linked $SKILL_DST → sentrux skill"
512
+ elif [ -e "$SKILL_DST" ]; then
513
+ echo "✓ sentrux skill already present at $SKILL_DST"
514
+ else
515
+ echo "✗ missing $SKILL_SRC — reinstall ultimate-pi"
516
+ fi
514
517
  ```
515
518
 
516
- This gives agents real-time access to structural health metrics:
517
- - `scan` — quality signal, file count, bottleneck detection
518
- - `session_start` / `session_end` — baseline comparison, degradation detection
519
- - `check_rules` — architectural constraint enforcement
520
- - `health`, `rescan`, `evolution`, `dsm`, `test_gaps`
519
+ After `/reload`, agents can invoke **`/skill:sentrux`** for install paths, `sentrux check`, `sentrux gate --save` / `sentrux gate`, and harness integration. **context-mode** remains a separate `npm:context-mode` package in `.pi/settings.json` (its own MCP bridge inside that extension).
521
520
 
522
521
  ### 4.3 — Sentrux rules bootstrap (required)
523
522
 
@@ -21,6 +21,7 @@ import {
21
21
  readFile,
22
22
  writeFile,
23
23
  } from "node:fs/promises";
24
+ import { randomBytes } from "node:crypto";
24
25
  import { constants } from "node:fs";
25
26
  import { join, dirname } from "node:path";
26
27
  import { fileURLToPath } from "node:url";
@@ -50,7 +51,10 @@ const SETTINGS_PATH = join(CORE_CONFIG, "settings.yml");
50
51
  const COMPOSE_PATH = join(SEARXNG_DIR, "docker-compose.yml");
51
52
  const ENV_COMPOSE = join(SEARXNG_DIR, ".env");
52
53
 
53
- const HARNESS_SETTINGS = `use_default_settings: true
54
+ const DEFAULT_SECRET = "ultrasecretkey";
55
+
56
+ function buildHarnessSettings(secret) {
57
+ return `use_default_settings: true
54
58
 
55
59
  search:
56
60
  formats:
@@ -58,9 +62,11 @@ search:
58
62
  - json
59
63
 
60
64
  server:
65
+ secret_key: "${secret}"
61
66
  limiter: false
62
67
  public_instance: false
63
68
  `;
69
+ }
64
70
 
65
71
  async function exists(path) {
66
72
  try {
@@ -138,6 +144,69 @@ async function readComposePort() {
138
144
  return DEFAULT_PORT;
139
145
  }
140
146
 
147
+ function parseEnvValue(raw) {
148
+ return raw.trim().replace(/^["']|["']$/g, "");
149
+ }
150
+
151
+ async function readComposeSecret() {
152
+ if (!(await exists(ENV_COMPOSE))) return null;
153
+ const text = await readFile(ENV_COMPOSE, "utf8");
154
+ for (const line of text.split("\n")) {
155
+ const m = line.match(/^SEARXNG_SECRET=(.+)$/);
156
+ if (m) {
157
+ const val = parseEnvValue(m[1]);
158
+ if (val && val !== DEFAULT_SECRET) return val;
159
+ }
160
+ }
161
+ return null;
162
+ }
163
+
164
+ async function readSettingsSecret() {
165
+ if (!(await exists(SETTINGS_PATH))) return null;
166
+ const text = await readFile(SETTINGS_PATH, "utf8");
167
+ const m = text.match(/^\s*secret_key:\s*["']?([^"'\n#]+)["']?\s*$/m);
168
+ if (!m) return null;
169
+ const val = m[1].trim();
170
+ return val && val !== DEFAULT_SECRET ? val : null;
171
+ }
172
+
173
+ function generateSecret() {
174
+ return randomBytes(32).toString("hex");
175
+ }
176
+
177
+ async function getOrCreateSecret() {
178
+ return (
179
+ (await readComposeSecret()) ||
180
+ (await readSettingsSecret()) ||
181
+ generateSecret()
182
+ );
183
+ }
184
+
185
+ async function upsertComposeSecret(secret) {
186
+ let content = "";
187
+ if (await exists(ENV_COMPOSE)) {
188
+ content = await readFile(ENV_COMPOSE, "utf8");
189
+ }
190
+ const line = `SEARXNG_SECRET=${secret}`;
191
+ const re = /^SEARXNG_SECRET=.*$/m;
192
+ if (re.test(content)) {
193
+ content = content.replace(re, line);
194
+ } else {
195
+ const sep = content.endsWith("\n") || content.length === 0 ? "" : "\n";
196
+ content = `${content}${sep}${line}\n`;
197
+ }
198
+ await writeFile(ENV_COMPOSE, content, "utf8");
199
+ }
200
+
201
+ async function settingsNeedUpdate() {
202
+ if (!(await exists(SETTINGS_PATH))) return true;
203
+ const text = await readFile(SETTINGS_PATH, "utf8");
204
+ if (!text.includes("json")) return true;
205
+ if (text.includes(DEFAULT_SECRET)) return true;
206
+ if (!/^\s*secret_key:/m.test(text)) return true;
207
+ return false;
208
+ }
209
+
141
210
  async function ensureSearxngLayout() {
142
211
  await mkdir(CORE_CONFIG, { recursive: true });
143
212
  if (!(await exists(COMPOSE_PATH))) {
@@ -152,12 +221,28 @@ async function ensureSearxngLayout() {
152
221
  }
153
222
  await copyFile(example, ENV_COMPOSE);
154
223
  }
155
- const needsSettings =
156
- !(await exists(SETTINGS_PATH)) ||
157
- !(await readFile(SETTINGS_PATH, "utf8")).includes("json");
158
- if (needsSettings) {
159
- await writeFile(SETTINGS_PATH, HARNESS_SETTINGS, "utf8");
160
- console.log(`✓ Wrote ${SETTINGS_PATH} (json format, limiter off)`);
224
+ const secret = await getOrCreateSecret();
225
+ await upsertComposeSecret(secret);
226
+ console.log(`✓ Set SEARXNG_SECRET in ${ENV_COMPOSE}`);
227
+ if (await settingsNeedUpdate()) {
228
+ try {
229
+ await writeFile(SETTINGS_PATH, buildHarnessSettings(secret), "utf8");
230
+ console.log(
231
+ `✓ Wrote ${SETTINGS_PATH} (json format, limiter off, secret_key set)`,
232
+ );
233
+ } catch (err) {
234
+ if (err && typeof err === "object" && "code" in err && err.code === "EACCES") {
235
+ console.warn(
236
+ `⚠ Could not write ${SETTINGS_PATH} (permission denied). ` +
237
+ "SEARXNG_SECRET in .env is set — restart containers. " +
238
+ `Fix ownership: chown -R $USER:$USER ${SEARXNG_DIR}`,
239
+ );
240
+ } else {
241
+ throw err;
242
+ }
243
+ }
244
+ } else {
245
+ console.log(`✓ ${SETTINGS_PATH} already configured`);
161
246
  }
162
247
  }
163
248
 
package/CHANGELOG.md CHANGED
@@ -4,6 +4,27 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [v0.6.1] — 2026-05-17
8
+
9
+ ### 🐛 Fixes
10
+
11
+ - **SearXNG bootstrap:** generate `SEARXNG_SECRET` and set `server.secret_key` so containers no longer crash on the default `ultrasecretkey` (SearXNG 2026.4+).
12
+ - **Harness env template:** remove obsolete `PI_VCC_CONFIG_PATH`; add env-only VCC, PostHog MCP, Sentrux, and default `VAULT_WIKI_PATH` keys aligned with `/harness-setup`.
13
+
14
+ ## [v0.6.0] — 2026-05-17
15
+
16
+ ### ✨ Features
17
+
18
+ - **sentrux Pi skill:** CLI-first architectural quality workflows (`check`, `gate`, GUI) via `/skill:sentrux`; symlinked in `.pi/skills`. Pi does not load `.pi/mcp.json`.
19
+
20
+ ### 📖 Documentation
21
+
22
+ - **harness-setup / CONTRIBUTING:** document Sentrux skill instead of MCP config; update `harness-sentrux-setup` workflow.
23
+
24
+ ### 🔧 Chores
25
+
26
+ - Remove shipped `.pi/mcp.json` from package `files` list; refresh `graphify-out`.
27
+
7
28
  ## [v0.5.0] — 2026-05-17
8
29
 
9
30
  ### ✨ Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-pi",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "Ultimate AI coding harness for pi.dev — extensible skills, Obsidian wiki knowledge layer, compressed context, deterministic output",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -59,7 +59,6 @@
59
59
  ".pi/model-router.example.json",
60
60
  ".pi/settings.example.json",
61
61
  ".pi/auto-commit.json",
62
- ".pi/mcp.json",
63
62
  ".pi/SYSTEM.md",
64
63
  ".pi/PACKAGING.md",
65
64
  "AGENTS.md",
package/.pi/mcp.json DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "mcpServers": {
3
- "context-mode": {
4
- "command": "context-mode"
5
- },
6
- "sentrux": {
7
- "command": "sentrux",
8
- "args": ["--mcp"]
9
- }
10
- }
11
- }