@primitive.ai/prim 0.1.0-alpha.19 → 0.1.0-alpha.20

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/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # @primitive.ai/prim
2
2
 
3
- The official CLI for [Primitive](https://getprimitive.ai). Manage specs, contexts, projects, and git hooks from the command line.
3
+ The official CLI for [Primitive](https://getprimitive.ai)'s **decision graph**. It
4
+ passively captures the decisions your team makes while coding, gates edits that
5
+ conflict with prior team decisions, and reports team presence — from the command
6
+ line and via session + git hooks.
4
7
 
5
8
  > [!WARNING]
6
9
  > This project is in **alpha**. Commands and APIs may change between releases.
@@ -22,16 +25,21 @@ npx @primitive.ai/prim
22
25
  ## Quick Start
23
26
 
24
27
  ```bash
25
- # Authenticate via browser (WorkOS OAuth)
28
+ # 1. Authenticate via browser (WorkOS OAuth)
26
29
  prim auth login
27
30
 
28
- # List your specs
29
- prim spec list
31
+ # 2. Wire the session hooks (decision capture + conflict gate + presence)
32
+ prim claude install # or: prim codex install
30
33
 
31
- # Install the pre-commit hook
34
+ # 3. Start the companion daemon (latency + team presence)
35
+ prim daemon start
36
+
37
+ # 4. Install the git hooks (pre-commit decision check + post-commit capture)
32
38
  prim hooks install
33
39
  ```
34
40
 
41
+ An AI coding agent can drive the entire setup itself — see [`setup.md`](./setup.md).
42
+
35
43
  ## Commands
36
44
 
37
45
  ### Auth
@@ -43,57 +51,92 @@ prim auth clear # Remove saved tokens
43
51
  prim auth status # Check authentication status
44
52
  ```
45
53
 
46
- ### Specs
54
+ ### Session integration
47
55
 
48
- Specs are documents that drive implementation. They can be synced to a project DAG and mapped to file patterns for automatic pre-commit hook integration.
56
+ Wires the agent's session hooks so the decisions you make are captured into the
57
+ graph, conflicting edits are gated, and presence is reported. Each hook
58
+ self-resolves the CLI at run time (PATH, then a local install, then
59
+ `npx --yes @latest`), so it keeps working with no global install.
49
60
 
50
61
  ```bash
51
- prim spec list # List all specs
52
- prim spec list --project-id <id> # Find spec for a root project
53
- prim spec get <id> # Show spec details
54
- prim spec get <id> --text-only # Print raw spec text
55
- prim spec update <id> --file spec.md # Update spec from file
56
- prim spec update <id> --name "New" # Rename a spec
57
- prim spec sync <id> # Trigger spec-to-project sync
58
- prim spec map <id> -p "src/auth/**" # Map file patterns to a spec
59
- prim spec unmap <id> # Clear all file patterns
60
- prim spec unmap <id> -p "src/auth/**" # Remove specific pattern
61
- prim spec auto-map <id> # Auto-detect file patterns
62
+ prim claude install # Install Claude Code hooks (uninstall / status)
63
+ prim codex install # Install OpenAI Codex hooks (uninstall / status)
62
64
  ```
63
65
 
64
- ### Contexts
66
+ ### Daemon
67
+
68
+ A long-lived companion process that accelerates the in-session decision checks
69
+ and powers the "team: N online" presence count. Optional — hooks fall back to
70
+ direct calls if it is down.
65
71
 
66
72
  ```bash
67
- prim context list # List all contexts
68
- prim context list --scope project # Filter by scope
69
- prim context list --project-id <id> # List contexts for a project
70
- prim context get <id> # Get context details
71
- prim context create -s project -n "Name" # Create a context
72
- prim context create -s project -n "Name" --file path/to/file
73
- prim context update <id> --name "New" # Update a context
74
- prim context delete <id> # Delete a context
75
- prim context link <id> --project <pid> # Link context to project
76
- prim context unlink <id> --project <pid> # Unlink context from project
73
+ prim daemon start # start (stop / restart / status)
77
74
  ```
78
75
 
79
- ### Projects
76
+ ### Decisions
77
+
78
+ Read and respond to the decision graph.
80
79
 
81
80
  ```bash
82
- prim project create -n "Project name" # Create a project
83
- prim project create -n "Project name" -d "Description" # Create with description
84
- prim project create -n "Project name" --spec <contextId> # Create and link a spec
81
+ prim decisions recent # Recent decisions feed
82
+ prim decisions show <id> # Drill into one decision
83
+ prim decisions cascade <id> # Blast radius of a decision
84
+ prim decisions check --files <…> # Active decisions referencing files (warn-only)
85
+ prim decisions confirm <id> # Answer a rationale-confirmation prompt
86
+ ```
87
+
88
+ `<id>` accepts a full decision ID or its short ID. STDOUT is machine-readable
89
+ JSON; human-readable status goes to STDERR.
90
+
91
+ ### Reconcile
92
+
93
+ ```bash
94
+ prim reconcile <id> # Mint a single-use bypass for a decision a gate flagged
85
95
  ```
86
96
 
87
97
  ### Hooks
88
98
 
89
99
  ```bash
90
- prim hooks install # Install pre-commit hook
91
- prim hooks uninstall # Remove pre-commit hook
100
+ prim hooks install # Install git hooks (pre-commit decision check + post-commit capture)
101
+ prim hooks uninstall # Remove the prim git hooks
102
+ ```
103
+
104
+ The pre-commit hook checks staged files against the live decision graph
105
+ (warn-only — it never blocks the commit). The post-commit hook records each
106
+ commit as a capture boundary for classification. Supports
107
+ [Husky](https://typicode.github.io/husky/) — `prim hooks install` detects Husky
108
+ and offers to install into `.husky/`.
109
+
110
+ ### Presence statusline
111
+
112
+ ```bash
113
+ prim statusline # Render the team-presence statusline (reads the daemon)
92
114
  ```
93
115
 
94
- The pre-commit hook automatically syncs specs when you commit changes to files matching a spec's file patterns (configured via `prim spec map`).
116
+ ### Session & journal
117
+
118
+ Lower-level plumbing for the capture pipeline — org binding and the local move
119
+ journal. Capture works automatically once the session hooks are installed; these
120
+ are for inspecting and steering it (e.g. multi-org machines).
121
+
122
+ ```bash
123
+ prim session start <id> # Pin a Claude Code session to an org (list / drop <id>)
124
+ prim moves bind # Pin the current directory to an org via .prim/workspace.json (drop)
125
+ prim moves status # Per-bucket pending stats for the local journal
126
+ prim moves tail # Pretty-print recent journal entries
127
+ prim moves flush # Drain the local journals to the server (also runs from hooks)
128
+ ```
129
+
130
+ ### Skill
131
+
132
+ ```bash
133
+ prim skill install # Install the decision-graph agent guide into your rules file
134
+ prim skill uninstall # Remove the managed block
135
+ prim skill status # Report whether the block is installed
136
+ ```
95
137
 
96
- Supports [Husky](https://typicode.github.io/husky/) `prim hooks install` detects Husky and offers to install into `.husky/pre-commit`.
138
+ Writes a managed block teaching your agent how to work with the decision graph
139
+ into the rules file it reads (CLAUDE.md, AGENTS.md, .cursor/rules, …).
97
140
 
98
141
  ## Development
99
142
 
package/SKILL.md CHANGED
@@ -1,21 +1,17 @@
1
1
  ---
2
2
  name: prim
3
- description: Use the prim CLI for Primitive specs, contexts, projects, pre-commit hooks, and the decision graph (passive decision capture, the conflict gate, reconcile, and team presence). TRIGGER when the user mentions Primitive, prim, "specs" or "contexts" (in the Primitive sense), or decisions / the decision graph / a conflict gate / reconcile; when the repo's package.json depends on @primitive.ai/prim; when the user asks to sync, map, update, or auto-map a spec; when an edit is denied or warned by a prior decision; when configuring Primitive hooks. SKIP when "spec" means test specs (vitest, jest, rspec), when "context" means React context or an LLM context window, or for unrelated CLIs.
3
+ description: Use the prim CLI for Primitive's decision graph passive decision capture, the conflict gate, reconcile, rationale confirmations, and team presence. TRIGGER when the user mentions Primitive, prim, decisions / the decision graph / a conflict gate / reconcile; when an edit is denied or warned by a prior decision; when the repo's package.json depends on @primitive.ai/prim; when configuring Primitive session or git hooks. SKIP when "decision" is unrelated to Primitive, or for unrelated CLIs.
4
4
  ---
5
5
 
6
6
  # Working with the prim CLI
7
7
 
8
- `prim` is the official CLI for [Primitive](https://app.getprimitive.ai). Use it -- don't reach for shell or curl.
8
+ `prim` is the official CLI for [Primitive](https://app.getprimitive.ai)'s **decision graph**. Use it -- don't reach for shell or curl.
9
9
 
10
10
  ## Mental model
11
11
 
12
- A **spec** captures intent for execution -- it defines what should be done, usually so other agents (or humans) can act on it. A **context** is everything else: supporting material that informs but doesn't define the work -- design docs, references, prior art, shared documentation, examples. When deciding which to create, ask: does this say *what to do*, or does it *inform* whoever's doing it? A project has at most one spec but can link many contexts.
12
+ As your team codes, prim passively captures the **decisions** you make -- which library, which pattern, which config value -- into a queryable graph, and links them: a decision can depend on earlier decisions and reference the files it touched. When a later change conflicts with a load-bearing prior decision, prim **gates** the edit and surfaces the decision for review.
13
13
 
14
- In Primitive, a markdown spec is associated with a **project**. The spec is the source of truth: `npx --yes @primitive.ai/prim spec sync` parses the spec, diffs it against the project, and **applies the diff** -- adding, updating, or **archiving** items in the project to match. Items removed from a spec are soft-archived (recoverable via the dashboard), not deleted -- but they leave the active view, so flag the user before large spec rewrites on projects with work in flight.
15
-
16
- A **spec is a kind of context** -- same IDs, same storage. The `npx --yes @primitive.ai/prim spec ...` commands are a focused view onto specs; `npx --yes @primitive.ai/prim context get <id>` works on a spec ID and vice versa. For structured metadata on a spec (review status, root project, sync version, scope, file patterns), use `npx --yes @primitive.ai/prim context get <specId>` -- it returns JSON.
17
-
18
- `npx --yes @primitive.ai/prim spec list` returns only spec-type contexts. `npx --yes @primitive.ai/prim context list` returns all contexts regardless of type.
14
+ You never invoke capture. It runs automatically through the session hooks installed by `npx --yes @primitive.ai/prim claude install` (Claude Code) or `npx --yes @primitive.ai/prim codex install` (Codex). Your job is to **respond** to the gate, **read** the graph before load-bearing edits, and **answer** the occasional rationale confirmation.
19
15
 
20
16
  ## Auth
21
17
 
@@ -25,21 +21,18 @@ Three ways to authenticate, in priority order:
25
21
 
26
22
  1. **`PRIM_TOKEN` environment variable** -- preferred for agents and CI. Set it before invoking prim and you're done; no interactive flow, no token files.
27
23
  2. **`npx --yes @primitive.ai/prim auth set-token <token>`** -- saves a bearer token to `~/.config/prim/token`. Use when the user has a long-lived token in hand.
28
- 3. **`npx --yes @primitive.ai/prim auth login`** -- opens a browser via WorkOS OAuth. **An agent cannot complete this.** If `auth status` exits non-zero and `PRIM_TOKEN` is unset, **stop and ask the user** to run `npx --yes @primitive.ai/prim auth login` themselves.
24
+ 3. **`npx --yes @primitive.ai/prim auth login`** -- opens a browser via WorkOS OAuth. **Drive this yourself; do not hand it to the user.** It blocks up to 2 minutes waiting for approval -- that wait is expected, not a failure. The user's only action is clicking "Authorize". Run it in the background, surface the authorize URL it prints on STDERR so the user can click it if the browser didn't open, then poll `auth status` until it exits 0. If it times out before they click, run it again -- never fall back to asking them to run it.
29
25
 
30
- The CLI auto-refreshes expired tokens. On unrecoverable expiry it throws `Authentication expired. Run prim auth login to re-authenticate.` -- relay it.
26
+ The CLI auto-refreshes a still-valid session from the stored refresh token (proactively ~60s before expiry, and again on a 401), so a short access-token "expires in 2m" is normal -- not a reason to re-authenticate or warn the user. Only an absent refresh token, or an explicit `Authentication expired. Run prim auth login to re-authenticate.`, warrants a re-login -- which you then drive yourself, per the above. Relay that message if it appears.
31
27
 
32
28
  ## Ground rules
33
29
 
34
- 1. Don't guess IDs. Discover them with `npx --yes @primitive.ai/prim spec list`, `npx --yes @primitive.ai/prim spec list --project-id <pid>`, or `npx --yes @primitive.ai/prim context list`.
35
- 2. Every command accepts `--help`. When unsure of flags, run `npx --yes @primitive.ai/prim <cmd> --help` rather than guessing.
36
- 3. The CLI prints API errors as one-liners to stderr and exits non-zero. Treat any non-zero exit as actionable. If a command fails with an unrecognized error, re-run with `--help` to check your flags. If auth-related, re-check `auth status`.
30
+ 1. Every command accepts `--help`. When unsure of flags, run `npx --yes @primitive.ai/prim <cmd> --help` rather than guessing.
31
+ 2. The CLI prints API errors as one-liners to stderr and exits non-zero. Treat any non-zero exit as actionable. If auth-related, re-check `auth status`.
32
+ 3. `<idOrShortId>` arguments accept either a full decision ID or the short ID shown in feeds and gate reasons.
37
33
 
38
- ## Working with the decision graph
34
+ ## Heed the conflict gate
39
35
 
40
- Separate from specs, prim passively captures the decisions you make during a coding session -- which library, which pattern, which config value -- into a queryable decision graph, and actively **gates** edits that would conflict with a load-bearing prior decision. Capture and the gate run automatically through the session hooks installed by `npx --yes @primitive.ai/prim claude install` (Claude Code) or `npx --yes @primitive.ai/prim codex install` (Codex). You never invoke capture; you *respond* to the gate and *read* the graph.
41
-
42
- ### Heed the conflict gate
43
36
  Before an edit (Claude Code: Edit/Write/MultiEdit; Codex: apply_patch) a PreToolUse hook scores the target file against the graph:
44
37
 
45
38
  - **deny** -- the edit is blocked: it conflicts with a load-bearing prior decision. Don't fight it. Read the reason line; it names the decision id. If you genuinely intend to override that decision, run `npx --yes @primitive.ai/prim reconcile dec_<shortId>`, then retry the edit once. Otherwise choose an approach that respects the decision.
@@ -48,12 +41,14 @@ Before an edit (Claude Code: Edit/Write/MultiEdit; Codex: apply_patch) a PreTool
48
41
 
49
42
  The gate fail-opens on its *own* infrastructure errors (no daemon, network blip, org-unbound token) -- a setup problem never blocks your edit. That is exactly why an "unavailable" note matters: it is the honest signal that the check, not your edit, is what failed.
50
43
 
51
- ### Read the graph before large or load-bearing edits
44
+ ## Read the graph before large or load-bearing edits
45
+
52
46
  - `npx --yes @primitive.ai/prim decisions check --files "src/a.ts,src/b.ts"` -- which active decisions reference the files you're about to touch (comma-separated paths, one `--files` value). Run it before a big change.
53
47
  - `npx --yes @primitive.ai/prim decisions recent` -- the team's recent decisions, each row badged by author and agent (`Your Claude Code` / `Your Codex`); `--limit <n>` and `--since <dur>` narrow it.
54
48
  - `npx --yes @primitive.ai/prim decisions show <idOrShortId>` and `npx --yes @primitive.ai/prim decisions cascade <idOrShortId>` -- full detail, and the downstream blast radius a change would disturb.
55
49
 
56
- ### Reconcile and the verdict footer
50
+ ## Reconcile and the verdict footer
51
+
57
52
  `npx --yes @primitive.ai/prim reconcile <idOrShortId>` mints a single-use bypass for the named decision -- it prints `[prim] reconcile bypass issued for dec_<short> (expires in ...)` to STDERR, with the bypass JSON on STDOUT. Your *next* edit to the governed file then goes through, and on that edit prim prints a verdict footer to STDERR -- confirmation the override was recorded, not silently dropped:
58
53
 
59
54
  ```
@@ -62,198 +57,60 @@ The gate fail-opens on its *own* infrastructure errors (no daemon, network blip,
62
57
 
63
58
  `N` is the reconciled decision's downstream live-dependent count, shown as `N+` when the server caps it.
64
59
 
65
- ### Presence
66
- With the daemon running (`npx --yes @primitive.ai/prim daemon start`), `npx --yes @primitive.ai/prim daemon status` includes the live online count in its STDOUT JSON (when presence is fresh); Claude Code surfaces it in the statusline as `team: N online`. Your captured decisions are attributed to your agent automatically -- no flag required.
60
+ ## Answer rationale confirmations
67
61
 
68
- ## Common workflows
62
+ Occasionally the graph asks you (or the user) to confirm *why* a decision was made — a low-friction yes/no, never a paragraph. Answer it with:
69
63
 
70
- ### Read a spec's current text (do this before any partial edit)
71
64
  ```
72
- npx --yes @primitive.ai/prim spec get <id> --text-only > spec.md
65
+ npx --yes @primitive.ai/prim decisions confirm <idOrShortId>
73
66
  ```
74
- `npx --yes @primitive.ai/prim spec update <id> --file <path>` replaces the entire body. Fetch first if you're only changing part of it.
75
67
 
76
- ### Update a spec from a local file and apply to the project
77
- ```
78
- npx --yes @primitive.ai/prim spec list --project-id <pid> # find the spec for a project
79
- npx --yes @primitive.ai/prim spec update <id> --file spec.md # replaces spec body
80
- npx --yes @primitive.ai/prim spec sync <id> # required -- update doesn't apply changes to the project
81
- ```
82
- `npx --yes @primitive.ai/prim spec sync` is **async**: it returns immediately with `Triggered sync for spec`, then applies in the background. The project isn't updated when the command returns -- surface that to the user.
83
-
84
- Auto-map runs automatically on the server after every `spec update`. Call `npx --yes @primitive.ai/prim spec auto-map <id>` explicitly only to re-run mapping without changing the spec text.
85
-
86
- ### Map files to a spec (so pre-commit auto-syncs all affected specs)
87
- ```
88
- npx --yes @primitive.ai/prim spec map <id> -p "src/auth/**" "src/foo/**" # multiple patterns at once
89
- npx --yes @primitive.ai/prim spec unmap <id> -p "src/auth/**" # remove one
90
- npx --yes @primitive.ai/prim spec unmap <id> # clear all manual patterns
91
- ```
92
-
93
- ### Create or link a context
94
- ```
95
- npx --yes @primitive.ai/prim context create -s project -n "<name>" --file <path> --project-id <pid> # add --spec to make it a spec
96
- npx --yes @primitive.ai/prim context create -s global -n "<name>" --text "..." # filed in the global context pane, not linked to a specific project
97
- npx --yes @primitive.ai/prim context link <ctxId> --project <projectId> # works on any scope
98
- npx --yes @primitive.ai/prim context unlink <ctxId> --project <projectId> # remove a link
99
- ```
100
-
101
- ### Update or delete a context
102
- ```
103
- npx --yes @primitive.ai/prim context update <id> -n "<new name>" # rename
104
- npx --yes @primitive.ai/prim context update <id> --file <path> # replace body
105
- npx --yes @primitive.ai/prim context delete <id> # permanent -- confirm with the user first
106
- ```
107
-
108
- ### Create a project (optionally with a linked spec)
109
- ```
110
- npx --yes @primitive.ai/prim project create -n "<name>" -d "<desc>"
111
- npx --yes @primitive.ai/prim project create -n "<name>" --spec <contextId> # value is a context ID
112
- ```
113
-
114
- ### Link a spec to a branch (and an optional PR)
115
-
116
- Linking is **automatic** once the pre-commit hook is installed and a spec is bound to your branch — every commit refreshes the link's metadata, including the PR number (detected from `gh pr view` when `gh` is on `PATH`). When a spec was authored for the work on this branch, bind it at the right moment so the hook can take over — do this without waiting for the user to ask. When no spec exists for the work, **do not bind one** — see "Decide whether a spec exists for this branch" below.
117
-
118
- **At the start of branch work, install the hook** (skip if `.git/hooks/pre-commit` or `.husky/pre-commit` already invokes `prim-pre-commit`):
119
- ```
120
- npx --yes @primitive.ai/prim hooks install --yes
121
- ```
122
-
123
- **When you create a spec for branch-scoped work, always pass `--branch`** (and `--pr` if a PR already exists):
124
- ```
125
- br=$(git rev-parse --abbrev-ref HEAD)
126
- pr=$(gh pr view --json number -q .number 2>/dev/null)
127
- npx --yes @primitive.ai/prim spec create -s project -n "<name>" --file <path> --branch "$br" ${pr:+--pr "$pr"}
128
- ```
129
- `--branch` requires a GitHub origin; if `git remote get-url origin` isn't GitHub the link is silently dropped (stderr warning). There is no `prim spec link` subcommand in v1 — to rebind a spec to a different branch, edit it from the spec editor UI.
68
+ Confirmations are author-targeted and rare by design; answering keeps the graph's rationale trustworthy. Don't manufacture rationale — if you don't know why a decision was made, say so.
130
69
 
131
- **Decide whether a spec exists for this branch.** A spec is "for this branch" only if one of:
132
- - the user named a spec ID or title in conversation,
133
- - a spec was created with `--branch "$br"` (visible via `npx --yes @primitive.ai/prim spec list --json | jq --arg br "$br" '.[] | select(.linkedBranches[]?.branch == $br)'`, where `$br` is the same shell variable set in the recipe above).
70
+ ## Presence
134
71
 
135
- **Do not** browse `prim spec list` and pick the closest- or most-related-sounding spec. Topical proximity is not authorship two specs that touch the same area of the codebase can describe entirely different intents. An irrelevant link pollutes drift signal and silently misattributes review findings; no link is strictly better than a wrong link.
136
-
137
- If neither signal applies, **stop and ask the user**:
138
-
139
- > "I couldn't find a spec associated with this branch. Is there one I should link, or should I draft one from the PR description and our conversation?"
140
-
141
- Three legitimate answers:
142
- - **User names an existing spec** → proceed to "When the user has identified a spec for this branch" below.
143
- - **User declines a spec entirely** → leave the PR unlinked.
144
- - **User asks you to draft one** →
145
- - Compose with these sections (drop any that would only restate the obvious): *Goal*, *Requirements / Behavior*, *Technical Approach*, *Key Decisions*, *Out of Scope*. Scope to what the PR actually changed; don't restate the unchanged system. Each fact appears in exactly one section.
146
- - Voice: plain language; lead with the point; **intent before mechanism** ("users see each other's edits" before "we use WebSocket"); present tense, active voice; one idea per paragraph; cut sentences that don't earn their place.
147
- - **Key Decisions** is a markdown table — columns *Decision | Rationale | Trade-offs*, one row per non-obvious choice.
148
- - Title is just the feature name (no `Spec:` prefix); no numbered or parenthetical headers. Match length to PR complexity — a small fix is one screen; a substantial feature warrants the full shape.
149
- - Do not paste the PR description verbatim — a spec captures *intent*, not a change log. If the rationale behind a non-obvious decision isn't in conversation, ask one or two targeted questions before drafting; do not invent rationale.
150
- - Show the user the drafted text and wait for go-ahead before running `spec create`.
151
- - Then create-and-link using the recipe above.
152
-
153
- **When the user has identified a spec for this branch, check whether it's bound to your branch** before committing:
154
- ```
155
- npx --yes @primitive.ai/prim context get <specId> --json | jq '.linkedBranches[]?.branch'
156
- ```
157
- - Your branch appears → done; the hook keeps it fresh.
158
- - Empty or branch absent → the first commit's hook auto-binds it; no CLI step needed.
159
- - Bound only to another branch → the hook silently excludes it from your branch's syncs; rebind via the editor UI before committing.
160
-
161
- **After `gh pr create`**, no CLI step is required: the next commit's hook patches `linkedBranches[].prNumber` via `gh pr view`, and GitHub's webhook to Primitive sets the same field server-side within seconds. Confirm with:
162
- ```
163
- npx --yes @primitive.ai/prim context get <specId> --json | jq .linkedBranches
164
- ```
165
-
166
- **On every commit, read the `[synced]` line to verify link state** — it piggybacks the suffix:
167
- - `(auto-linking to <branch>)` — first sync; server is binding now.
168
- - `(linked to <branch> #<n> <state>)` — link is sticky.
169
- - `[skip] <id> — not linked to <branch>` — the spec is bound elsewhere; investigate before continuing.
170
-
171
- ### Trigger PR Intent Review or dispatch drift-fix against a linked PR
172
-
173
- ```
174
- npx --yes @primitive.ai/prim spec review <id> --pr <n> # head SHA defaults to `git rev-parse HEAD`
175
- npx --yes @primitive.ai/prim spec review <id> --pr <n> --sha <s> # explicit SHA
176
- npx --yes @primitive.ai/prim spec drift <id> --pr <n> # dispatch the Claude Code drift-fix workflow against the PR
177
- ```
178
-
179
- The review bot runs server-side, posts a PR comment with findings, and the outcome surfaces on the **next** pre-commit sync's `[synced]` line as ` (reviewed: <n> finding(s) → <prCommentUrl>)` or ` (review failed)` — don't poll the API yourself.
180
-
181
- `spec drift` requires the `primitive-drift-fix.yml` workflow file checked into the repo and the GitHub App's `actions:write` scope granted on the org. The CLI errors out otherwise with a one-liner naming the likely causes.
182
-
183
- Neither `spec review` nor `spec drift` accepts `--json` in v1 — they emit a single human-readable line on stdout. Capture it as text or branch on `$?`.
184
-
185
- ### Inspect a task's auto-completion state
186
-
187
- ```
188
- npx --yes @primitive.ai/prim spec status <taskId>
189
- ```
72
+ With the daemon running (`npx --yes @primitive.ai/prim daemon start`), `npx --yes @primitive.ai/prim daemon status` includes the live online count in its STDOUT JSON (when presence is fresh); Claude Code surfaces it in the statusline as `team: N online`. Your captured decisions are attributed to your agent automatically -- no flag required.
190
73
 
191
- Reports the task's `status`, whether `auto-complete suppressed: yes/no`, and the timestamp + PR # of the most-recent auto-completion activity (with the bot's explanation). Use this after a merge to verify the auto-complete bot acted — or to see *why* it didn't (suppressed via the dashboard, last activity from a different PR, etc.).
74
+ ## The git hooks
192
75
 
193
- `spec status` operates on a **task ID**, not a context/spec ID. Discover task IDs from `prim project create` output or from the editor URL. No `--json` support in v1; output is a fixed `key: value` block on stdout.
76
+ `npx --yes @primitive.ai/prim hooks install` installs two git hooks:
194
77
 
195
- ### Install the pre-commit hook
196
78
  ```
197
79
  npx --yes @primitive.ai/prim hooks install # auto-detects Husky and prompts
198
80
  npx --yes @primitive.ai/prim hooks install --yes # confirm Husky (non-interactive)
199
81
  npx --yes @primitive.ai/prim hooks install --target=git-hooks # force .git/hooks (skip Husky detection)
200
82
  npx --yes @primitive.ai/prim hooks uninstall
201
83
  ```
202
- Under `CI=1` (or with `--non-interactive`), `hooks install` fails fast in a Husky repo unless `--yes` or `--target` is set. The error message names both escapes.
203
-
204
- **Note:** `hooks uninstall` only removes `.git/hooks/pre-commit`. If the hook was installed into `.husky/pre-commit`, you must remove the prim block from that file manually.
205
-
206
- ## How the pre-commit hook behaves
207
-
208
- `npx --yes @primitive.ai/prim hooks install` adds a hook that, on every commit:
209
84
 
210
- 1. Fetches the org's spec-to-file-pattern mappings.
211
- 2. Glob-matches staged files against each spec's patterns (`*` and `**` supported).
212
- 3. For each affected spec, sends `git diff --cached` to `/api/cli/contexts/:id/sync-diff`. The backend runs an **LLM over (current spec + diff)** to produce edits, updates the spec text, then applies the new spec to the project.
213
- 4. Prints `[synced] <id> -- <name>` or `[skip] <id> -- <reason>` per affected spec to stdout, and `[error]` lines to stderr.
85
+ - **pre-commit** -- checks staged files against the live decision graph and prints any active decisions that reference them to stderr. It is **warn-only**: failures (auth, network, backend) or matches never block the commit; a successful `git commit` doesn't prove the check ran clean. When the check can't complete it says so ("not verified" / "truncated") rather than implying all-clear.
86
+ - **post-commit** -- records each commit as a capture boundary so the server can classify the surrounding work into decisions. It never blocks and runs in the background.
214
87
 
215
- What that means:
88
+ Under `CI=1` (or with `--non-interactive`), `hooks install` fails fast in a Husky repo unless `--yes` or `--target` is set; the error names both escapes. `hooks uninstall` only removes the `.git/hooks` copies — if a hook was installed into `.husky/`, remove the prim block from that file manually. To suppress the hooks for one commit, use `git commit --no-verify`.
216
89
 
217
- - **The hook is not `npx --yes @primitive.ai/prim spec sync`.** `npx --yes @primitive.ai/prim spec sync` re-applies the *existing* spec to the project. The hook calls `sync-diff` -- an LLM updates the spec from the code change, then applies the new spec to the project. The casual "just commit and the hook will sync" is ambiguous; when explaining to the user, specify which operation you mean.
218
- - **The hook never blocks the commit.** Failures (auth, network, backend) print `[error]` to stderr but exit 0, so a successful `git commit` doesn't prove the spec changed. Check the hook's `[synced]` / `[error]` / `[skip]` output, or verify with `npx --yes @primitive.ai/prim spec get <id>`.
219
- - **Diffs over 256 KiB are truncated.** The hook logs `(truncated: X KiB -> Y KiB analyzed)`. The LLM only sees the first 256 KiB of the diff.
220
- - **The hook is branch-aware.** It sends `repoFullName`, `branch`, `sha`, and `prNumber` (the last detected from `gh pr view` when `gh` is on `PATH`, silently null otherwise). The server filters mappings to specs linked to the current branch *or* unlinked (auto-link candidates); specs bound to other branches are silently excluded from the affected list — they don't surface as `[skip]` lines, they just don't appear. If you push an explicit `sync-diff` for an other-branch spec via the API, the hook logs `[skip] <id> — <name> — not linked to <branch>` and continues.
221
- - **Link state and review results piggyback on the synced line.** `[synced]` lines carry ` (linked to <branch> #<pr> <state>)` or ` (auto-linking to <branch>)`, and once a PR Intent Review completes they grow ` (reviewed: <n> finding(s) → <prCommentUrl>)` or ` (review failed)`. PR `<state>` (`open` / `closed` / `merged`) tracks GitHub webhook deliveries — give it a few seconds to settle after a state change.
222
- - **To suppress the hook for one commit** (e.g., when intentionally desyncing code from spec, or when committing unrelated changes), use `git commit --no-verify`.
90
+ These git hooks are separate from the **session hooks** (`claude install` / `codex install`) that drive in-session capture and the conflict gate.
223
91
 
224
92
  ## Output formats
225
93
 
226
- Every data-returning command accepts `--json`. With `--json` set, stdout is a single JSON document — pipe to `jq` instead of parsing text:
94
+ The CLI keeps STDOUT machine-readable and STDERR human-readable. The `decisions` and `reconcile` commands **always** emit a single JSON document on STDOUT no flag needed; pipe straight to `jq`. The `decisions` commands have **no** `--json` flag and reject one; `reconcile` accepts a reserved no-op `--json`. `auth status` and `skill status` default to human-readable STDOUT and take `--json` to switch to JSON.
227
95
 
228
- - `id=$(npx --yes @primitive.ai/prim context create -s global -n foo --text "x" --json | jq -r ._id)` capture an ID
229
- - `npx --yes @primitive.ai/prim spec list --json | jq -r '.[]._id'` — list every spec ID
230
- - `npx --yes @primitive.ai/prim auth status --json | jq -r .authenticated` boolean; the exit code remains the authoritative signal
231
-
232
- Without `--json`, mutating commands (`context create/update/delete/link/unlink`, `spec create/update/sync/map/unmap/auto-map`, `project create`) emit the bare resource `_id` to **stdout** (one line, no prefix) and human-readable diagnostics to **stderr**. So this also works as a one-liner without `jq`:
96
+ - **STDOUT is machine-readable** JSON (one document per invocation). `decisions` reads project lean shapes, not raw rows.
97
+ - **STDERR is human-readable** a verdict-first line, plus the gate/verdict-footer/presence notes.
98
+ - **Exit code is authoritative** where it carries meaning — `auth status` exits 0 when authenticated; `decisions show`/`cascade`/`confirm` exit non-zero (e.g. 4 not-found) on a missing or unauthorized id.
233
99
 
234
- - `id=$(npx --yes @primitive.ai/prim context create -s global -n foo --text "x")`
100
+ Examples:
235
101
 
236
- | Command | Without `--json` | With `--json` |
237
- |---|---|---|
238
- | Mutators above | stdout: bare `_id`; stderr: `Created/Updated/...` prefix (plus secondary lines: `Root project:`, `Linked spec:`, pattern lists) | stdout: `{ "_id": "<id>", }` with extras where applicable (`spec sync` adds `specRootTaskId`; `context link/unlink` add `project`; `project create --spec` adds `spec`; `spec map/unmap` add `filePatterns`) |
239
- | `context list`, `spec list` (non-empty) | stdout: rows (first token = `_id`); stderr: `N context(s)` / `N spec(s)` summary | stdout: JSON array |
240
- | `context list`, `spec list` (empty) | stdout: (empty); stderr: `No contexts found.` / `No spec documents found.` | stdout: `[]` |
241
- | `spec list --project-id <pid>` | stdout: key:value block (or stdout empty + stderr `No spec document found for this project.` if none) | stdout: single object or `null` |
242
- | `context get <id>` | stdout: pretty-printed JSON (always JSON; `--json` accepted for symmetry) | stdout: pretty-printed JSON |
243
- | `spec get <id>` | stdout: human-readable key:value block (`ID:` line first) | stdout: JSON object |
244
- | `spec get <id> --text-only` | stdout: raw spec markdown, nothing else | stdout: JSON object (`--json` wins over `--text-only`) |
245
- | `auth status` | stdout: human readout; **exit code is the authoritative signal** (0 = authed) | stdout: JSON; exit code unchanged |
102
+ - `npx --yes @primitive.ai/prim auth status --json | jq -r .authenticated` — boolean; the exit code remains the authoritative signal
103
+ - `npx --yes @primitive.ai/prim decisions recent | jq -r '.decisions[].shortId'` — list recent decision short ids (STDOUT is already JSON)
104
+ - `npx --yes @primitive.ai/prim decisions show <id> | jq .` full decision detail
246
105
 
247
106
  ## Pitfalls
248
107
 
249
- - **`npx --yes @primitive.ai/prim spec sync` archives anything dropped from the spec.** Removed content is archived (recoverable), not deleted.
250
- - **`npx --yes @primitive.ai/prim spec update` doesn't apply changes to the project.** Always follow with `npx --yes @primitive.ai/prim spec sync <id>`.
251
- - **`npx --yes @primitive.ai/prim spec update --file` replaces the whole body.** Fetch with `npx --yes @primitive.ai/prim spec get <id> --text-only` before any partial edit.
252
- - **`npx --yes @primitive.ai/prim spec sync` rejects non-spec contexts** with "Context is not a spec document. Use `prim context` instead." Use `npx --yes @primitive.ai/prim spec list` to find spec IDs.
253
- - **`npx --yes @primitive.ai/prim context delete` is permanent.** Confirm with the user before deleting.
254
- - **Scope is set at creation.** To change it, delete and recreate the context.
255
- - **The hook silently excludes specs bound to other branches.** If you don't see a spec you expected to sync, check its `linkedBranches[]` via `npx --yes @primitive.ai/prim context get <id>` — it may be bound to a different branch. To re-bind, use the spec editor (no CLI subcommand in v1).
108
+ - **An "unavailable" / "not verified" gate or check is not an all-clear.** Treat constraints as UNKNOWN and proceed deliberately; never read the silence as approval.
109
+ - **A `deny` means a real prior decision conflicts.** Reconcile only when you genuinely intend to override it; otherwise pick an approach that respects it.
110
+ - **Reconcile bypasses are single-use and short-lived.** One bypass clears your *next* edit to the governed file; it is not a standing override.
111
+ - **Capture is automatic, never manual.** If decisions aren't showing up, check that the session hooks are installed (`claude status` / `codex status`) and the daemon is running — don't try to inject moves by hand.
112
+ - **Don't fabricate rationale on a confirmation.** If you don't know why a decision was made, say so rather than guessing.
256
113
 
257
114
  ## After each task
258
115
 
259
- Report the names and IDs you touched (spec, context, project) so the user can verify in the dashboard. If you ran `npx --yes @primitive.ai/prim spec sync`, remind the user it's async -- the project settles in the background.
116
+ If the conflict gate denied or warned you, report which decision(s) it named and whether you reconciled. If you read the graph before a load-bearing change, note what you found so the user can verify in the dashboard.
@@ -167,9 +167,7 @@ async function request(method, path, body, options) {
167
167
  function getClient() {
168
168
  return {
169
169
  get: (path, options) => request("GET", path, void 0, options),
170
- post: (path, body, options) => request("POST", path, body, options),
171
- patch: (path, body, options) => request("PATCH", path, body, options),
172
- delete: (path, options) => request("DELETE", path, void 0, options)
170
+ post: (path, body, options) => request("POST", path, body, options)
173
171
  };
174
172
  }
175
173
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getClient
3
- } from "./chunk-6SIEWWUL.js";
3
+ } from "./chunk-26VA3ADF.js";
4
4
  import {
5
5
  daemonRequest
6
6
  } from "./chunk-UTKQTZHL.js";
@@ -115,37 +115,8 @@ function formatDecisionsWarning(result) {
115
115
  return lines.join("\n");
116
116
  }
117
117
 
118
- // src/utils/git.ts
119
- import { execSync } from "child_process";
120
- function safeExec(cmd) {
121
- try {
122
- return execSync(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }).trim();
123
- } catch {
124
- return null;
125
- }
126
- }
127
- function parseRepoFullName(remoteUrl) {
128
- const match = remoteUrl.match(/(?:github\.com[:/])([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
129
- return match ? `${match[1]}/${match[2]}` : null;
130
- }
131
- function getGitContext() {
132
- const branchRaw = safeExec("git rev-parse --abbrev-ref HEAD");
133
- const branch = branchRaw && branchRaw !== "HEAD" ? branchRaw : null;
134
- const sha = safeExec("git rev-parse HEAD");
135
- const remoteUrl = safeExec("git remote get-url origin");
136
- const repoFullName = remoteUrl ? parseRepoFullName(remoteUrl) : null;
137
- let prNumber = null;
138
- if (safeExec("command -v gh")) {
139
- const raw = safeExec("gh pr view --json number -q .number");
140
- const n = raw ? Number.parseInt(raw, 10) : Number.NaN;
141
- if (Number.isFinite(n)) prNumber = n;
142
- }
143
- return { branch, sha, repoFullName, prNumber };
144
- }
145
-
146
118
  export {
147
119
  daemonOrDirectGet,
148
120
  checkAffectedDecisions,
149
- formatDecisionsWarning,
150
- getGitContext
121
+ formatDecisionsWarning
151
122
  };
@@ -3,7 +3,7 @@ import {
3
3
  getClient,
4
4
  getTokenExpiresAt,
5
5
  refreshToken
6
- } from "../chunk-6SIEWWUL.js";
6
+ } from "../chunk-26VA3ADF.js";
7
7
 
8
8
  // src/daemon/server.ts
9
9
  import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
@@ -5,7 +5,7 @@ import {
5
5
  } from "../chunk-BEEGFDGU.js";
6
6
  import {
7
7
  getClient
8
- } from "../chunk-6SIEWWUL.js";
8
+ } from "../chunk-26VA3ADF.js";
9
9
  import {
10
10
  scrubFromCwd
11
11
  } from "../chunk-6LAQVM26.js";