prjct-cli 3.12.2 → 3.14.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [3.14.0] - 2026-07-01
6
+
7
+ ### Features
8
+
9
+ - triage drives orchestration — trivial→direct, complex→SDD+TDD+crew, per-subagent model (#499)
10
+
11
+ ### Performance
12
+
13
+ - run bundled entry in-process — 41% faster commands (#498)
14
+
15
+
16
+ ## [3.13.0] - 2026-07-01
17
+
18
+ ### Features
19
+
20
+ - Schema v2 relational redesign + vault removal + legacy cleanup (#497)
21
+
22
+
5
23
  ## [3.12.2] - 2026-06-29
6
24
 
7
25
  ### Bug Fixes
package/README.md CHANGED
@@ -101,8 +101,8 @@ and locked-down CI, which closes the supply-chain surface a native rebuild opens
101
101
 
102
102
  After install, **next session in any prjct-cli project**:
103
103
 
104
- - **Lookup-first protocol**: Claude reads the configured vault snapshot (default: your OS Documents folder, e.g. `~/Documents/prjct/<slug>/_generated/` on macOS/Linux) BEFORE re-exploring source. Cuts ~10K tokens of exploration per session.
105
- - **Auto-capture**: Stop hook scans the assistant transcript and persists durable insights (decisions/learnings/gotchas) tagged for dedup. The next session finds them in the vault.
104
+ - **Lookup-first protocol**: Claude queries prjct (`prjct search`, `prjct context memory`, MCP `prjct_*`) BEFORE re-exploring source. Cuts ~10K tokens of exploration per session.
105
+ - **Auto-capture**: Stop hook scans the assistant transcript and persists durable insights (decisions/learnings/gotchas) tagged for dedup. The next session finds them via recall.
106
106
  - **Pattern detection**: Stop hook detects hot files (>3 changes in 7 days), recurring bugs (gotchas with the same topic), tech-debt growth (TODO/FIXME count rising). All persisted as learnings, surfaced next session.
107
107
  - **5 quality workflows** activated by natural language ("review this branch", "qa the UI", "security check", "investigate this bug"):
108
108
  - `review` — Production Bug Hunt + Completeness Gate (3 modes)
@@ -114,47 +114,45 @@ After install, **next session in any prjct-cli project**:
114
114
 
115
115
  ## How it works
116
116
 
117
- State lives in **SQLite** at `~/.prjct-cli/projects/<id>/`. The vault is an auto-regenerated Markdown snapshot under the root configured by `prjct setup` (default: your OS Documents folder, e.g. `~/Documents/prjct/<slug>/_generated/` on macOS/Linux) — agent-readable via `Read`/`Glob`, browsable in Obsidian.
117
+ State lives in **SQLite** at `~/.prjct-cli/projects/<id>/`. prjct is the LLM
118
+ data plane — agents read it **through tools**, not files: `prjct search`,
119
+ `prjct context memory`, `prjct guard`, or the MCP `prjct_*` tools. There is no
120
+ generated markdown export to browse or hand-edit.
118
121
 
119
122
  ```
120
123
  Claude Code session prjct-cli
121
124
  | |
122
125
  | SessionStart hook fires |
123
- | --------------------------------> | self-heal CLAUDE.md, regen vault
126
+ | --------------------------------> | self-heal CLAUDE.md
124
127
  | | (opt-in: silent auto-update check)
125
128
  | |
126
129
  | Lookup-first protocol kicks in: |
127
- | reads _generated/* before source |
130
+ | queries prjct before source |
128
131
  v |
129
132
  Writes code, makes decisions |
130
133
  | |
131
134
  | Stop hook fires |
132
- | --------------------------------> | ingest captured/, ingest workflows/,
133
- | | scan transcript → memory,
135
+ | --------------------------------> | scan transcript memory,
134
136
  | | detect hot files / recurring bugs
135
- | | / tech-debt growth → memory,
136
- | | regen vault
137
+ | | / tech-debt growth → memory
137
138
  ```
138
139
 
139
- State is the source of truth; the vault is recall. New knowledge enters via `prjct remember <type>`, `prjct capture`, or — automatically — the Stop hook's transcript scan.
140
+ State is the source of truth. New knowledge enters via `prjct remember <type>`, `prjct capture`, or — automatically — the Stop hook's transcript scan.
140
141
 
141
142
  ### Where data actually lives
142
143
 
143
- Not "all in a local `.prjct/` folder" — that's the pre-v1.24.1 model. Three tiers:
144
+ Not "all in a local `.prjct/` folder" — that's the pre-v1.24.1 model. Two tiers:
144
145
 
145
146
  | Tier | Location | Commit it? |
146
147
  |---|---|---|
147
148
  | Config / identity | `<repo>/.prjct/prjct.config.json` (`projectId`, persona) | **Yes** — small, machine-independent |
148
149
  | State (source of truth) | `~/.prjct-cli/projects/<projectId>/prjct.db` (SQLite) | No — per-device |
149
- | Vault (recall snapshot) | `<vault-root>/<slug>/_generated/` (Markdown; `prjct setup --vault-root <path>`) | No — regenerated |
150
150
 
151
151
  Find a project's data: read `projectId` from `.prjct/prjct.config.json`, then the
152
- DB is `~/.prjct-cli/projects/<projectId>/`, the vault is
153
- `<vault-root>/<slug>/` (`<slug>` = repo dir name lowercased; `prjct setup`
154
- chooses the global vault root, defaulting to the OS Documents folder; `PRJCT_CLI_HOME`
155
- relocates the global store). Teammates share knowledge via optional cloud sync
152
+ DB is `~/.prjct-cli/projects/<projectId>/` (`PRJCT_CLI_HOME` relocates the
153
+ global store). Teammates share knowledge via optional cloud sync
156
154
  (`prjct login` + `prjct sync`), **not** git — git never carries state. Full
157
- detail, worktrees, monorepos: **[docs/storage-and-paths.md](./docs/storage-and-paths.md)**.
155
+ detail: **[docs/storage-and-paths.md](./docs/storage-and-paths.md)**.
158
156
 
159
157
  ## Agent compatibility levels
160
158
 
@@ -249,7 +247,7 @@ prjct ship # bump version, commit, push, open P
249
247
 
250
248
  In Claude Code, ask naturally:
251
249
  - "review my changes" → activates the `review` workflow with Production Bug Hunt methodology
252
- - "what patterns does this project use?" → Claude reads `_generated/patterns.md` directly (no `grep`)
250
+ - "what patterns does this project use?" → Claude calls MCP `prjct_analysis` directly (no `grep`)
253
251
  - "investigate why tests intermittently fail" → activates `investigate` with Iron Law
254
252
 
255
253
  Optional flags:
@@ -326,12 +324,12 @@ Slots ship **empty** — the human or the agent fills them on demand.
326
324
 
327
325
  | Event | Injects |
328
326
  |---|---|
329
- | `SessionStart` | Persona; on cold start (startup/clear/compact) also the knowledge digest — top traps + decisions in force, so a freshly-updated model starts grounded. Regenerates vault from DB |
327
+ | `SessionStart` | Persona; on cold start (startup/clear/compact) also the knowledge digest — top traps + decisions in force, so a freshly-updated model starts grounded |
330
328
  | `UserPromptSubmit` | Active project state (task, branch, inbox) |
331
329
  | `PreToolUse` (Bash git commit) | Anti-patterns tagged with touched files |
332
330
  | `PreToolUse` (Edit/Write) | The file's preventive memory (gotchas/anti-patterns) right before you edit it — pushes what `prjct guard` makes pull |
333
331
  | `PostToolUse` (Edit/Write) | Silently annotates `files_touched` on active task |
334
- | `Stop` | Async prompt: "learn anything reusable?"; ingests captured/ then regenerates vault |
332
+ | `Stop` | Async prompt: "learn anything reusable?"; scans the transcript for durable captures |
335
333
  | `SubagentStart` | Persona for fresh-brain subagents (cache-stable, digest-free) |
336
334
  | `CwdChanged` | Re-contextualizes on project switch |
337
335
 
@@ -359,11 +357,10 @@ prjct init Initialize project in current directory
359
357
  prjct install Install agent surfaces, Claude hooks, Codex status line
360
358
  prjct uninstall Complete system removal
361
359
  prjct sync Sync project state, rebuild indexes
362
- prjct regen Full vault rebuild from SQLite
363
360
  prjct watch Auto-sync on file changes
364
361
  prjct doctor Check system health
365
362
  prjct hooks <install|uninstall|status> Git hooks for auto-sync
366
- prjct context <memory|learnings|wiki> Recall memory / sync the vault
363
+ prjct context <memory|learnings> Recall memory
367
364
  prjct review-risk Advisory change-size + delivery-geometry hint (read-only)
368
365
  prjct workflow ["config"] Configure hooks via natural language
369
366
  prjct stop / restart Background daemon control (self-reloads on stale code; manual restart rarely needed)
@@ -386,9 +383,9 @@ prjct capture "check why webhook retries on 502"
386
383
  prjct context memory "auth refresh"
387
384
  ```
388
385
 
389
- Memory is FTS5-backed (SQLite) and persona-filtered. Recall blends three signals — BM25 lexical, semantic vectors, and a usefulness ledger that reinforces what the project keeps building on. Capture **dedups** automatically: a verbatim re-capture of the same `(type, content)` is skipped, so detectors firing each session can't bloat the store. Every `remember`, `capture`, `ship`, and the SessionStart / Stop hooks regenerate the agent-readable markdown export at `<vault-root>/<slug>/_generated/`.
386
+ Memory is FTS5-backed (SQLite) and persona-filtered. Recall blends three signals — BM25 lexical, semantic vectors, and a usefulness ledger that reinforces what the project keeps building on. Capture **dedups** automatically: a verbatim re-capture of the same `(type, content)` is skipped, so detectors firing each session can't bloat the store.
390
387
 
391
- > SQLite is the source of truth. The export is a snapshot never hand-edit `_generated/`; if data is missing, fix the pipeline.
388
+ > SQLite is the source of truth. Agents read it through tools (`prjct search`, `prjct context memory`, MCP `prjct_*`) there is no generated file to hand-edit.
392
389
 
393
390
  ### Semantic recall (embeddings)
394
391
 
@@ -433,27 +430,6 @@ prjct embeddings set --key "$AZURE_KEY" \
433
430
 
434
431
  Without a key the built-in local embedder is used. Vector dimensionality is detected from the provider's response (no hardcoded size). Each project re-vectorizes on its next session.
435
432
 
436
- ### Drop files into the vault (bidirectional)
437
-
438
- Drop a file into `<vault-root>/<slug>/captured/` — it becomes memory, vectorized into the DB. Two shapes:
439
-
440
- ```markdown
441
- ---
442
- type: learning
443
- tags: { domain: auth }
444
- ---
445
- JWT refresh rotation needs the prior token's `iat` to detect replay.
446
- ```
447
-
448
- - **Structured** — a markdown file WITH frontmatter → one typed entry.
449
- - **Raw document** — any text file with no frontmatter (`.txt`, `.json`, `.csv`, `.md`, …) → a `source` entry, auto-chunked when long. Binary/rich docs (`.pdf`, `.docx`, `.rtf`, images) are extracted via tools you already have — `textutil` (macOS), `pdftotext` (poppler), `tesseract` (OCR) — with zero bundled dependency; without the tool the file waits for a re-sync after you install it.
450
-
451
- The Stop hook (or `prjct context wiki sync`) ingests, vectorizes, then moves the file to `captured/_ingested/<timestamp>/`. Content is scanned for secrets and prompt-injection before ingest.
452
-
453
- ### Why a markdown export?
454
-
455
- Two reasons: (1) any agent with `Read`/`Glob` consumes it without an SDK or MCP handshake — the markdown tree is paged into ~5K-token chunks so a single file read stays cheap; (2) it survives `prjct uninstall` and remains human-readable. Obsidian compatibility is a side effect — `prjct install` auto-registers the vault so `obsidian://open?vault=<slug>` works in one click, but Obsidian is never required.
456
-
457
433
  ## Code Intelligence
458
434
 
459
435
  `prjct sync` builds three indexes:
@@ -498,7 +474,7 @@ prjct-cli/
498
474
  packs/ Pack manifests + pack-manager
499
475
  mcp/ MCP server (5 tool groups)
500
476
  domain/ BM25, import-graph, git-cochange, file-ranker
501
- services/ wiki-generator, wiki-ingest, sync, skill-generator
477
+ services/ sync-service, skill-generator, pattern-detector
502
478
  storage/ SQLite (one DB per project) — source of truth
503
479
  schemas/ Zod — runtime validation
504
480
  infrastructure/ path-manager, ai-provider, command-installer
@@ -519,8 +495,8 @@ prjct-cli/
519
495
 
520
496
  **How do I initialize / register a new project?**
521
497
  In any git repo, run `prjct sync` (it auto-runs on the first `prjct` command) or
522
- `prjct init`. This creates `.prjct/prjct.config.json` with a `projectId`, builds
523
- the SQLite store at `~/.prjct-cli/projects/<projectId>/`, and generates the vault.
498
+ `prjct init`. This creates `.prjct/prjct.config.json` with a `projectId` and
499
+ builds the SQLite store at `~/.prjct-cli/projects/<projectId>/`.
524
500
 
525
501
  **How do I start an AI Agile work cycle?**
526
502
  Run `prjct work "<intent>"` from the repo. It registers the work cycle in
@@ -558,9 +534,9 @@ persisting findings to memory. Concrete examples:
558
534
 
559
535
  You can also pull project knowledge directly: ask "what patterns does this
560
536
  project use?" and the agent runs `prjct search`, `prjct context memory`, or
561
- `prjct guard` before reading source. The generated vault is a snapshot fallback;
562
- the fast path is SQLite + retrieval so agents do not flood their context.
563
- Outside an agent, every command takes `--md` to emit agent-ready markdown.
537
+ `prjct guard` before reading source bounded, ranked SQLite retrieval, so
538
+ agents do not flood their context. Outside an agent, every command takes
539
+ `--md` to emit agent-ready markdown.
564
540
 
565
541
  **What does prjct-cli output look like in a normal terminal?**
566
542
  A branded, **animated** spinner with full colors and interactive prompts (the
@@ -587,7 +563,7 @@ piped stdio (non-TTY), it adapts on every axis, with no flag:
587
563
  structured markdown the model consumes directly.
588
564
  - **Context injection** — the installed hooks feed Claude persona + active task
589
565
  + topical memory at `SessionStart`/`UserPromptSubmit`, and the lookup-first
590
- protocol points it at the regenerated vault before it re-reads source.
566
+ protocol points it at `prjct search`/MCP tools before it re-reads source.
591
567
 
592
568
  Full per-environment table: [docs/environments.md](./docs/environments.md).
593
569
 
@@ -618,9 +594,9 @@ git check-ignore -v .prjct # why git ignores it
618
594
 
619
595
  The path is always `<repoRoot>/.prjct/` (strictly relative to the project — no
620
596
  env var, no global lookup). Read `projectId` from `prjct.config.json` to reach
621
- the *other* tiers: DB at `~/.prjct-cli/projects/<projectId>/prjct.db`, vault at
622
- `<vault-root>/<slug>/_generated/` (`prjct setup --vault-root <path>` configures the vault root; `PRJCT_CLI_HOME` overrides the global
623
- base). The in-repo `.prjct/` holds only config, not state — full detail in
597
+ the state tier: DB at `~/.prjct-cli/projects/<projectId>/prjct.db`
598
+ (`PRJCT_CLI_HOME` overrides the global base). The in-repo `.prjct/` holds only
599
+ config, not state — full detail in
624
600
  [docs/storage-and-paths.md](./docs/storage-and-paths.md).
625
601
 
626
602
  **How does prjct-cli detect its environment with no configuration?**
@@ -632,8 +608,8 @@ anything.
632
608
 
633
609
  **Is all project data really in a local `.prjct/` directory? Team/VCS implications?**
634
610
  No — only `.prjct/prjct.config.json` (small, **committable** identity) is in the
635
- repo. State is per-device SQLite under `~/.prjct-cli` (never committed); the
636
- vault is regenerated. Teams coordinate via optional cloud sync, not git. Full
611
+ repo. State is per-device SQLite under `~/.prjct-cli` (never committed).
612
+ Teams coordinate via optional cloud sync, not git. Full
637
613
  tradeoffs: [docs/storage-and-paths.md](./docs/storage-and-paths.md).
638
614
 
639
615
  ## Links
package/bin/prjct.cjs CHANGED
@@ -12,6 +12,7 @@ const childProcess = require('node:child_process')
12
12
  const fs = require('node:fs')
13
13
  const os = require('node:os')
14
14
  const path = require('node:path')
15
+ const url = require('node:url')
15
16
 
16
17
  const SCRIPT_PATH = fs.realpathSync(__filename)
17
18
  const SCRIPT_DIR = path.dirname(SCRIPT_PATH)
@@ -280,6 +281,47 @@ function runWithNode(args) {
280
281
  spawnAndExit(process.execPath, [distBin, ...args], { env: withSqliteFlag() })
281
282
  }
282
283
 
284
+ /**
285
+ * Fastest path: run the bundled entry IN-PROCESS under the node that already
286
+ * booted to run this launcher — NO second runtime boot. The historical design
287
+ * spawned a fresh bun/node process solely to inject `--experimental-sqlite`;
288
+ * but node:sqlite is available WITHOUT that flag on node >=22.5 (the supported
289
+ * minimum), so the second process is pure overhead (~40ms). The bundled
290
+ * `dist/bin/prjct.mjs` is a thin cold-entry (daemon client) that reads
291
+ * process.argv directly — identical argv in-process vs spawned — and calls
292
+ * process.exit() itself, so once imported it OWNS the process.
293
+ *
294
+ * Returns true once the entry has started (caller must NOT fall through to a
295
+ * spawn, or the command would run twice). Returns false only when in-process
296
+ * load is not viable (old node, missing bundle, Windows) or the module fails
297
+ * to load — then the caller falls back to the spawn path.
298
+ */
299
+ async function runInProcess() {
300
+ // Windows keeps the well-tested spawn path (shim/pathext nuances).
301
+ if (process.platform === 'win32') return false
302
+ const distBin = path.join(ROOT_DIR, 'dist', 'bin', 'prjct.mjs')
303
+ if (!fs.existsSync(distBin) || !nodeVersionOk()) return false
304
+ // node:sqlite is experimental on node 22.x → suppress the cosmetic
305
+ // ExperimentalWarning so stderr stays clean for `--md` consumers (the
306
+ // module is functionally available without the flag).
307
+ const origEmit = process.emitWarning.bind(process)
308
+ process.emitWarning = (warning, ...rest) => {
309
+ const msg = typeof warning === 'string' ? warning : warning?.message || ''
310
+ if (typeof msg === 'string' && /sqlite/i.test(msg)) return
311
+ return origEmit(warning, ...rest)
312
+ }
313
+ try {
314
+ // Resolves when the entry's top-level finishes; the entry keeps the event
315
+ // loop alive (daemon socket / core fallback) and exits the process itself.
316
+ await import(url.pathToFileURL(distBin).href)
317
+ return true
318
+ } catch {
319
+ // Module failed to load in-process — restore warnings and fall back.
320
+ process.emitWarning = origEmit
321
+ return false
322
+ }
323
+ }
324
+
283
325
  function runWithBun(args) {
284
326
  if (process.platform === 'win32') return false
285
327
  const distBin = path.join(ROOT_DIR, 'dist', 'bin', 'prjct.mjs')
@@ -289,7 +331,7 @@ function runWithBun(args) {
289
331
  return true
290
332
  }
291
333
 
292
- function main() {
334
+ async function main() {
293
335
  const args = process.argv.slice(2)
294
336
  if (args[0] === 'mcp-server') runMcpServer(args)
295
337
 
@@ -311,8 +353,14 @@ function main() {
311
353
  writeSetupStamp(version)
312
354
  }
313
355
 
356
+ // Fastest first: run the entry in-process under this node (no second boot).
357
+ // Only falls through to a spawned runtime if in-process load isn't viable.
358
+ if (await runInProcess()) return
314
359
  if (runWithBun(args)) return
315
360
  runWithNode(args)
316
361
  }
317
362
 
318
- main()
363
+ main().catch((error) => {
364
+ console.error(`Error: ${error?.message || error}`)
365
+ process.exit(1)
366
+ })