@marver-design/marver 0.20.0 → 0.22.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 +123 -0
- package/README.md +17 -4
- package/dist/{bake-tAb0D6Rc.mjs → bake-BSX4XR_U.mjs} +1 -1
- package/dist/board-status-CWGHIdo_.mjs +1307 -0
- package/dist/boards-BTGNPVMx.mjs +187 -0
- package/dist/{build-DwpNPl6Z.mjs → build-Dd2Qm3OG.mjs} +87 -16
- package/dist/cli.mjs +67 -8
- package/dist/config-DJxMRVD8.mjs +373 -0
- package/dist/context-DUAENlJ6.mjs +600 -0
- package/dist/{daemon-DbHvLQUL.mjs → daemon-BmkwErpC.mjs} +1 -1
- package/dist/{dev-BjdDP69b.mjs → dev-BW7a5kDF.mjs} +8 -6
- package/dist/{init-DKxuRxBr.mjs → init-NJ3xjLVu.mjs} +39 -44
- package/dist/managed-write-Bo-oPc-i.mjs +71 -0
- package/dist/{manifest-B01PSyDc.mjs → manifest-BqBcMJcd.mjs} +26 -380
- package/dist/{plugin-y4Ch7o_A.mjs → plugin-8XntSCx_.mjs} +234 -97
- package/dist/{poster-FCv_nXyP.mjs → poster-DRZDszTI.mjs} +1 -1
- package/dist/{publish-bakes-XH6Bac58.mjs → publish-bakes-CCWRV9iX.mjs} +2 -2
- package/dist/{shot-iw3SEcpn.mjs → shot-C22Ues04.mjs} +2 -2
- package/docs/boards-and-folders.md +161 -0
- package/docs/context.md +117 -0
- package/docs/sharing.md +12 -2
- package/package.json +1 -1
- package/src/client/shell/BoardList.tsx +143 -54
- package/src/client/shell/ContextMenu.tsx +16 -5
- package/src/client/shell/StatusPicker.tsx +91 -0
- package/src/client/shell/board-icons.tsx +75 -0
- package/src/client/shell/store.ts +93 -14
- package/src/client/shell/styles.css +41 -9
- package/src/shared/board-tree.ts +291 -143
- package/src/shared/board-types.ts +103 -0
- package/src/shared/context.ts +265 -0
- package/src/shared/status.ts +157 -0
- package/templates/AGENTS-embedded.md +4 -3
- package/templates/AGENTS-studio.md +4 -3
- package/templates/context/INDEX.md +50 -0
- package/templates/context/map.json +6 -0
- package/templates/context/shipped-knowledge.md +19 -0
- package/templates/context/shipped.md +28 -0
- package/templates/instructions/boards.md +78 -22
- package/templates/instructions/context.md +114 -0
- package/templates/playbooks/publish-canvas/PLAYBOOK.md +72 -0
- package/templates/playbooks/reorganize-context/PLAYBOOK.md +232 -0
- package/templates/playbooks/reorganize-context/eval.md +93 -0
- package/dist/boards-BmxcT3Lc.mjs +0 -290
- package/dist/boards-PuVzw5Wp.mjs +0 -62
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: record
|
|
3
|
+
audience: team
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Shipped - what runs where, and what is available to whom
|
|
7
|
+
|
|
8
|
+
The only file that says what is available. Every evidence cell carries its level, and `confirmed`
|
|
9
|
+
and `reported` carry a citation:
|
|
10
|
+
|
|
11
|
+
- `confirmed` - observed in a system of record: the deploy run whose deploy step succeeded for that
|
|
12
|
+
service, a ci run that executed the suite. An environment marked "deployed" is not proof on its
|
|
13
|
+
own - some pipelines mark it when the run stood down.
|
|
14
|
+
- `reported` - a written claim, cited: a changelog line, an ops note.
|
|
15
|
+
- `unknown` - neither, with the reason. An honest unknown is the right answer.
|
|
16
|
+
|
|
17
|
+
Commit ancestry says a change is inside a revision, not that the revision is running.
|
|
18
|
+
|
|
19
|
+
## Services × environments
|
|
20
|
+
|
|
21
|
+
| Service | Environment | Revision | Deployed at | How | Evidence |
|
|
22
|
+
|---|---|---|---|---|---|
|
|
23
|
+
| app | production | - | - | - | `unknown` - nothing recorded yet |
|
|
24
|
+
|
|
25
|
+
## Capabilities
|
|
26
|
+
|
|
27
|
+
| Capability | Implemented | Verified | Available | Contract |
|
|
28
|
+
|---|---|---|---|---|
|
|
@@ -62,23 +62,33 @@ viewport and lays it out:
|
|
|
62
62
|
|
|
63
63
|
## Folders - organising the sidebar
|
|
64
64
|
|
|
65
|
-
Boards can sit in folders,
|
|
66
|
-
|
|
65
|
+
Boards can sit in folders, two levels deep: a folder holds boards and folders, a folder
|
|
66
|
+
inside a folder (a **sub-folder**) holds boards only. A board can sit at the root, in a
|
|
67
|
+
folder, or in a sub-folder. Files are the truth, and two files carry it:
|
|
67
68
|
|
|
68
69
|
- **Membership lives on the board**: `"folder": "research"` in the board file, next
|
|
69
|
-
to `order
|
|
70
|
-
|
|
70
|
+
to `order` - always the ONE folder it sits in directly, at either level (a board in a
|
|
71
|
+
sub-folder names the sub-folder, never a path). `order` then ranks it among its
|
|
72
|
+
siblings: at every level, the boards and folders there share one sequence (the root's
|
|
73
|
+
boards and top-level folders; a folder's boards and sub-folders; a sub-folder's boards). Same grammar as board names
|
|
71
74
|
(`^[a-z0-9][a-z0-9-]*$`); an invalid value means top level. `all-scenes` never
|
|
72
75
|
lives in a folder.
|
|
73
76
|
- **Folders live in `design/boards/_folders.json`** - the underscore marks it as
|
|
74
77
|
infrastructure, never a board:
|
|
75
78
|
|
|
76
79
|
```json
|
|
77
|
-
{ "version":
|
|
80
|
+
{ "version": 2, "folders": [
|
|
78
81
|
{ "name": "research", "order": 1, "title": "R&D", "description": "The thinking behind the live boards - specs, flows, references" },
|
|
82
|
+
{ "name": "flows", "parent": "research", "order": 2, "description": "One board per user flow" },
|
|
79
83
|
{ "name": "archive", "order": 3, "description": "Retired directions and scene versions, oldest first" } ] }
|
|
80
84
|
```
|
|
81
85
|
|
|
86
|
+
**Nesting lives here only**: a sub-folder's entry carries `"parent": "<folder>"`, and the
|
|
87
|
+
file says `"version": 2` while any entry has a parent (`"version": 1` when none does - an
|
|
88
|
+
older Marver can read that, and refuses a version-2 file rather than lose its nesting).
|
|
89
|
+
A parent must itself be a registered top-level folder; a sub-folder never holds a
|
|
90
|
+
folder. Folder names are unique across both levels.
|
|
91
|
+
|
|
82
92
|
A folder's `name` is its slug - the identity its boards point at with `folder`; its
|
|
83
93
|
`title` (optional, free text) is what humans see, exactly as on a board; its
|
|
84
94
|
`description` says what belongs in it - the next session files boards right without
|
|
@@ -87,7 +97,8 @@ Files are the truth, and two files carry it:
|
|
|
87
97
|
It exists so an EMPTY folder can exist and so a folder has a rank at the root.
|
|
88
98
|
A folder a board names but the registry lacks is still real (it sorts after the
|
|
89
99
|
ranked items, by name) - two boards with `"folder": "research"` make a Research
|
|
90
|
-
folder on their own.
|
|
100
|
+
folder on their own. Such an implied folder is always top-level: to nest it, register
|
|
101
|
+
it with its `parent`. A malformed registry is an error the canvas shows, not an
|
|
91
102
|
empty one - fix it, never delete it.
|
|
92
103
|
|
|
93
104
|
**Look before you organise: `npx marver boards`** prints the sidebar as the files say
|
|
@@ -99,39 +110,78 @@ have rearranged things since you last looked, and their arrangement stands.
|
|
|
99
110
|
The moves, each a file edit, so the files always agree:
|
|
100
111
|
- **Create** a folder: add `{ "name": "<slug>", "order": <n>, "description": "…" }`
|
|
101
112
|
to the registry's `folders` (create the file if absent) - or just point a board at it.
|
|
102
|
-
|
|
103
|
-
among that folder's boards
|
|
104
|
-
|
|
113
|
+
**Create a sub-folder**: the same entry with `"parent": "<top-level folder>"`, its
|
|
114
|
+
`order` among that folder's boards and sub-folders, and `"version": 2` on the file.
|
|
115
|
+
- **Move a folder in or out**: set its `parent` (only a folder with no sub-folders of its
|
|
116
|
+
own can move into another - never three levels) or delete it; re-rank the siblings you
|
|
117
|
+
touch, and set `"version"` to 2 while any parent remains, 1 when none does.
|
|
118
|
+
- **Move a board in**: write `"folder": "<slug>"` on the board - any folder, at either
|
|
119
|
+
level - and give it an `order` among that folder's boards and sub-folders. **Move it
|
|
120
|
+
out**: delete the `folder` field and give it an `order` among the top-level items.
|
|
105
121
|
- **Rank** folders and boards: `order` on the board (among its siblings) and on the
|
|
106
122
|
registry entry (among the top-level items). Renumber the siblings you touch.
|
|
107
123
|
- **Retitle** a folder (or a board): set `title` on the registry entry (on the board
|
|
108
124
|
file). **Rename a slug** - a folder's `name`, a board's file name - only when asked,
|
|
109
|
-
and as one refactor: a folder slug is on every member's `folder` field
|
|
110
|
-
all, AND the registry entry - a registry rename
|
|
111
|
-
|
|
125
|
+
and as one refactor: a folder slug is on every member's `folder` field and on
|
|
126
|
+
every sub-folder's `parent` (rewrite them all, AND the registry entry - a registry rename
|
|
127
|
+
alone leaves the members in the old, implied folder and the sub-folders pointing at a
|
|
128
|
+
parent that no longer exists); a board file name is in `publish.json`, in its comment threads and in
|
|
112
129
|
every path anyone copied. A title does what a rename usually wanted.
|
|
113
|
-
- **Delete** a folder:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
130
|
+
- **Delete** a folder: what it holds moves up one level, into its place - a top-level
|
|
131
|
+
folder's boards lose `folder` and its sub-folders lose `parent` (they become top-level
|
|
132
|
+
folders, keeping their boards); a sub-folder's boards take its parent as their `folder`.
|
|
133
|
+
Then remove its registry entry and re-rank the level it emptied into. Folders organise,
|
|
134
|
+
never own: deleting one never deletes a board.
|
|
135
|
+
- The **landing board** is the first board in sidebar order, reading down through
|
|
136
|
+
folders and sub-folders - rank a folder first and its first board opens the canvas.
|
|
117
137
|
|
|
118
138
|
Use folders proactively, the way a tidy studio would: a canvas past six or eight
|
|
119
139
|
boards wants grouping - the live feature boards at the top level, `research` /
|
|
120
140
|
`specs` for the thinking, `decks` for slides, `archive` for history and versions
|
|
121
|
-
last.
|
|
141
|
+
last. Reach for a sub-folder when a folder itself grows past six or eight boards and
|
|
142
|
+
splits naturally (features by surface, archive by year) - not before; one level reads
|
|
143
|
+
faster than two. Propose the grouping in one sentence and do it; keep folder names short and
|
|
122
144
|
plain.
|
|
123
145
|
|
|
124
146
|
The human does all of this too - from the sidebar: New folder (right-click the Boards
|
|
125
|
-
header, or its `+`),
|
|
126
|
-
folder,
|
|
127
|
-
|
|
147
|
+
header, or its `+`), New folder inside (a top-level folder's menu), Rename (the title -
|
|
148
|
+
slugs never move from the sidebar), Delete folder, Move to top level (a board in a folder,
|
|
149
|
+
a sub-folder), Move to new folder (a board), and DRAG: boards into and out of folders at
|
|
150
|
+
either level, folders among boards and - when they hold no sub-folders - into a top-level
|
|
151
|
+
folder. Each drag rewrites `order` (and
|
|
128
152
|
`folder`) on the boards it touches and the registry - the shell owns those fields
|
|
129
153
|
while the canvas is open, exactly as it owns `order`; write membership and new
|
|
130
154
|
folders freely, and never rewrite an arrangement the human just made. The shell
|
|
131
155
|
refuses a write that would overwrite an edit it has not seen (your file write and
|
|
132
156
|
the human's drag can never silently erase each other), so read a board file before
|
|
133
|
-
you rewrite it. Published canvases show the folders of the published boards only
|
|
134
|
-
folder with nothing published never reaches
|
|
157
|
+
you rewrite it. Published canvases show the folders of the published boards only - a
|
|
158
|
+
sub-folder's parent included; a folder with nothing published at any depth never reaches
|
|
159
|
+
the bundle.
|
|
160
|
+
|
|
161
|
+
## Types and status - what a board is for, and where it stands
|
|
162
|
+
|
|
163
|
+
Every canvas shares one sidebar vocabulary. A board's `"type"` - `start`, `feature`, `surface`,
|
|
164
|
+
`project`, `feedback`, `context`, `deck`, `archive` - draws its icon; set it on the board, or on a
|
|
165
|
+
folder's entry in `_folders.json` and every board inside wears it (its own type wins; a sub-folder's
|
|
166
|
+
boards fall back to the parent folder's type). Moving a board changes an inherited type only.
|
|
167
|
+
|
|
168
|
+
- **Make a board in its starting layout:** `npx marver boards new <name> --folder features` (the
|
|
169
|
+
folder's type), or `--type <type>`. A feature gets three phase scenes as three bands -
|
|
170
|
+
`<name>-specs`, `<name>-lofi`, `<name>` - each with a brief; a start board renders
|
|
171
|
+
`context/INDEX.md` and `context/shipped.md`; a deck starts on a title slide. It never overwrites.
|
|
172
|
+
The phase scenes start empty: pin each frame you make in one as a node, or the board never shows it.
|
|
173
|
+
- **Add a typed folder:** `npx marver folders add decks` (or `start`, `features`, `surfaces`,
|
|
174
|
+
`projects`, `feedback`, `context`, `archive`) - appended, never moving one that exists.
|
|
175
|
+
- **Feature and project boards wear a status** read from `context/` (instructions/context.md): the
|
|
176
|
+
capability is the board's name, or `"capability": "<slug>"`. You may decide only three things on
|
|
177
|
+
the board: `"status": "archived"`, `"paused"`, or `"blocked"` with `"reason": "<one sentence>"`.
|
|
178
|
+
**Never write `"status": "done"`** - Done comes from `context/shipped.md`, and the check fails it.
|
|
179
|
+
Without `context/` a board may also say `"todo"`, `"backlog"` or `"in-progress"` by hand.
|
|
180
|
+
A person sets the same from the sidebar (right-click, Change status…) - it rewrites only `status`
|
|
181
|
+
and `reason`, so re-read a board before you edit it.
|
|
182
|
+
- In progress fills by phase: the phase scenes above, or `phase: spec | lofi | hifi` in a scene's
|
|
183
|
+
`_brief.md` front matter - never by where a row sits.
|
|
184
|
+
- `npx marver boards` prints every board's type and status with what decided it.
|
|
135
185
|
|
|
136
186
|
## The default composition: one horizontal band
|
|
137
187
|
|
|
@@ -224,6 +274,12 @@ be ON a published board - unlisted frames are excluded from the bundle at build
|
|
|
224
274
|
time. Deploying the built canvas - gate password, the collaboration volume,
|
|
225
275
|
accounts and invites - is its own phase: **instructions/publish.md**.
|
|
226
276
|
|
|
277
|
+
When you add a board to `publish.json`, write the `type` its board type suggests - `slides` for a
|
|
278
|
+
deck, `refs` for a context board, `doc` for a project (`marver build` notes any row that names none).
|
|
279
|
+
A board's status, reason and capability never ship - unless the row says `"showStatus": true`, and
|
|
280
|
+
then only a status drawn from publishable evidence (`audience: publishable` under `context/`; a scene
|
|
281
|
+
brief counts unless it says otherwise), never Blocked, never a reason.
|
|
282
|
+
|
|
227
283
|
The published gate page shows the app's identity: `design/logo.svg` + the host
|
|
228
284
|
package name (overridable via config `share`). If the app has no logo asset yet,
|
|
229
285
|
create a simple `design/logo.svg`. Leave `share.branding` ON unless the human
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Context - what the product is, kept true
|
|
2
|
+
|
|
3
|
+
The project's knowledge lives in `context/`, beside `design/`. Code says what is implemented;
|
|
4
|
+
`context/` says what is available, how it works, why, and what is next - with evidence. The canvas
|
|
5
|
+
reads the same files: every feature and project board wears the status they record.
|
|
6
|
+
|
|
7
|
+
## At the start of a session
|
|
8
|
+
|
|
9
|
+
Read `context/INDEX.md`, then at most two more files per question. The index routes; it never
|
|
10
|
+
explains. If there is no `context/`, see "Setting up" below before you invent answers.
|
|
11
|
+
|
|
12
|
+
## The files
|
|
13
|
+
|
|
14
|
+
| Path | What it holds |
|
|
15
|
+
|---|---|
|
|
16
|
+
| `INDEX.md` | routing only, under 800 words; its capability table is generated from `map.json` |
|
|
17
|
+
| `shipped.md` | **the only place availability is written** - services by environment, capabilities by who has them; for knowledge work, what was delivered to whom |
|
|
18
|
+
| `product/<capability>.md` | one current contract per capability |
|
|
19
|
+
| `map.json` | which code each capability lives in - the pull-request rule reads it |
|
|
20
|
+
| `playbooks/<name>/PLAYBOOK.md` | how we do things - steps with checks, traps, a run log |
|
|
21
|
+
| `feedback/` | the inbox: one row per piece of feedback, with its state |
|
|
22
|
+
| `plans/` | proposals in flight - a plan folds into its contract when it lands |
|
|
23
|
+
|
|
24
|
+
## Evidence has levels
|
|
25
|
+
|
|
26
|
+
Every availability claim in `shipped.md` carries one, with a citation:
|
|
27
|
+
- `confirmed` - observed in a system of record: the deploy job that ran for that service and
|
|
28
|
+
succeeded, a ci run that executed the suite. Not an environment marked "deployed" - some
|
|
29
|
+
pipelines mark it when the run stood down.
|
|
30
|
+
- `reported` - a written claim, cited: a changelog line, an ops note.
|
|
31
|
+
- `unknown` - neither, with the reason. An honest unknown is a correct answer.
|
|
32
|
+
|
|
33
|
+
Never upgrade a level because a claim sounds sure. Commit ancestry says a change is inside a
|
|
34
|
+
revision, not that the revision is running.
|
|
35
|
+
|
|
36
|
+
## A contract
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
---
|
|
40
|
+
state: current # current | proposed | historical
|
|
41
|
+
capability: quote-intake # the same slug as its feature board
|
|
42
|
+
audience: team # team | publishable | restricted
|
|
43
|
+
reviewed: { revision: 606ad4e, scope: "apps/quote, db schema", method: "read code and tests" }
|
|
44
|
+
---
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then: what it does and its limits; who can use it and when; how it works; what it touches (frontend,
|
|
48
|
+
backend, database, workers, integrations); invariants; code and tests; decisions; its frames
|
|
49
|
+
(`scene/frame` ids - say which are designed but not built); the PRs that built it; what is still
|
|
50
|
+
proposed; and `## Availability` pointing at its row in `shipped.md`.
|
|
51
|
+
|
|
52
|
+
- **Read the code to write it.** Cite `path:line` for every behaviour; a test file's existence is
|
|
53
|
+
not a run.
|
|
54
|
+
- **No status line, no availability** ("live", "on production", "since 30 Sep") - that is
|
|
55
|
+
`shipped.md`'s alone. The check fails on both.
|
|
56
|
+
- **One answer per rule.** When a plan amends a rule, write the amended rule - never "section 20
|
|
57
|
+
wins where it differs".
|
|
58
|
+
- **When code and an accepted document disagree,** the contract says what the code does and the
|
|
59
|
+
conflict goes to the human. Never decide what was intended.
|
|
60
|
+
|
|
61
|
+
## When you change things
|
|
62
|
+
|
|
63
|
+
- **Behaviour** - update its contract in the same change. A change that leaves behaviour alone says
|
|
64
|
+
`no-contract-change: <capability> - <why>` in the pull request body.
|
|
65
|
+
- **A deploy** - write its row in `shipped.md` with the run that proves it (`playbooks/` usually
|
|
66
|
+
has the release recipe).
|
|
67
|
+
- **A decision** - in the project's decision log, numbered, with what it applies to.
|
|
68
|
+
- **Feedback** - one row per item: source, who, when, what they said, theme, state (`new`,
|
|
69
|
+
`triaged`, `proposed`, `planned`, then `shipped` or `declined`), and what resolved it. An item is
|
|
70
|
+
`shipped` only when `shipped.md` shows its fix `confirmed` where it was raised; a `reported`
|
|
71
|
+
deploy leaves it `planned`, saying what is missing. On closing, draft - never send - a note back.
|
|
72
|
+
|
|
73
|
+
## Status on the canvas
|
|
74
|
+
|
|
75
|
+
Feature and project boards wear a status read from these files (the first that matches wins):
|
|
76
|
+
the board's own `"status"` - `archived`, `paused`, or `blocked` with a `"reason"`; Unknown when the
|
|
77
|
+
evidence cannot be read; In progress when an open plan in `plans/` names the capability (filling by
|
|
78
|
+
phase: `<cap>-specs`, `<cap>-lofi`, `<cap>`); Done when `shipped.md` shows it `confirmed` in an
|
|
79
|
+
availability clause (one per `;`) with no negation or pending word ("nowhere", "not yet", "rolled
|
|
80
|
+
back", "planned") and no pre-production place (staging, preview, dev, local, testing) unless it also
|
|
81
|
+
names production; Done, reported when only `reported`; To do when its contract is `state: current`; else Backlog.
|
|
82
|
+
**Done is never set by hand** - `"status": "done"` fails the check. A board finds its capability by
|
|
83
|
+
its own name, or `"capability": "<slug>"` in its JSON.
|
|
84
|
+
|
|
85
|
+
## Audiences
|
|
86
|
+
|
|
87
|
+
`team` - everyone with the repository (the default); `publishable` - may appear on a published
|
|
88
|
+
canvas; `restricted` - never tracked by git (keep it under a gitignored `context/private/`). A
|
|
89
|
+
frame that renders a `team` file onto a published board fails the check. A digest of restricted
|
|
90
|
+
material is restricted, however it is labelled.
|
|
91
|
+
|
|
92
|
+
## Setting up - when there is no `context/`
|
|
93
|
+
|
|
94
|
+
Context starts with people. Ask, in one message:
|
|
95
|
+
1. Who is involved - the team and their roles; clients, users, partners?
|
|
96
|
+
2. Where does each relationship happen - channels, email, recorded meetings, docs, in-product
|
|
97
|
+
feedback, canvas comments?
|
|
98
|
+
3. What is private, and who may see what?
|
|
99
|
+
4. How is this project named in shared spaces - keywords, tags?
|
|
100
|
+
|
|
101
|
+
Then `npx marver context init`, record the answers in `context/people.md`, and draft from evidence:
|
|
102
|
+
the shipped record from deploy runs and the changelog (`unknown` where nothing proves it), a map from
|
|
103
|
+
the code, contracts for the capabilities that matter now. **Context that exists but is scattered**
|
|
104
|
+
- specs out of date, nobody sure what is live - is a job for
|
|
105
|
+
`context/playbooks/reorganize-context/PLAYBOOK.md`, not for a rewrite.
|
|
106
|
+
|
|
107
|
+
## The check
|
|
108
|
+
|
|
109
|
+
`npx marver context check` - availability only in `shipped.md`, a level and a citation on every
|
|
110
|
+
evidence cell, citations and links that resolve, the index under budget and equal to the map,
|
|
111
|
+
audiences, feedback and contract states, playbook freshness; with `--base <ref>` (or in ci on a pull
|
|
112
|
+
request) a contract change or a stated reason for every mapped change. Exit 0 pass, 1 fail, 2 cannot
|
|
113
|
+
determine (fetch full history - `fetch-depth: 0`). `npx marver context index` rewrites the index's
|
|
114
|
+
generated table after you change the map.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: publish-canvas
|
|
3
|
+
description: Use this when the canvas should be on a URL - a first publish, a republish after changes, or moving it to a new host. Steps with checks, the traps that have bitten, how to roll back.
|
|
4
|
+
last_success: none
|
|
5
|
+
depends_on:
|
|
6
|
+
- design/publish.json
|
|
7
|
+
- design/config.ts
|
|
8
|
+
- Dockerfile
|
|
9
|
+
- package.json
|
|
10
|
+
- "service: the canvas host (Railway or any volume-capable host)"
|
|
11
|
+
- "account: the host, and Marver Sign In or the canvas password"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Publish a canvas
|
|
15
|
+
|
|
16
|
+
The recipe. `design/instructions/publish.md` is the reference - every variable, both gates, the
|
|
17
|
+
host contract; read it when a step here is not enough. Marver maintains this file; record your
|
|
18
|
+
project's values (which account, which domain, which gate) and every run in the log at the end.
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
- `@marver-design/marver` resolves from the registry in `package.json` - a `link:` or `file:`
|
|
23
|
+
dependency cannot ride to a remote host.
|
|
24
|
+
- The three decisions are made: **which boards ship** (`design/publish.json` - publishing is
|
|
25
|
+
default-closed), **who gets in** (Marver Sign In by default; the canvas password when nothing
|
|
26
|
+
external may be in the sign-in path), **collaboration** (a persistent volume for comments, or none).
|
|
27
|
+
- The canvas has a name: `share: { name: "..." }` in `design/config.ts`.
|
|
28
|
+
|
|
29
|
+
## Steps
|
|
30
|
+
|
|
31
|
+
1. **Build locally first.** `npx marver build`.
|
|
32
|
+
*Check:* it lists exactly the boards you meant, `textures:` reports the hi-fi frames asleep, and
|
|
33
|
+
no warning names a deck with no slide frames.
|
|
34
|
+
2. **Check what ships.** `npx marver context check` when the project has `context/`.
|
|
35
|
+
*Check:* no `team` or `restricted` file is reachable from a published board; a board's status
|
|
36
|
+
ships only where its publish row says `"showStatus": true`.
|
|
37
|
+
3. **Commit the host files** - a `Dockerfile` (it gives the build a browser for the glass
|
|
38
|
+
textures) and a `.dockerignore` with `node_modules`, `design/.dist`, `design/.local`.
|
|
39
|
+
*Check:* `design/.dist` is gitignored and not in the upload.
|
|
40
|
+
4. **Create the service once:** a persistent volume, `MARVER_DATA_DIR` on it, the gate's variables,
|
|
41
|
+
`MARVER_TRUSTED_PROXY=1` behind a proxy, `MARVER_CLI_TOKEN` generated (`openssl rand -hex 24`),
|
|
42
|
+
never chosen. *Check:* the host lists the volume mounted at the path the variable names.
|
|
43
|
+
5. **Deploy** - on Railway, `railway up` from the repository root.
|
|
44
|
+
*Check:* the deploy succeeds, and the URL answers with the gate.
|
|
45
|
+
6. **Walk it.** Sign in as the owner, open each published board, leave a comment, reload.
|
|
46
|
+
*Check:* the comment survives the reload, and a second account sees only what its rights allow.
|
|
47
|
+
7. **Write the run** in the log below - date, revision, URL, what was checked.
|
|
48
|
+
|
|
49
|
+
## Traps
|
|
50
|
+
|
|
51
|
+
- **The upload is the working tree.** Untracked files and full-resolution images go up with it;
|
|
52
|
+
`marver build` ships images at full size, and a large `design/assets/` can pass the host's upload
|
|
53
|
+
cap. Keep heavy originals out of published frames, or out of the upload.
|
|
54
|
+
- **A repository linked to another project uploads there.** Check which project and service the
|
|
55
|
+
host CLI is linked to before `up` - a canvas deployed onto the app's own service replaces the app.
|
|
56
|
+
- **An ephemeral data directory loses every comment** on the next deploy. The volume is not optional
|
|
57
|
+
once collaboration is on.
|
|
58
|
+
- **Run one instance.** The comment log is single-writer.
|
|
59
|
+
- **Fonts only on your laptop** render differently in the build container; the glass textures then
|
|
60
|
+
rest live. Bundle fonts with the project.
|
|
61
|
+
- **A republish never clobbers comments** - the server unions the seeded logs on boot - but tabs
|
|
62
|
+
already open keep the old textures until they reload.
|
|
63
|
+
|
|
64
|
+
## Rolling back
|
|
65
|
+
|
|
66
|
+
Redeploy the previous revision the same way. Comments live on the volume, not in the build, so a
|
|
67
|
+
rollback keeps them; a board removed from `publish.json` hides its threads until it ships again.
|
|
68
|
+
|
|
69
|
+
## Run log
|
|
70
|
+
|
|
71
|
+
| Date | Revision | Who | URL | Outcome |
|
|
72
|
+
|---|---|---|---|---|
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reorganize-context
|
|
3
|
+
description: Reorganize an existing project's accumulated context - specs, changelogs, roadmaps, transcripts, research, boards, agent memory - so a fresh agent can answer what is available to users, how it works, why, and what is next, from the repo alone. Builds a shipped record with evidence levels, writes current contracts for a bounded first batch, adds a checker, reconciles only what that batch covers, and proves the result with a blind before/after eval. Works on a branch and never deletes. Use when specs are out of date, nobody can say what is on production, or context is scattered.
|
|
4
|
+
last_success: none
|
|
5
|
+
depends_on: []
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Reorganize a project's context
|
|
9
|
+
|
|
10
|
+
`design/instructions/context.md` defines the target - the files under `context/`, what each holds,
|
|
11
|
+
the evidence levels. This is how an agent gets an existing project there. Marver maintains it: it
|
|
12
|
+
was first run on a client project in October 2026 (16 of 16 questions answered before and after,
|
|
13
|
+
with 40% fewer tokens after), and each rule exists because that project, or an earlier draft of this
|
|
14
|
+
playbook, broke it. Record your project's runs in the run log at the end.
|
|
15
|
+
|
|
16
|
+
**The order matters: truth first, then authority, then files.** Moving documents before you know
|
|
17
|
+
which one is right only relocates the contradiction.
|
|
18
|
+
|
|
19
|
+
## Done means
|
|
20
|
+
|
|
21
|
+
A fresh agent with no memory reads `context/INDEX.md` and at most two more files per question, and
|
|
22
|
+
answers correctly - or says "unknown" with the reason - what each production service runs, whether a
|
|
23
|
+
capability is available and to whom, how it works, why, and what is next. Every artifact that
|
|
24
|
+
existed before has a recorded disposition. A blind before/after eval proves it.
|
|
25
|
+
|
|
26
|
+
## Hard rules
|
|
27
|
+
|
|
28
|
+
1. **Worktree and branch.** Never main. Never touch the original checkout's uncommitted changes.
|
|
29
|
+
2. **Never delete.** Originals are preserved; superseded ones get a header pointing at their
|
|
30
|
+
replacement. Delete only proven disposable output, listed in the report.
|
|
31
|
+
3. **Code says what is implemented, not what is intended.** When code and an accepted requirement
|
|
32
|
+
disagree, record both on the exception list - do not pick a winner silently.
|
|
33
|
+
4. **Evidence has levels.** `confirmed`: observed in a system of record. `reported`: a written claim,
|
|
34
|
+
cited - a changelog line, an ops note, agent memory. `unknown`: neither. Never upgrade a level
|
|
35
|
+
because a claim sounds sure. Commit ancestry says a change is inside a revision, not that the
|
|
36
|
+
revision is running.
|
|
37
|
+
5. **Stable paths stay stable.** Frame ids, board and scene slugs, URLs, comment anchors and asset
|
|
38
|
+
paths are identities. Do not move them in this pass.
|
|
39
|
+
6. **Read-only outside the repo.** You may read deploy records (`gh`, a provider's status command).
|
|
40
|
+
You never deploy, migrate, query a production database, or edit agent memory. A read that needs
|
|
41
|
+
credentials you were not given is an exception-list item, not a workaround.
|
|
42
|
+
7. **No secrets; mind the audience.** Never copy credentials. Record sensitive files by path and
|
|
43
|
+
hash only.
|
|
44
|
+
8. **History is not rewritten.** Old changelog entries stay as written.
|
|
45
|
+
9. **Bounded scope.** This pass rewrites only what the first batch of capabilities needs. Everything
|
|
46
|
+
else is inventoried and marked `deferred` - never superseded on a guess.
|
|
47
|
+
|
|
48
|
+
## Phase 0 - baseline, in this order
|
|
49
|
+
|
|
50
|
+
1. **The original checkout first.** In `context/reorg/start.md` (written later into the worktree,
|
|
51
|
+
from notes kept outside it): the revision, every dirty and untracked path with the hash of its
|
|
52
|
+
**working** file (`shasum`), and the tracked hashes (`git ls-files -s`).
|
|
53
|
+
2. **The worktree.** `git worktree add ../<repo>-context -b context/reorganize <revision>` and work
|
|
54
|
+
only there from now on. Note that the original's dirty files are not in it.
|
|
55
|
+
3. **Preimages.** Hash every context-bearing file in the worktree. This list is what Phase 9
|
|
56
|
+
compares against: untouched files must match; edited files must appear on the edit list with
|
|
57
|
+
their preimage hash and the reason.
|
|
58
|
+
4. **The eval, blind.** Follow `eval.md` (beside this file). The questions go into the evaluated
|
|
59
|
+
agent's prompt; the **answer key never enters the worktree**. Run the before pass now.
|
|
60
|
+
|
|
61
|
+
## Phase 1 - inventory, bounded
|
|
62
|
+
|
|
63
|
+
`context/reorg/inventory.md`:
|
|
64
|
+
- **Every** context-bearing path at file or folder level - docs, plans, changelogs, roadmaps,
|
|
65
|
+
feedback lists, READMEs inside apps, research, `design/` (boards, briefs, sticky notes, content
|
|
66
|
+
frames, comments), asset indexes, sync logs, `CLAUDE.md` / `AGENTS.md`, CI and scripts that
|
|
67
|
+
encode procedure, and the agent's project memory (Claude Code:
|
|
68
|
+
`~/.claude/projects/<path-slug>/memory/`). Size, last change, one-line role.
|
|
69
|
+
- **Section by section** only for documents that touch the first batch (Phase 4).
|
|
70
|
+
- Everything else gets disposition `deferred`.
|
|
71
|
+
|
|
72
|
+
Classes: current contract · proposed · historical evidence · decision · release/validation evidence ·
|
|
73
|
+
operational procedure · receipt · generated view · convention · tool state.
|
|
74
|
+
|
|
75
|
+
Flag, with file and line: status lines in prose; supersession inside a current file ("section 20
|
|
76
|
+
wins"); double homes ("the board is canonical, this file is its digest"); conventions pointing at
|
|
77
|
+
paths that no longer exist; design status phrased as product status; hand-kept counts.
|
|
78
|
+
|
|
79
|
+
Start `context/reorg/exceptions.md` now and keep adding to it in every phase.
|
|
80
|
+
|
|
81
|
+
## Phase 2 - the shipped record
|
|
82
|
+
|
|
83
|
+
`context/shipped.md`, two tables, every cell with an evidence level and a citation.
|
|
84
|
+
|
|
85
|
+
**Services × environments** - discover the services first (deploy workflow, Dockerfiles, provider
|
|
86
|
+
config), then for each: revision, deployed at, how (pipeline / by hand), evidence level + citation,
|
|
87
|
+
migrations applied.
|
|
88
|
+
- `confirmed` needs the run that deployed **that service** and succeeded - the job inside the deploy
|
|
89
|
+
workflow, or the provider's own deploy status - not an environment record, which some pipelines
|
|
90
|
+
mark "deployed" even when the run stood down.
|
|
91
|
+
- Hand deploys leave only prose: `reported`, cite the line.
|
|
92
|
+
- A health endpoint that reports no revision cannot confirm one - note the gap.
|
|
93
|
+
- An API you cannot reach: `unknown`, with the error.
|
|
94
|
+
|
|
95
|
+
**Capabilities** - implemented (code reference); verified (a test or recorded walk: revision,
|
|
96
|
+
environment, date, scope - a test file's existence is not a run); available (which environment, and
|
|
97
|
+
for which tenants - a flag or setting is separate evidence from the deploy, usually `reported`
|
|
98
|
+
unless someone with access confirms it); contract link.
|
|
99
|
+
|
|
100
|
+
## Phase 3 - the implementation map
|
|
101
|
+
|
|
102
|
+
`context/map.json`, machine-readable because the checker reads it:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{ "capabilities": { "quote-intake": { "paths": ["apps/quote/app/**"], "tests": [] } },
|
|
106
|
+
"excluded": [{ "path": "apps/run/app/preview/**", "reason": "generated from the canvas" }] }
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Enumerate from the code: routes and actions, domain commands, tables and SQL functions, migrations
|
|
110
|
+
(every mechanism - a second app may keep its own schema), queued jobs and schedules, integrations,
|
|
111
|
+
config, tests. Map or exclude each, with a reason. Shared files may map to several capabilities. The
|
|
112
|
+
map is routing, not proof that anything is documented.
|
|
113
|
+
|
|
114
|
+
## Phase 4 - contracts, the first batch
|
|
115
|
+
|
|
116
|
+
Pick 5-7 capabilities where the evidence showed contradictions or no contract. For each,
|
|
117
|
+
`context/product/<capability>.md`:
|
|
118
|
+
|
|
119
|
+
```yaml
|
|
120
|
+
state: current
|
|
121
|
+
capability: quote-intake
|
|
122
|
+
audience: team # team | publishable | restricted
|
|
123
|
+
reviewed: { revision: 606ad4e, scope: "apps/quote, db schema", method: "read code and tests" }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Then: what it does and its limits; who can use it and when; how it works; what it touches -
|
|
127
|
+
frontend, backend, database, workers, integrations; invariants; code and test references; decisions;
|
|
128
|
+
its lo-fi and hi-fi frames and the PRs that built it; what is still proposed. Read the code to write
|
|
129
|
+
it. Apply the plan's amendments - one answer per rule. Shared rules go once in `context/system/`.
|
|
130
|
+
|
|
131
|
+
The contracts are independent: one agent each, in parallel, from one shared brief (the rules, the
|
|
132
|
+
format, "no availability, no status lines", and a report back of every code-vs-document conflict and
|
|
133
|
+
the exact sections it now covers, `full` or `part`). Then a second model reviews the batch against
|
|
134
|
+
the code before anything relies on it - on its first run it found 18 overstated or mis-cited claims.
|
|
135
|
+
A shared file maps to every contract whose behaviour it changes, or the pull-request rule misses it.
|
|
136
|
+
|
|
137
|
+
## Phase 5 - the checker, before reconciling anything
|
|
138
|
+
|
|
139
|
+
`scripts/context-check.mjs` (or the project's language), wired into existing CI. Inputs: front
|
|
140
|
+
matter, `context/map.json`, `context/shipped.md`, the publish configuration and what it pulls in, and
|
|
141
|
+
on a pull request the changed paths (`git diff --name-only <base>...<head>`, base and head from the
|
|
142
|
+
CI event) and the PR body (from the event payload).
|
|
143
|
+
|
|
144
|
+
Audiences decide where a file may go: `restricted` is never tracked by git and never published;
|
|
145
|
+
`team` may be committed in a private repo but never published; `publishable` may appear in a
|
|
146
|
+
publish. "Published" means everything a canvas build carries: the boards in its publish config, the
|
|
147
|
+
frames on them, and every markdown import, image, note and asset those frames pull in.
|
|
148
|
+
|
|
149
|
+
| Rule | Result |
|
|
150
|
+
|---|---|
|
|
151
|
+
| a `state: current` doc has a status line (`^\s*\**status\**\s*:`) - lines, not domain words like a bank account's `verified` | fail |
|
|
152
|
+
| a current doc carries supersession markers ("wins where it differs", "overrides section") | fail |
|
|
153
|
+
| a shipped cell has no evidence level, or `confirmed` / `reported` with no citation | fail |
|
|
154
|
+
| a dead relative link, `?raw` import or asset reference under `context/` or in a frame that renders it | fail |
|
|
155
|
+
| `INDEX.md` over 800 words | fail |
|
|
156
|
+
| a `restricted` file tracked by git, or a `team` or `restricted` file reachable from what a publish carries | fail |
|
|
157
|
+
| a PR changes mapped paths without its contract, and without `no-contract-change: <capability> - <reason>` in the PR body | fail on pull requests |
|
|
158
|
+
| an `unknown` evidence cell | pass - honest unknowns are the right answer |
|
|
159
|
+
| a rule it cannot evaluate (no git history, API unreachable) | exit 2, "cannot determine", printed |
|
|
160
|
+
|
|
161
|
+
Exit 0 pass, 1 fail, 2 cannot determine. In CI, 2 blocks like 1 - fix the cause (fetch full history,
|
|
162
|
+
grant the read). During this pass, Phase 6 may start on exit 0, or on exit 2 when every
|
|
163
|
+
"cannot determine" is on the exception list with its reason.
|
|
164
|
+
|
|
165
|
+
## Phase 6 - reconcile, first batch only
|
|
166
|
+
|
|
167
|
+
For each document that the first batch's contracts now supersede, **only the sections they cover**:
|
|
168
|
+
|
|
169
|
+
| Material | Action |
|
|
170
|
+
|---|---|
|
|
171
|
+
| amendment-stacked spec | its covered sections get "Superseded by `context/product/x.md`"; the file stays as history; uncovered sections stay `deferred` |
|
|
172
|
+
| mixed spec | covered contract → `product/`; review diary stays; open items → backlog |
|
|
173
|
+
| dated feedback lists | covered items get a resolution: contract + shipped row, or `open` |
|
|
174
|
+
| roadmap in two homes | one editable source; the board renders it (`?raw`) |
|
|
175
|
+
| README with contradictions | fix the covered contradiction; keep run instructions by the app |
|
|
176
|
+
| changelog | untouched; its release lines are cited from `shipped.md` |
|
|
177
|
+
| sync log | keep cursors and pending failures; drop "agent memory" as a target |
|
|
178
|
+
| agent memory | project facts the batch needs land in their repo home; `context/reorg/memory-trim.md` proposes the rest |
|
|
179
|
+
| wrong binding instructions | correct them - an agent will obey them |
|
|
180
|
+
|
|
181
|
+
Diff duplicate prose before merging; check inbound references after every move.
|
|
182
|
+
|
|
183
|
+
**Line citations move when you insert.** Every note added to an old document shifts the lines that
|
|
184
|
+
contracts cite. Either reconcile before the contracts cite those documents, or remap every citation
|
|
185
|
+
once, mechanically, from the base revision's lines to the new ones - and verify by content (the cited
|
|
186
|
+
line still says what the citation claims). Never run a remap twice. Prefer line-neutral edits where a
|
|
187
|
+
document is cited heavily.
|
|
188
|
+
|
|
189
|
+
## Phase 7 - entry point and index
|
|
190
|
+
|
|
191
|
+
- Root `AGENTS.md` is the shared entry point; tool files route to it. Keep existing binding routes
|
|
192
|
+
(for example to `design/AGENTS.md`).
|
|
193
|
+
- `context/INDEX.md`, **at most 800 words**, counted by the checker: the product in five lines; the
|
|
194
|
+
capabilities with their contract and shipped row; where each role lives, including healthy homes
|
|
195
|
+
left in place; the rules (status only in `shipped.md`; a behaviour change updates its contract or
|
|
196
|
+
says `no-contract-change`; every deploy writes the record; plans fold into contracts when they
|
|
197
|
+
land; changelog lines start with kind and capability: `[product:quote]`, `[design:board]`,
|
|
198
|
+
`[infra]`, `[decision 41]`). Generated parts sit between `<!-- generated -->` fences.
|
|
199
|
+
|
|
200
|
+
## Phase 8 - the exception list, asked once
|
|
201
|
+
|
|
202
|
+
Everything collected since Phase 1: `unknown` availability that matters, code-vs-intent conflicts,
|
|
203
|
+
disputed capability boundaries, audience and retention calls, reads that need credentials. Ask in
|
|
204
|
+
one numbered batch now - or immediately, only if an item blocks the next step.
|
|
205
|
+
|
|
206
|
+
| The human decides | The agent decides from evidence |
|
|
207
|
+
|---|---|
|
|
208
|
+
| intended behaviour where code and an accepted requirement conflict | what the code implements |
|
|
209
|
+
| access, audiences, retention, redaction | inventory, hashes, references |
|
|
210
|
+
| priorities, commitments, pilot scope | what is done vs still proposed |
|
|
211
|
+
| disputed capability boundaries | the initial grouping (reversible) |
|
|
212
|
+
|
|
213
|
+
## Phase 9 - verify
|
|
214
|
+
|
|
215
|
+
`context/reorg/report.md`:
|
|
216
|
+
|
|
217
|
+
| Check | Passing result |
|
|
218
|
+
|---|---|
|
|
219
|
+
| Preservation | untouched files match their preimage; every edited file is on the edit list with preimage and reason |
|
|
220
|
+
| Disposition | every inventoried path is unchanged, edited, superseded (covered sections only) or `deferred` |
|
|
221
|
+
| The checker | exit 0, or exit 2 with each "cannot determine" explained |
|
|
222
|
+
| Release honesty | every availability claim carries a level and a citation, or says `unknown` |
|
|
223
|
+
| Reconciliation | no Phase 1 contradiction inside the first batch survives as competing current text |
|
|
224
|
+
| The eval | the after pass beats the before pass, per `eval.md` |
|
|
225
|
+
|
|
226
|
+
Then stop. The report lists what moved, what was decided without asking, the open exceptions, what
|
|
227
|
+
was deferred, and the memory-trim proposal. The human reviews the branch; nothing merges on its own.
|
|
228
|
+
|
|
229
|
+
## Run log
|
|
230
|
+
|
|
231
|
+
| Date | Revision | Who | Batch | Outcome |
|
|
232
|
+
|---|---|---|---|---|
|