@invariant.guru/cli 0.5.5 → 0.6.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Invariant CLI
2
2
 
3
- A package manager for AI coding-agent context. Install, compose, and sync reusable agents, skills, commands, rules, contexts, and instructions into `.claude/`, `.cursor/`, and other CLI target folders.
3
+ A package manager for AI coding-agent context. Install, compose, and sync reusable agents, skills, commands, rules, contexts, and instructions. Every item is stored **once** in `.agents/` — the [Agent Skills](https://agentskills.io) standard most harnesses read natively — and each CLI target gets a view of it rather than its own copy.
4
4
 
5
5
  ## Requirements
6
6
 
@@ -42,7 +42,7 @@ invariant init claude cursor # multiple targets
42
42
  invariant init --name my-project
43
43
  ```
44
44
 
45
- Supported targets: `claude`, `codex`, `cursor`, `windsurf`, `aider`, `copilot`.
45
+ Supported targets: `claude`, `codex`, `cursor`, `aider`, `copilot`.
46
46
 
47
47
  ### 2. `invariant install` — pull a package
48
48
 
@@ -119,13 +119,20 @@ invariant add skill:nest-clean-architecture/implement-command \
119
119
 
120
120
  Check what landed with `invariant inspect nest-clean-architecture`, or use `invariant add-interactive` for a checkbox tree of every installed item.
121
121
 
122
- ### 4. `invariant sync` — write the files
122
+ ### 4. `invariant sync` — reconcile and write the files
123
123
 
124
- `sync` renders the active set into each configured target: `CLAUDE.md`, `.claude/agents/`, `.claude/skills/<name>/SKILL.md`, `.claude/commands/`, `.claude/rules/`, and the equivalents for other targets.
124
+ `sync` brings the whole tree back in line with `invariant.json`: it rebuilds
125
+ canonical items that went missing, materializes every active item for every
126
+ configured target, prunes what is no longer active, and regenerates the context
127
+ files (`CLAUDE.md`, `AGENTS.md`, …).
128
+
129
+ Add a target to `invariant.json`, run `sync`, and that target is set up — no need
130
+ to re-run `add`.
125
131
 
126
132
  ```bash
127
133
  invariant sync
128
134
  invariant sync --target claude
135
+ invariant sync --check # CI gate: exits 1 when the tree is stale
129
136
  ```
130
137
 
131
138
  `add`, `install`, and `add-interactive` all accept `-s, --sync` to do this in one shot:
@@ -144,12 +151,30 @@ invariant plan "implement the cargo booking command" --context nest-clean-archit
144
151
  invariant plan "implement the cargo booking command" --full
145
152
  ```
146
153
 
154
+ Every session file starts with a `<session-meta>` header carrying its title and
155
+ status (`draft` → `planned` → `in-progress` → `executed`). The agent updates it
156
+ as the work progresses; the UI reads it.
157
+
147
158
  When the session is done, stamp it:
148
159
 
149
160
  ```bash
150
161
  invariant plan:complete <session-id> --summary "Booking command + tests"
151
162
  ```
152
163
 
164
+ ### 6. `invariant ui` — see and manage your sessions
165
+
166
+ Opens a local dashboard for this project's sessions: a board grouped by status,
167
+ rendered markdown, a rich editor, and a command palette.
168
+
169
+ ```bash
170
+ invariant ui # start on 4200 (or the next free port) and open a browser
171
+ invariant ui status # every running instance on this machine
172
+ invariant ui stop # stop this project's instance
173
+ ```
174
+
175
+ Each directory gets its own instance on its own port, so several repositories can
176
+ be open at once without ever mixing sessions.
177
+
153
178
  ### Full walkthrough
154
179
 
155
180
  ```bash
@@ -158,6 +183,7 @@ invariant install github:invariant-guru/inv-nest-clean-architecture
158
183
  invariant add nest-clean-architecture # activate the whole module
159
184
  invariant sync
160
185
  invariant plan "add the cargo booking command"
186
+ invariant ui # follow it through to done
161
187
  ```
162
188
 
163
189
  ---
@@ -179,6 +205,8 @@ invariant init --hybrid
179
205
  |--------|-------------|
180
206
  | `-n, --name <name>` | Project name (defaults to directory name) |
181
207
  | `--hybrid` | Initialize as hybrid mode — project *and* package in one directory |
208
+ | `--copy` | Copy items into each target folder instead of linking them to `.agents/` |
209
+ | `--canonical-dir <dir>` | Canonical store location (default `.agents`) |
182
210
 
183
211
  ### `invariant install [packages...]`
184
212
 
@@ -306,7 +334,9 @@ invariant sync --target cursor
306
334
 
307
335
  | Option | Description |
308
336
  |--------|-------------|
309
- | `-t, --target <target>` | Sync only to a specific target (`claude`, `codex`, `cursor`, `windsurf`, `aider`, `copilot`) |
337
+ | `-t, --target <target>` | Sync only to a specific target (`claude`, `codex`, `cursor`, `aider`, `copilot`). Skips pruning — the other targets are out of scope |
338
+ | `--check` | Report drift without writing anything; exits `1` when out of sync |
339
+ | `--force` | Replace target files that were hand-edited away from the canonical item |
310
340
 
311
341
  ### `invariant inspect [package]`
312
342
 
@@ -370,7 +400,9 @@ invariant plan "implement user authentication" --context nest-clean-architecture
370
400
 
371
401
  ### `invariant plan:complete <session>`
372
402
 
373
- Stamp a completion header at the top of a finished session file.
403
+ Mark a session finished: sets `<status>` to `executed` and stamps `<summary>` and
404
+ `<completed>` in the session's `<session-meta>` header. Notes are appended to the
405
+ body as a **Completion notes** section.
374
406
 
375
407
  ```bash
376
408
  invariant plan:complete session-uuid --summary "Auth command + e2e tests"
@@ -383,6 +415,46 @@ invariant plan:complete session-uuid -n "Follow-up: rate limiting" -d 2026-08-19
383
415
  | `-n, --note <note>` | Extra note line (repeatable) |
384
416
  | `-d, --date <date>` | Completion date (`YYYY-MM-DD`), defaults to today |
385
417
 
418
+ ### `invariant ui [port]`
419
+
420
+ Start (or attach to) the local session UI for the current project, then open a
421
+ browser. One instance per directory; the default port is 4200 and the next free
422
+ port is used when it is taken.
423
+
424
+ ```bash
425
+ invariant ui # start and open a browser
426
+ invariant ui 4300 # ask for a specific port (fails if it is busy)
427
+ invariant ui --no-open # start without opening a browser
428
+ invariant ui status --json # machine-readable status of every instance
429
+ invariant ui stop --all # stop every instance on this machine
430
+ invariant ui migrate-headers # add <session-meta> headers to legacy sessions
431
+ ```
432
+
433
+ | Subcommand | Description |
434
+ |--------|-------------|
435
+ | *(none)* / `start [port]` | Start or attach, then open a browser |
436
+ | `stop` | Stop this project's instance (`--all` for every instance) |
437
+ | `status` | Every instance, liveness-checked (`--json`) |
438
+ | `migrate-headers` | Give legacy session files a canonical `<session-meta>` header |
439
+
440
+ | Option | Description |
441
+ |--------|-------------|
442
+ | `-p, --port <port>` | Port to listen on (default 4200) |
443
+ | `--no-open` | Do not open a browser window |
444
+
445
+ The server binds `127.0.0.1` only, checks `Host` and `Origin`, and requires a
446
+ per-instance token kept in `~/.invariant/ui.json` (mode 0600). What it can read
447
+ and write is limited to the directory it was started in.
448
+
449
+ In the UI: `⌘K` opens the command palette, `⇧⌘V` toggles rendered preview and
450
+ editing, `N` starts a session, `?` lists every shortcut.
451
+
452
+ To work on the UI itself: start a daemon (`invariant ui --no-open`), then run
453
+ `yarn dev:ui` for Vite with hot reload against it — `INVARIANT_UI_PORT=<port>`
454
+ when the daemon landed on something other than 4200.
455
+
456
+ See [docs/spec-ui.md](docs/spec-ui.md) for the header contract and the HTTP API.
457
+
386
458
  ### `invariant scan`
387
459
 
388
460
  Scan the codebase with embedded tree-sitter grammars and write a CodeGraph to `.invariant/codegraph/` — a structured inventory of files, languages, and top-level symbols for LLM navigation.
@@ -522,11 +594,64 @@ After `init` + `install` + `sync`:
522
594
  │ ├── contexts/ # rendered contexts
523
595
  │ ├── instructions/ # rendered instructions
524
596
  │ ├── sessions/ # `invariant plan` output
597
+ │ │ └── .archive/ # sessions archived from the UI
525
598
  │ └── codegraph/ # `invariant scan` output
599
+ ├── .agents/ # canonical store — the only physical copy
600
+ │ ├── skills/<name>/SKILL.md
601
+ │ ├── agents/<name>.md
602
+ │ ├── commands/<name>.md
603
+ │ └── rules/<name>.md
526
604
  ├── CLAUDE.md # generated by `invariant sync`
527
- └── .claude/
528
- ├── agents/<name>.md
529
- ├── skills/<name>/SKILL.md
605
+ └── .claude/ # symlinks into .agents/
606
+ ├── agents/<name>.md -> ../../.agents/agents/<name>.md
607
+ ├── skills/<name> -> ../../.agents/skills/<name>
530
608
  ├── commands/<name>.md
531
609
  └── rules/<name>.md
532
610
  ```
611
+
612
+ ### One copy, many views
613
+
614
+ `.agents/` holds the single physical copy of every activated item. What each
615
+ target gets depends on how it reads skills:
616
+
617
+ | Target | Skills | Agents / commands / rules |
618
+ |---|---|---|
619
+ | `claude` | symlink into `.agents/` | symlink into `.agents/` |
620
+ | `codex` | reads `.agents/skills/` — nothing written | embedded in `AGENTS.md` |
621
+ | `cursor` | reads `.agents/skills/` — nothing written | `.cursor/rules/<name>.mdc` |
622
+ | `copilot` | reads `.agents/skills/` — nothing written | `.github/instructions/<name>.instructions.md` |
623
+ | `aider` | embedded in `CONVENTIONS.md` | embedded in `CONVENTIONS.md` |
624
+
625
+ Two consequences worth knowing:
626
+
627
+ - Targets that speak the standard get **no invariant-written skill files**, so
628
+ they never read the same skill twice.
629
+ - Hand-written items you put in `.claude/skills/` yourself are never touched —
630
+ invariant only manages what is listed in `invariant.json → active`, plus links
631
+ that resolve into `.agents/`. A target file you edit by hand is kept, with a
632
+ warning, until you pass `--force`.
633
+
634
+ On hosts without symlink support the CLI falls back to a Windows junction, then
635
+ to a physical copy, and says which one it used. `invariant init --copy` (or
636
+ `"materialization": { "mode": "copy" }`) opts out of linking entirely.
637
+
638
+ ### Version control
639
+
640
+ `.agents/` and the target folders are **generated** — they are rebuilt by
641
+ `invariant add` and `invariant sync`, the way `node_modules` is rebuilt by a
642
+ package manager. `init` and `sync` keep them out of git via a delimited block:
643
+
644
+ ```gitignore
645
+ # --- invariant (generated, do not edit) ---
646
+ .agents/
647
+ .claude/agents/
648
+ .claude/skills/
649
+ .claude/commands/
650
+ .claude/rules/
651
+ CLAUDE.md
652
+ # --- end invariant ---
653
+ ```
654
+
655
+ Only paths invariant owns outright are listed, so a folder you share with it
656
+ (`.cursor/rules/`, which also holds your own rules) is left alone. Commit
657
+ `invariant.json`, run `invariant sync` after a clone.