tack-cli 0.1.0 → 0.1.2

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,209 +1,307 @@
1
- # tack
2
-
3
- Architecture drift guard. Declare your spec. Tack enforces it.
4
-
5
- ## Why Tack
6
-
7
- `tack` is a context and change-tracking layer for agent-driven software work.
8
-
9
- It gives agents and humans a shared project memory across sessions:
10
-
11
- - Captures architecture intent in `spec.yaml` and supporting context docs.
12
- - Detects architecture signals in code and tracks drift over time.
13
- - Generates handoff artifacts (`.md` + canonical `.json`) for the next agent/session.
14
- - Preserves machine history in append-only logs.
15
- - Supports explicit decision and note write-back for continuity.
16
-
17
- ## Persistent Context in `.tack/`
18
-
19
- All state lives in `./.tack/` so work survives restarts, agent changes, and handoffs:
20
-
21
- - `context.md`, `goals.md`, `assumptions.md`, `open_questions.md` - human intent and constraints.
22
- - `decisions.md` - durable decision history with reasoning.
23
- - `_notes.ndjson` - timestamped agent notes between sessions.
24
- - `spec.yaml` - declared architecture contract (allowed/forbidden systems, constraints, optional `domains` map).
25
- - `_audit.yaml` - latest detector snapshot.
26
- - `_drift.yaml` - unresolved/accepted/rejected drift items.
27
- - `_logs.ndjson` - append-only machine event stream.
28
- - `handoffs/*.md` and `handoffs/*.json` - transfer artifacts for the next session.
29
- - `verification.md` - validation steps carried into handoffs.
30
-
31
- Agents and tools consume this state via:
32
-
33
- - The `tack-mcp` server (Model Context Protocol), which exposes context resources and write-back tools.
34
- - Direct file access to `.tack/`, where human-authored docs and machine-managed state live together.
35
-
36
- ## Change Tracking Workflow
37
-
38
- - `tack status` updates `_audit.yaml` and computes drift against your spec.
39
- - `tack watch` continuously rescans and appends events to `_logs.ndjson`.
40
- - `tack handoff` packages context + machine state + git deltas for the next session.
41
- - `tack log` and `tack note` store decisions and notes that future agents can reuse.
42
-
43
- ## Install
44
-
45
- ```bash
46
- npm install
47
- npm run build
48
- ```
49
-
50
- Optional global/local CLI use:
51
-
52
- ```bash
53
- npm link
54
- # now `tack` is available globally on this machine
55
- ```
56
-
57
- Or package for use in another project:
58
-
59
- ```bash
60
- npm pack
61
- # then install the tarball in another project if desired
62
- ```
63
-
64
- ## Usage
65
-
66
- From any project directory:
67
-
68
- ```bash
69
- node /absolute/path/to/tack/dist/index.js init
70
- node /absolute/path/to/tack/dist/index.js status
71
- node /absolute/path/to/tack/dist/index.js watch
72
- node /absolute/path/to/tack/dist/index.js handoff
73
- node /absolute/path/to/tack/dist/index.js mcp
74
- ```
75
-
76
- Within the `tack` repo itself:
77
-
78
- ```bash
79
- node dist/index.js help
80
- ```
81
-
82
- ## `tack watch` Preview
83
-
84
- ![tack watch terminal preview](./tackpreview.png)
85
-
86
- ## Typical Multi-Session Loop
87
-
88
- ```bash
89
- # Session start
90
- tack status
91
-
92
- # During work
93
- tack watch
94
-
95
- # Record key intent changes
96
- tack log
97
- tack note
98
-
99
- # Session end
100
- tack handoff
101
- ```
102
-
103
- ## Using Tack with Agents
104
-
105
- Tack treats LLM agents as **clients of a deterministic engine**. Agents should read context from `.tack/` and write back through the documented channels instead of mutating machine-managed files directly.
106
-
107
- ### MCP (Model Context Protocol)
108
-
109
- **Run the MCP server:** From a project that has `.tack/`, run:
110
-
111
- ```bash
112
- tack mcp
113
- ```
114
-
115
- If `tack` is on your PATH (e.g. `npm link` from the tack clone), that’s all you need. Or: `node /path/to/tack/dist/index.js mcp`. The server reads `.tack/` from the current working directory, so run it from your **project root**.
116
-
117
- **Cursor MCP:** Add an MCP server in Cursor (Settings → Tools & MCP) with command `tack`, args `["mcp"]`, and **cwd** = your project root (the directory that contains `.tack/`). If `tack` isn’t on PATH, use command `node`, args `["/path/to/tack/dist/index.js", "mcp"]`, cwd = project root. Restart Cursor after changing MCP config.
118
-
119
- The server (`tack-mcp`) exposes these key resources:
120
-
121
- - `tack://context/intent` `context.md`, `goals.md`, `open_questions.md`, `decisions.md`
122
- - `tack://context/facts` – `implementation_status.md` and `spec.yaml`
123
- - `tack://context/machine_state` – `_audit.yaml` and `_drift.yaml`
124
- - `tack://context/decisions_recent` – recent decisions as markdown
125
- - `tack://handoff/latest` – latest handoff JSON (`.tack/handoffs/*.json`)
126
-
127
- And these tools for write-back:
128
-
129
- - `log_decision` – append a decision to `.tack/decisions.md` and log a `decision` event
130
- - `log_agent_note` append an agent note to `.tack/_notes.ndjson`
131
-
132
- ### Direct File Access
133
-
134
- Agents without MCP should:
135
-
136
- - **Read**:
137
- - `.tack/spec.yaml` — architecture guardrails
138
- - `.tack/context.md`, `.tack/goals.md`, `.tack/assumptions.md`, `.tack/open_questions.md`
139
- - `.tack/implementation_status.md`
140
- - `.tack/_audit.yaml`, `.tack/_drift.yaml`
141
- - `.tack/verification.md` — validation/verification steps to run after changes
142
- - `.tack/handoffs/*.json`, `.tack/handoffs/*.md`
143
- - `.tack/_notes.ndjson` — agent working notes (NDJSON)
144
- - **Write back**:
145
- - Append decisions to `.tack/decisions.md`: `- [YYYY-MM-DD] Decision — reason`
146
- - Use the CLI to log notes: `tack note --message "..." --type discovered --actor agent:cursor`
147
- - Or append NDJSON lines manually to `.tack/_notes.ndjson` if the CLI is not available
148
-
149
- Do **not** modify `.tack/_drift.yaml`, `.tack/_audit.yaml`, or `.tack/_logs.ndjson` directly; they are machine-managed.
150
-
151
- ## Detectors and YAML rules
152
-
153
- Detection is **YAML-driven**. Bundled rules live in `src/detectors/rules/*.yaml` and are shipped with the CLI. At runtime we also load any `*.yaml` from `.tack/detectors/` (optional project extension).
154
-
155
- Each rule file uses this schema:
156
-
157
- - **Top-level:** `name`, `displayName`, `signalId`, `category` (`system` | `scope` | `risk`).
158
- - **`systems`:** list of entries, each with:
159
- - `id` — system identifier (e.g. `nextjs`, `prisma`, `stripe`)
160
- - `packages` — npm package names that imply this system
161
- - `configFiles` — paths to look for (e.g. `next.config.js`)
162
- - `directories` — optional dirs (e.g. `src/jobs`)
163
- - `routePatterns` optional regex strings to grep in project files
164
-
165
- If any of packages/configFiles/directories/routePatterns match for a system, one signal is emitted (confidence 1). Invalid YAML or bad regex is skipped without failing the scan. The only detectors still implemented in TypeScript are `multiuser`, `admin`, and `duplicates`; all other primary systems (framework, auth, db, payments, background_jobs, exports) are defined in YAML.
166
-
167
- ## Commands
168
-
169
- ### `init`
170
-
171
- - Runs a detector sweep
172
- - Prompts you to classify detected systems as allowed/forbidden/skip
173
- - Writes initial files under `./.tack/`
174
-
175
- ### `status`
176
-
177
- - Runs a one-shot scan
178
- - Updates `./.tack/_audit.yaml`
179
- - Computes drift and prints summary
180
-
181
- ### `watch`
182
-
183
- - Starts persistent file watching
184
- - Re-scans on file changes
185
- - Creates drift items for new violations/risks/undeclared systems
186
- - Sends OS notifications for violations and risks
187
- - Press `q` to quit
188
-
189
- ### `handoff`
190
-
191
- - Reads context docs + current machine state
192
- - Reads file-level git changes
193
- - Writes `./.tack/handoffs/<timestamp>.md`
194
- - Writes `./.tack/handoffs/<timestamp>.json` (canonical)
195
- - Includes a **Validation / Verification** section driven by `.tack/verification.md`:
196
- - Each bullet/numbered item becomes a `verification.steps` entry in JSON and a markdown bullet
197
- - Intended for humans or external tools to know which commands/checks to run after applying the handoff
198
- - Tack does **not** execute these commands automatically
199
-
200
- ## Keyboard Controls
201
-
202
- In selection prompts (`init`, drift options):
203
-
204
- - `↑` / `↓` to move
205
- - `Enter` to confirm
206
-
1
+ # tack
2
+
3
+ [![npm version](https://img.shields.io/npm/v/tack-cli.svg)](https://www.npmjs.com/package/tack-cli) [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4
+
5
+ Architecture drift guard. You declare the spec; Tack checks your code against it.
6
+
7
+ ## Why Tack
8
+
9
+ `tack` keeps a single, shared picture of your architecture and how it changes over time.
10
+
11
+ It gives agents and humans a shared project memory that survives across sessions:
12
+
13
+ - Captures your intended architecture in `spec.yaml` and a small set of context docs.
14
+ - Detects architecture signals in code and tracks drift from the spec over time.
15
+ - Generates handoff artifacts (`.md` + canonical `.json`) for the next agent or session.
16
+ - Preserves machine history in append-only logs instead of ad-hoc console output.
17
+ - Records explicit decisions and notes so future sessions can see why changes happened.
18
+
19
+ ## Persistent Context in `.tack/`
20
+
21
+ All Tack state lives in `./.tack/`, so you can stop and resume work (or swap agents) without losing context:
22
+
23
+ - `context.md`, `goals.md`, `assumptions.md`, `open_questions.md` human-written intent and constraints.
24
+ - `decisions.md` – append-only decision history with a short reason for each choice.
25
+ - `_notes.ndjson` timestamped agent notes between sessions (newline-delimited JSON).
26
+ - `spec.yaml` your architecture contract: allowed/forbidden systems, constraints, optional `domains` map.
27
+ - `_audit.yaml` latest detector snapshot of what the codebase actually does.
28
+ - `_drift.yaml` unresolved/accepted/rejected drift items between spec and reality.
29
+ - `_logs.ndjson` – append-only machine event stream (what Tack saw and when).
30
+ - `handoffs/*.md` and `handoffs/*.json` – handoff packages for the next session.
31
+ - `verification.md` validation steps that get pulled into handoffs.
32
+
33
+ Agents and tools read and write this state in two main ways:
34
+
35
+ - Through the `tack-mcp` server (Model Context Protocol), which exposes typed context resources and safe write-back tools.
36
+ - By reading and appending to files under `.tack/`, where human-authored docs and machine-managed state live side by side.
37
+
38
+ ## Change Tracking Workflow
39
+
40
+ - `tack status` runs a scan, updates `_audit.yaml`, and computes drift against your spec.
41
+ - `tack watch` continuously rescans on file changes and appends events to `_logs.ndjson`.
42
+ - `tack handoff` packages context + machine state + git deltas for the next session.
43
+ - `tack log` and `tack note` store decisions and notes that future agents and humans can reuse.
44
+
45
+ ## Install from npm
46
+
47
+ Use Tack in any project without cloning:
48
+
49
+ **Run without installing (npx):**
50
+
51
+ ```bash
52
+ npx tack-cli init
53
+ npx tack-cli status
54
+ npx tack-cli handoff
55
+ ```
56
+
57
+ **Or install in your project (local):**
58
+
59
+ ```bash
60
+ npm install tack-cli
61
+ npx tack-cli init
62
+ # or: ./node_modules/.bin/tack init
63
+ ```
64
+
65
+ **Or install globally:**
66
+
67
+ ```bash
68
+ npm install -g tack-cli
69
+ tack init
70
+ tack status
71
+ tack handoff
72
+ ```
73
+
74
+ > **Note:** If global install on Windows fails with `EEXIST` or cleanup errors, remove any existing `tack` or `tack-cli` in `npm root -g`, or use `npx tack-cli` instead.
75
+
76
+ ## Build from source
77
+
78
+ To develop or contribute:
79
+
80
+ ```bash
81
+ npm install
82
+ npm run build
83
+ ```
84
+
85
+ Optional global link for local development:
86
+
87
+ ```bash
88
+ npm link
89
+ # now `tack` is available globally on this machine
90
+ ```
91
+
92
+ Or package for use in another project:
93
+
94
+ ```bash
95
+ npm pack
96
+ # then install the tarball in another project if desired
97
+ ```
98
+
99
+ ## Usage
100
+
101
+ From any project directory:
102
+
103
+ ```bash
104
+ node /absolute/path/to/tack/dist/index.js init
105
+ node /absolute/path/to/tack/dist/index.js status
106
+ node /absolute/path/to/tack/dist/index.js watch
107
+ node /absolute/path/to/tack/dist/index.js handoff
108
+ node /absolute/path/to/tack/dist/index.js mcp
109
+ ```
110
+
111
+ Within the `tack` repo itself:
112
+
113
+ ```bash
114
+ node dist/index.js help
115
+ ```
116
+
117
+ ## `tack watch` Preview
118
+
119
+ ![tack watch MCP activity preview](./tack-mcp.png)
120
+
121
+ ## Typical Multi-Session Loop
122
+
123
+ ```bash
124
+ # Session start
125
+ tack status
126
+
127
+ # During work
128
+ tack watch
129
+
130
+ # Record key intent changes
131
+ tack log
132
+ tack note
133
+
134
+ # Session end
135
+ tack handoff
136
+ ```
137
+
138
+ ## Project Root Rules
139
+
140
+ Tack looks for the nearest ancestor directory that contains `.tack/` and treats that as the project root. This means you can run `tack status`, `tack watch`, `tack handoff`, `tack log`, `tack note`, and `tack diff` from subdirectories inside an initialized project.
141
+
142
+ If no `.tack/` directory exists in the current directory or any parent, Tack will not try to guess a sibling project. Run Tack from the project root you actually want, or initialize a new project there:
143
+
144
+ ```bash
145
+ cd /path/to/your/project
146
+ tack init
147
+ ```
148
+
149
+ Legacy migration from `./tack/` to `./.tack/` only happens when that directory looks like old Tack state, not when it is just a separate folder named `tack`.
150
+
151
+ ## Using Tack with Agents
152
+
153
+ Tack exposes a small, deterministic engine that agents call into (same inputs same outputs, no hidden network calls). Agents should read context from `.tack/` and write back only through the documented channels instead of editing machine-managed files directly.
154
+
155
+ ### MCP (Model Context Protocol)
156
+
157
+ **Run the MCP server:** From a project that has `.tack/`, run:
158
+
159
+ ```bash
160
+ tack mcp
161
+ ```
162
+
163
+ If `tack` is on your PATH (for example after `npm install -g tack-cli` or `npm link` from the Tack repo), that’s all you need. Or run `node /path/to/tack/dist/index.js mcp`. The server reads `.tack/` from the current working directory, so always run it from your **project root**.
164
+
165
+ **Cursor:** In Cursor (Settings Tools & MCP), add an MCP server with command `tack`, args `["mcp"]`, and **cwd** set to your project root (the directory that contains `.tack/`). If `tack` isn’t on PATH, use command `node` with args `["/path/to/tack/dist/index.js", "mcp"]`, cwd = project root. Restart Cursor after changing MCP config.
166
+
167
+ **Codex CLI:** Add the Tack MCP server to Codex:
168
+
169
+ ```bash
170
+ # With tack-cli on PATH (for example after npm install -g tack-cli)
171
+ codex mcp add tack -- tack mcp
172
+
173
+ # With a local build of this repo
174
+ codex mcp add tack -- node /path/to/tack/dist/index.js mcp
175
+ ```
176
+
177
+ Then verify it:
178
+
179
+ ```bash
180
+ codex mcp get tack
181
+ codex mcp list
182
+ ```
183
+
184
+ Tack reads `.tack/` from the current working directory, and Codex launches MCP servers relative to the Codex session cwd. Start Codex from your **project root** (the directory that contains `.tack/`), for example:
185
+
186
+ ```bash
187
+ cd /path/to/your/project
188
+ codex
189
+ ```
190
+
191
+ Or:
192
+
193
+ ```bash
194
+ codex -C /path/to/your/project
195
+ ```
196
+
197
+ If you update Tack from source, rebuild it with `npm run build` so `dist/index.js` stays current.
198
+
199
+ **Claude Code:** From your project root (the directory that contains `.tack/`), add the Tack MCP server:
200
+
201
+ ```bash
202
+ # With tack-cli on PATH (e.g. npm install -g tack-cli)
203
+ claude mcp add --transport stdio tack-mcp -- tack mcp
204
+
205
+ # With npx (no global install)
206
+ claude mcp add --transport stdio tack-mcp -- npx tack-cli mcp
207
+ ```
208
+
209
+ On **Windows (native, not WSL)** use the `cmd /c` wrapper for npx:
210
+
211
+ ```bash
212
+ claude mcp add --transport stdio tack-mcp -- cmd /c npx tack-cli mcp
213
+ ```
214
+
215
+ Then run `/mcp` in Claude Code to confirm the server is connected. Tack reads `.tack/` from the current working directory, so open your project folder in Claude Code so the server runs with the correct cwd.
216
+
217
+ The server (`tack-mcp`) exposes these key resources:
218
+
219
+ - `tack://context/intent` – `context.md`, `goals.md`, `open_questions.md`, `decisions.md`
220
+ - `tack://context/facts` – `implementation_status.md` and `spec.yaml`
221
+ - `tack://context/machine_state` – `_audit.yaml` and `_drift.yaml`
222
+ - `tack://context/decisions_recent` – recent decisions as markdown
223
+ - `tack://handoff/latest` – latest handoff JSON (`.tack/handoffs/*.json`)
224
+
225
+ And these tools for safe write-back:
226
+
227
+ - `log_decision` – appends a decision to `.tack/decisions.md` and logs a `decision` event
228
+ - `log_agent_note` – appends an agent note to `.tack/_notes.ndjson`
229
+
230
+ ### Direct File Access
231
+
232
+ Agents without MCP should:
233
+
234
+ - **Read**:
235
+ - `.tack/spec.yaml` — architecture guardrails
236
+ - `.tack/context.md`, `.tack/goals.md`, `.tack/assumptions.md`, `.tack/open_questions.md`
237
+ - `.tack/implementation_status.md`
238
+ - `.tack/_audit.yaml`, `.tack/_drift.yaml`
239
+ - `.tack/verification.md` — validation/verification steps to run after changes
240
+ - `.tack/handoffs/*.json`, `.tack/handoffs/*.md`
241
+ - `.tack/_notes.ndjson` — agent working notes (NDJSON)
242
+ - **Write back**:
243
+ - Append decisions to `.tack/decisions.md` in this format: `- [YYYY-MM-DD] Decision — reason`
244
+ - Prefer the CLI for notes: `tack note --message "..." --type discovered --actor agent:cursor`
245
+ - If the CLI is not available, append NDJSON lines manually to `.tack/_notes.ndjson`
246
+
247
+ Do **not** modify `.tack/_drift.yaml`, `.tack/_audit.yaml`, or `.tack/_logs.ndjson` directly; they are machine-managed and may be overwritten at any time.
248
+
249
+ ## Detectors and YAML rules
250
+
251
+ Detection is **YAML-driven**. Bundled rules live in `src/detectors/rules/*.yaml` and ship with the CLI. At runtime Tack also loads any `*.yaml` from `.tack/detectors/` so projects can add or override detectors.
252
+
253
+ Each rule file uses this schema:
254
+
255
+ - **Top-level:** `name`, `displayName`, `signalId`, `category` (`system` | `scope` | `risk`).
256
+ - **`systems`:** list of entries, each with:
257
+ - `id` — system identifier (for example `nextjs`, `prisma`, `stripe`)
258
+ - `packages` — npm package names that imply this system
259
+ - `configFiles` — config files to look for (for example `next.config.js`)
260
+ - `directories` — optional directories (for example `src/jobs`)
261
+ - `routePatterns` — optional regex strings to grep in project files
262
+
263
+ If any of `packages` / `configFiles` / `directories` / `routePatterns` match for a system, one signal is emitted (confidence 1). Invalid YAML or bad regex is skipped without failing the scan. The only detectors still implemented in TypeScript are `multiuser`, `admin`, and `duplicates`; all other primary systems (framework, auth, db, payments, background_jobs, exports) are defined in YAML.
264
+
265
+ ## Commands
266
+
267
+ ### `init`
268
+
269
+ - Runs a detector sweep
270
+ - Prompts you to classify detected systems as allowed/forbidden/skip
271
+ - Writes initial files under `./.tack/`
272
+
273
+ ### `status`
274
+
275
+ - Runs a one-shot scan
276
+ - Updates `./.tack/_audit.yaml`
277
+ - Computes drift and prints summary
278
+
279
+ ### `watch`
280
+
281
+ - Starts persistent file watching
282
+ - Re-scans on file changes
283
+ - Creates drift items for new violations/risks/undeclared systems
284
+ - Sends OS notifications for violations and risks
285
+ - Press `q` to quit
286
+
287
+ ### `handoff`
288
+
289
+ - Reads context docs + current machine state
290
+ - Reads file-level git changes
291
+ - Writes `./.tack/handoffs/<timestamp>.md`
292
+ - Writes `./.tack/handoffs/<timestamp>.json` (canonical)
293
+ - Includes a **Validation / Verification** section driven by `.tack/verification.md`:
294
+ - Each bullet/numbered item becomes a `verification.steps` entry in JSON and a markdown bullet
295
+ - Intended for humans or external tools to know which commands/checks to run after applying the handoff
296
+ - Tack does **not** execute these commands automatically
297
+
298
+ ## Keyboard Controls
299
+
300
+ In selection prompts (`init`, drift options):
301
+
302
+ - `↑` / `↓` to move
303
+ - `Enter` to confirm
304
+
207
305
  ## Development
208
306
 
209
307
  ```bash
@@ -223,10 +321,9 @@ Optional Bun source-run for contributors who have Bun:
223
321
  ```bash
224
322
  npm run dev:bun
225
323
  ```
226
-
227
- ## Notes
228
-
229
- - Offline-only (no network calls)
230
- - Writes are guarded to `./.tack/` only
231
- - Python virtual environments are ignored during scans (`venv`, `.venv`, `site-packages`) to avoid false positives
232
-
324
+
325
+ ## Notes
326
+
327
+ - Offline-only (no network calls)
328
+ - Writes are guarded to `./.tack/` only
329
+ - Python virtual environments are ignored during scans (`venv`, `.venv`, `site-packages`) to avoid false positives
@@ -65,7 +65,7 @@ export function parseDecisionsMarkdown(content, file = ".tack/decisions.md") {
65
65
  const line = (lines[i] ?? "").trim();
66
66
  if (!line.startsWith("- "))
67
67
  continue;
68
- const m = line.match(/^-\s*\[(\d{4}-\d{2}-\d{2})\]\s*(.+?)\s*—\s*(.+)$/);
68
+ const m = line.match(/^-\s*\[(\d{4}-\d{2}-\d{2})\]\s*(.+?)\s*(?:—|–|--|-)\s*(.+)$/);
69
69
  if (!m)
70
70
  continue;
71
71
  out.push({