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 +18 -0
- package/README.md +33 -57
- package/bin/prjct.cjs +50 -2
- package/dist/bin/prjct-core.mjs +903 -660
- package/dist/bin/prjct-hooks.mjs +694 -446
- package/dist/daemon/entry.mjs +809 -566
- package/dist/mcp/server.mjs +684 -411
- package/dist/templates.json +1 -1
- package/package.json +1 -1
- package/templates/antigravity/SKILL.md +1 -1
- package/templates/codex/SKILL.md +1 -1
- package/templates/crew/CLAUDE-leader-mode.md +2 -2
- package/templates/crew/agents/leader.md +4 -4
- package/templates/global/ANTIGRAVITY.md +1 -1
- package/templates/global/GEMINI.md +1 -1
- package/templates/sdd-canonical-sequence.md +1 -1
- package/templates/skills/prjct/SKILL.md +3 -4
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
|
|
105
|
-
- **Auto-capture**: Stop hook scans the assistant transcript and persists durable insights (decisions/learnings/gotchas) tagged for dedup. The next session finds them
|
|
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>/`.
|
|
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
|
|
126
|
+
| --------------------------------> | self-heal CLAUDE.md
|
|
124
127
|
| | (opt-in: silent auto-update check)
|
|
125
128
|
| |
|
|
126
129
|
| Lookup-first protocol kicks in: |
|
|
127
|
-
|
|
|
130
|
+
| queries prjct before source |
|
|
128
131
|
v |
|
|
129
132
|
Writes code, makes decisions |
|
|
130
133
|
| |
|
|
131
134
|
| Stop hook fires |
|
|
132
|
-
| --------------------------------> |
|
|
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
|
|
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.
|
|
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
|
|
153
|
-
|
|
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
|
|
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
|
|
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
|
|
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?";
|
|
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
|
|
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.
|
|
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.
|
|
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/
|
|
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
|
|
523
|
-
the SQLite store at `~/.prjct-cli/projects/<projectId
|
|
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
|
|
562
|
-
|
|
563
|
-
|
|
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
|
|
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
|
|
622
|
-
|
|
623
|
-
|
|
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)
|
|
636
|
-
|
|
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
|
+
})
|