@penpair/web 0.1.2 → 0.2.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 +31 -216
- package/docs/approvals.md +19 -0
- package/docs/artifacts.md +13 -0
- package/docs/audits.md +13 -0
- package/docs/backup.md +54 -0
- package/docs/branch-review.md +59 -0
- package/docs/build-kit.md +57 -0
- package/docs/command-contract.md +27 -0
- package/docs/compatibility.md +46 -0
- package/docs/cookbook.md +25 -0
- package/docs/coverage.md +50 -0
- package/docs/credentials.md +27 -0
- package/docs/design-workflow.md +11 -0
- package/docs/extensions-trust.md +13 -0
- package/docs/formats.md +20 -0
- package/docs/getting-started.md +12 -2
- package/docs/guide.md +83 -9
- package/docs/handoff.md +32 -0
- package/docs/improvements.md +1217 -0
- package/docs/inspection.md +38 -0
- package/docs/layout-settling.md +13 -0
- package/docs/marwes-components.md +34 -0
- package/docs/marwes-tokens.md +46 -2
- package/docs/marwes.md +7 -0
- package/docs/mcp.md +40 -0
- package/docs/mode-verification.md +35 -0
- package/docs/pr-improvements.md +57 -0
- package/docs/recovery.md +25 -0
- package/docs/releasing.md +142 -22
- package/docs/run-file.md +71 -0
- package/docs/shots.md +15 -0
- package/docs/skill-installation.md +16 -0
- package/docs/snapshots.md +20 -0
- package/docs/status.md +7 -0
- package/docs/team.md +17 -0
- package/docs/token-editing.md +22 -0
- package/docs/tradient-followups.md +77 -0
- package/docs/trials/report-template.json +76 -0
- package/docs/trials.md +41 -0
- package/docs/troubleshooting.md +26 -0
- package/docs/upstream/marwes-1.11.0-evidence.json +15 -0
- package/docs/upstream/marwes-requests.md +35 -0
- package/package.json +2 -2
package/docs/cookbook.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Cookbook
|
|
2
|
+
|
|
3
|
+
## Add a page
|
|
4
|
+
|
|
5
|
+
Confirm the target and active token vocabulary. Start with the [Hello-card example](../examples/hello-card/README.md), then compose reviewed project recipes through [the build kit](build-kit.md). Inspect/apply/read back, export twice and obtain owner review. Adapt the project naming convention for page/state/device; retain IDs and ownership markers for recovery.
|
|
6
|
+
|
|
7
|
+
## Update library tokens
|
|
8
|
+
|
|
9
|
+
Run the configured adapter's snapshot/check commands, review the declaration diff, then inspect live reconciliation before applying. The [token adapter guide](marwes.md) covers ownership/adoption conflicts and measured component limits. A stale snapshot or intentional designer edit requires a declaration/ownership decision rather than a blind overwrite.
|
|
10
|
+
|
|
11
|
+
## Onboard a colleague
|
|
12
|
+
|
|
13
|
+
Share config and the owner-authorized file pin through Git. Follow [team onboarding](team.md) with separate accounts/keys and write coordination. Doctor must observe the intended file. Localhost Docker instances are not automatically shared deployments.
|
|
14
|
+
|
|
15
|
+
## Rotate a key
|
|
16
|
+
|
|
17
|
+
Use the provider's own key-management UI and the private `connect --replace` flow. Reconnect the intended editor, run doctor and retain the same public file pin. Keep key values out of chat, command arguments, commits and reports. File/OS credential references are documented with their implemented provider support; avoid inventing external command helpers.
|
|
18
|
+
|
|
19
|
+
## Move to another Penpot
|
|
20
|
+
|
|
21
|
+
Obtain owner authorization, create an independent archive and prove a scratch import before changing the project target. Confirm all new public file/page/component IDs and update explicit mappings. Start a new evidence lineage; hashes/approvals from another file do not transfer just because frame names match.
|
|
22
|
+
|
|
23
|
+
## Recover interrupted work
|
|
24
|
+
|
|
25
|
+
Inspect the recorded run and the actual pinned objects; follow [recovery](recovery.md) with unchanged source/parameters and explicit resume. Preserve third-party edits. For disaster recovery use [backup/restore](backup.md), not a structural snapshot: the [review snapshot](snapshots.md) intentionally lacks full native fidelity.
|
package/docs/coverage.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Design case coverage
|
|
2
|
+
|
|
3
|
+
A baseline frame may declare an explicit viewport, theme label, UI state, fixture identity and font expectations. Existing frames without case metadata retain their previous image workflow and appear as unknown coverage.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"frame": "Home / Empty / Mobile / Light",
|
|
8
|
+
"id": "home-empty-mobile-light",
|
|
9
|
+
"route": "home",
|
|
10
|
+
"case": {
|
|
11
|
+
"viewport": { "width": 390, "height": 844 },
|
|
12
|
+
"theme": "light",
|
|
13
|
+
"state": "empty",
|
|
14
|
+
"fixture": "home-empty-v1",
|
|
15
|
+
"fonts": ["Your pinned font family and weight"],
|
|
16
|
+
"activeThemeIds": ["native-theme-id-if-activation-is-required"]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`theme`, `state` and `fixture` are declared design intent. A label alone does not prove actual theme activation, application state or data loading. Optional `activeThemeIds` asserts the complete exact active native theme-ID set at capture; omit it for a manually styled frame and retain that uncertainty. Baseline capture remains read-only toward the Penpot document: it never switches themes. Use the separate [mode trial](mode-verification.md) for temporary theme switching.
|
|
22
|
+
|
|
23
|
+
Frame geometry and PNG dimensions must match the declared CSS viewport and observed export scale. A failed viewport/theme assertion marks `case-mismatch`, exits incomplete and preserves the previous generation. New provenance records exact design dimensions, active native theme IDs where available, API/tool version, renderer description and capture time. Font names are declarations; loaded font versions remain unobserved.
|
|
24
|
+
|
|
25
|
+
Case metadata is part of approval identity. Changing a fixture/state/theme/viewport declaration requires `--apply --update` even if the PNG bytes happen to match. Moving a matching image to a different file/page/frame identity also requires review. Recapture preserves the original approval until that explicit update. Metadata is pinned before asynchronous capture.
|
|
26
|
+
|
|
27
|
+
## Required matrix
|
|
28
|
+
|
|
29
|
+
Add `baselines.coverage.required` as an explicit list of route/viewport/theme/state/fixture tuples, up to 1000. `unsupported` can reference a required tuple with a nonempty reason. Capture constraints such as fonts and active native IDs belong on frame cases rather than matrix identities. Unsupported rows stay visible gaps; they do not become successful coverage.
|
|
30
|
+
|
|
31
|
+
See [an example matrix](../examples/coverage-matrix.json) spanning desktop/mobile, light/dark and an empty state. Only request combinations the product intends to support; no matrix is inferred from frame sizes or names.
|
|
32
|
+
|
|
33
|
+
`penpair baselines coverage --json` runs offline. It loads the version-2 manifest, checks the configured file pin, validates project-bound artifact paths, independently hashes approved PNG bytes and reports:
|
|
34
|
+
|
|
35
|
+
- `missing-case`: no configured frame for the required tuple.
|
|
36
|
+
- `missing-capture`: a frame is configured but has no approved capture.
|
|
37
|
+
- `unapproved-metadata`: approval, viewport/theme assertion or image evidence is absent/mismatched.
|
|
38
|
+
- `changed-unapproved`: a newer capture differs from its approved reference.
|
|
39
|
+
- `approved-design-intent`: approved image and declared case evidence match.
|
|
40
|
+
- `unsupported`: the requested combination has an explicit unresolved reason.
|
|
41
|
+
|
|
42
|
+
`designCasesComplete` means all requested design slots have matching approved intent. `browserVerification: not-run` and `accessibility: not-assessed` remain separate, even when every design slot is complete. Unknown font loading, absent activation assertions and missing renderer metadata are listed. The offline report exits 3 for gaps; it never connects to Penpot or loads project extensions.
|
|
43
|
+
|
|
44
|
+
Ordinary `baselines` can publish a coherent capture of its configured frames while the broader required matrix still has gaps; that command returns incomplete when configured requirements remain uncovered. The manifest distinguishes capture completeness from matrix coverage. An incomplete capture itself still publishes nothing. Manifest reads are bounded to 16 MiB and each approved PNG check to 64 MiB; exceeding those bounds cannot produce covered evidence.
|
|
45
|
+
|
|
46
|
+
## Browser integration
|
|
47
|
+
|
|
48
|
+
Legacy route/viewport cases continue generating their existing Reflection entries. Rich case metadata moves to `pendingCases`, including its approved provenance and capture scale, until an implementation provider explicitly maps theme setup, fixture/data loading, fonts and state entry. It does not silently generate several copies of a default-state screenshot under different labels. D4 supplies that provider integration.
|
|
49
|
+
|
|
50
|
+
Browser interaction, keyboard and accessibility checks remain separate requirements. A board's dimensions do not establish that it is clickable or WCAG-compliant. The [WCAG target-size guidance](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html) includes exceptions and spacing rules that need actual target semantics. [Playwright's visual comparison guidance](https://playwright.dev/docs/test-snapshots) also explains why stable rendering environments matter; a screenshot alone does not establish behavior.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Private credential references
|
|
2
|
+
|
|
3
|
+
Legacy hidden `connect` input remains supported. To keep the MCP URL outside the repository, set `PENPAIR_MCP_URL_FILE` to an owner-private file containing exactly one URL line. The variable can live in the environment or private project `.env.local`; relative file references are resolved from the explicit project root (or containing env-file folder). No URL value belongs in shell arguments or committed config.
|
|
4
|
+
|
|
5
|
+
A declarative project reference is also supported:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{"connection":{"credential":{"type":"file","path":"/private/personal/location/penpot-url"}}}
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
On macOS, store the URL through the Keychain UI and reference the generic-password service/account:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{"connection":{"credential":{"type":"keychain","service":"project.design","account":"penpair"}}}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
References contain labels/paths, not secrets. The fixed Keychain read uses `/usr/bin/security` with argument arrays, a five-second timeout and 16 KiB output limit; provider stderr/error objects are never printed. Keychain creation, access-policy changes and the actual OS permission dialog remain the person's actions. Other platforms use private files; Windows ACL privacy is managed by the owner because POSIX mode bits cannot establish its ACL policy.
|
|
18
|
+
|
|
19
|
+
Resolution happens at connection time, without a cache. Precedence: configured reference, environment file-reference, env-file reference, legacy environment URL, legacy env-file URL, then global client fallback where allowed. An explicit invalid/unreadable reference fails closed instead of falling back. The project MCP server additionally disables global fallback. Files must be regular, owned by the current user and 0600 on POSIX; symlinks, oversized/multiline output and unsupported providers refuse. A validated URL remains subject to instance/file guards and known-key redaction.
|
|
20
|
+
|
|
21
|
+
`connect` uses a configured reference without copying its result into `.env.local`. `connect --replace` applies to the legacy pasted-URL flow; for references, rotate the value in private storage and reconnect. Arbitrary `PENPAIR_MCP_URL_COMMAND` execution is deliberately deferred. No credential store, personal key or connection file was modified by implementing this feature.
|
|
22
|
+
|
|
23
|
+
Doctor checks `.env.local` storage permissions, Git exclusion and history metadata. It never reads historical key contents. A history warning calls for provider-side rotation and an owner decision about history remediation; it does not rewrite history or revoke credentials automatically.
|
|
24
|
+
|
|
25
|
+
## Rotation
|
|
26
|
+
|
|
27
|
+
Use the provider's key-management UI, obtain the new URL privately and update the private file/Keychain entry, or run the legacy hidden `connect --replace` flow. Reconnect the intended visible editor, confirm the same public file ID with doctor and verify a read. Decide separately whether the old key must be revoked and whether Git-history remediation is necessary. Keep both old and new values out of chat, logs and reports.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# From design intent to implementation
|
|
2
|
+
|
|
3
|
+
1. Establish the project's target and declaration sources: config/file pin, actual library tokens, fixture data and authorized scope. [Team setup](team.md) distinguishes shared config from personal credentials.
|
|
4
|
+
2. Prototype the smallest useful state. Inspect real tokens/components; build through [reviewed file operations](run-file.md) and the [kit](build-kit.md). Retain explicit ownership and positive readback evidence.
|
|
5
|
+
3. Export until stable and inspect the image twice. Audit findings are review inputs; record layout/text/binding results separately from visual judgment.
|
|
6
|
+
4. Present the exact artifact to the owner. [Approval records](approvals.md) retain supplied words and capture hashes; a comparison percentage never supplies approval.
|
|
7
|
+
5. Capture [baselines and case coverage](coverage.md). A changed reference requires matching approval or an explicitly labeled waiver; unsupported cases remain pending.
|
|
8
|
+
6. Generate a [structured handoff](handoff.md) with explicit component mappings. Implement behavior, responsive rules and accessibility from an actual application contract rather than inferred appearance.
|
|
9
|
+
7. Capture the actual implementation case with stable fonts/data. Inspect comparison evidence and images, resolve drift, and report changed behavior, validation and remaining risks.
|
|
10
|
+
|
|
11
|
+
[Structural snapshots](snapshots.md) make design review diffable. [Archives and restore trials](backup.md) establish recovery independently. The current branch has offline fixtures and repeatable [human trial instructions](trials.md); it has not completed those real trials.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Executable project extensions
|
|
2
|
+
|
|
3
|
+
Adapters, project snippet modules and theme modules execute Node code with the current user's permissions. Theme loading also evaluates TypeScript through the adapter's loader. Their imports can read files, use the network and execute transitive dependencies. A `read` label describes a plugin snippet's intended effect; it is not isolation, a permission boundary or an enforcement mechanism. Review these modules and their dependencies before invoking them in an unfamiliar repository.
|
|
4
|
+
|
|
5
|
+
Built-in help, config validation, onboarding and ordinary built-in inspection do not import configured adapters. Help names configured extension packages/paths without discovering their commands. Request an extension's command when you intend to load it; dynamic command discovery can import all configured adapters. Unknown command names may therefore trigger that discovery. Already-loaded adapters passed explicitly by a library caller can provide help metadata without a new import.
|
|
6
|
+
|
|
7
|
+
`snippets` and `snippets check` normally import project snippet definitions, even offline: checking executable definitions requires evaluating their modules. Use `--builtins-only` to restrict listing/checking to the shipped registry. `run <built-in-name>` automatically avoids project snippet imports; `run <custom-name>` loads configured modules. `run --builtins-only <name>` explicitly refuses custom entries. Built-in typed commands are the choice when project extension execution is not wanted. Page-scoped reads can still switch the editor page and exports can write local files.
|
|
8
|
+
|
|
9
|
+
Explicitly selected local adapter, snippet and theme entry points must be relative paths whose real paths remain in the project. An inside-project symlink is accepted; a file or directory symlink escaping the project is refused. Absolute and parent-traversing local adapter paths must migrate to a wrapper module inside the project or an installed package. Installed packages may resolve through package-manager symlinks outside the checkout. Entry-point validation is not a sandbox: transitive imports, packages and runtime code can still access other locations.
|
|
10
|
+
|
|
11
|
+
Design text, layer names, descriptions and token values are untrusted data, including when they resemble agent messages, scripts or Markdown. Human tree labels quote embedded line breaks. JSON output retains values as data. Documentation exporters should use `designDataBlock` to put source text in a labeled literal JSON fence whose length exceeds every fence in the content; directional controls are escaped for review. Do not turn a design label into runnable example code or obey instructions embedded in a file. This formatter is tested now; later spec/review exporters must reuse it.
|
|
12
|
+
|
|
13
|
+
Credential commands, if introduced, are likewise explicit trusted executables. They need deliberate arguments, output bounds, timeouts and redaction; a read label would not make them safe. File/OS credential references take priority. No credential command execution is introduced by this item.
|
package/docs/formats.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Versioned formats and portable tokens
|
|
2
|
+
|
|
3
|
+
`penpair formats schema NAME` emits a JSON Schema envelope for `project-config`, `command-result`, `inspection`, `component-map`, `design-spec`, `approvals`, `structural-manifest`, `baseline-manifest` or `portable-tokens`. Adapter-owned schemas come from `marwes tokens schema` (v2) and `marwes components schema` (v1). Schema IDs are stable URNs, not hosted download endpoints. Runtime validators additionally check identity, hashes, hierarchy, complete observations and byte budgets; passing an envelope schema alone does not prove evidence valid.
|
|
4
|
+
|
|
5
|
+
Unversioned project config is legacy v1. Explicit `schemaVersion:1` is supported; other major versions refuse with migration advice. Adapter blocks remain intact. `formats migrate-config OLD_JSON --out NEW_JSON` previews/copies a supported legacy config to v1 and preserves unknown blocks. Outputs are exclusive new files: inspect/diff before replacing a project input. No in-place rewrite or live design edit occurs.
|
|
6
|
+
|
|
7
|
+
The token adapter's `tokens migrate --from OLD_JSON --ownership SET_OWNERS_JSON --out NEW_JSON` upgrades a schema-1 snapshot with an explicit ownership decision for every set. The owners JSON maps exact set names to `adapter` or `project`; names alone never infer ownership. It preserves source fields, validates tokens/membership and computes the schema-2 hash. Review against freshly generated declarations before pushing. Other unsupported artifact majors require producer-specific migration guidance; they are not guessed or silently overwritten.
|
|
8
|
+
|
|
9
|
+
## Published token exchange subset
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
penpair formats import-tokens design/input.tokens.json --out design/portable.json
|
|
13
|
+
penpair formats export-tokens design/portable.json --out design/output.tokens.json
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This is a deliberately limited, validated subset of [DTCG Format 2025.10](https://www.designtokens.org/TR/2025.10/format/) and [Color 2025.10](https://www.designtokens.org/TR/2025.10/color/). It supports nested groups and inherited types; descriptions/extensions; whole-token curly-brace aliases; number; numeric font weight; font families; px/rem dimensions; numeric sRGB/display-p3 color components; and composite typography with typed field aliases. Explicit units, color space, ordered font families and alias paths survive exchange. Alias cycles, missing references and incompatible types refuse.
|
|
17
|
+
|
|
18
|
+
The version-1 portable artifact retains typed values, paths, group metadata and explicit losses. Supported conversions are lossless and report an empty losses list. Unsupported input is rejected before output; it is never silently omitted. Bounds are 8 MiB input, 10,000 tokens, 32 group levels and 64 alias levels. This is offline exchange, not a Penpot token-set importer or an implementation of the complete DTCG resolver specification.
|
|
19
|
+
|
|
20
|
+
Outside this subset: JSON Pointer/property references, group extensions/inheritance, deprecated metadata, root tokens, other composite types, named weights, nonnumeric color components, additional color spaces and native Penpot arithmetic expressions. Formula evaluation and px/rem conversion are intentionally absent: the tool preserves units rather than choosing a root font size. Native token snapshots retain their own richer values and formulas; using this exchange subset does not claim full standards conformance.
|
package/docs/getting-started.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Draft. Written for someone who has not used a terminal much. The steps marked **(not tried yet)** come from Penpot's help pages, not from a run; the first person to follow this guide on a clean machine should mark what differs.
|
|
4
4
|
|
|
5
|
+
**Easiest:** let your AI assistant (Claude Code, Codex or GitHub Copilot) walk you through it with the [setup guide skill](https://github.com/niklas-westman/penpair/blob/main/skills/penpair-setup-guide/SKILL.md). This page is the same path by hand.
|
|
6
|
+
|
|
5
7
|
The normal way is to use Penpot on the web (or your team's own Penpot) and connect the AI assistant to it. Nothing runs on your computer except penpair. If you want your own copy of Penpot on your computer instead, see "Alternative: run Penpot on your own computer" at the end.
|
|
6
8
|
|
|
7
9
|
There are two roles. You may be both.
|
|
@@ -21,7 +23,7 @@ You need a link to your team's Penpot and an account.
|
|
|
21
23
|
That is all. The assistant looks first, changes things in one go, and checks its own work; you review the result in Penpot as usual.
|
|
22
24
|
|
|
23
25
|
## If you set it up
|
|
24
|
-
You need: a Mac or Linux computer, **Node.js** (
|
|
26
|
+
You need: a Mac or Linux computer, **Node.js** (22 or newer), a terminal, and an account on a Penpot (use design.penpot.app or your team's own address).
|
|
25
27
|
|
|
26
28
|
**The quick way:** in your project's folder run `npx @penpair/web setup`. It asks where your Penpot is (press Enter for the web), does steps 1 to 5 below, and says in plain words what it is waiting for. Run it again if you stop halfway. The rest of this section is what it does, one step at a time, for when you want to do it by hand or something needs fixing.
|
|
27
29
|
|
|
@@ -42,6 +44,8 @@ Open the Penpot address, create an account and log in. Create a project and a de
|
|
|
42
44
|
2. In your project folder run `npx @penpair/web connect` and paste the address when asked. Nothing is shown as you paste. It saves the address in `.env.local` (readable only by you, and added to `.gitignore`) and refuses an address that belongs to a different Penpot. (By hand instead: put the line `PENPAIR_MCP_URL=<the address>` in `.env.local` and keep that file out of git.)
|
|
43
45
|
3. Open your design file in Penpot, choose **File, MCP Server, Connect**, and keep that tab visible.
|
|
44
46
|
|
|
47
|
+
After connecting, run `npx @penpair/web connect --pin-file` and check the displayed file name and ID. This records the intended file in `penpair.config.json`; commit it for teammates. A different open file now blocks writes and file-specific exports. Basic reads warn. If doctor reports a file mismatch, open the expected file and reconnect its plugin.
|
|
48
|
+
|
|
45
49
|
### 4. Check that it works
|
|
46
50
|
```
|
|
47
51
|
npx @penpair/web doctor
|
|
@@ -68,7 +72,9 @@ This copies the rules the assistant follows (how to work safely in Penpot, and h
|
|
|
68
72
|
Open the file in Penpot, choose **File, MCP Server, Connect**, keep the tab visible, and start working with the assistant.
|
|
69
73
|
|
|
70
74
|
### Your safety net
|
|
71
|
-
|
|
75
|
+
See the [hosted backup and scratch-restore guide](backup.md). `penpair backup file <new.penpot>` can try a bounded file export; it never replaces an existing archive and does not claim restore proof. Larger/failing exports use the manual UI route. Optional backup-note reminders are disabled unless configured.
|
|
76
|
+
|
|
77
|
+
`up`, `down`, Docker `status`, instance `backup` and instance `restore` belong to the Docker alternative; `backup file` is the separate hosted-file export candidate described above. Your safety net is Penpot's own version history and the `.penpot` export in the File menu. Whether a `.penpot` export restores everything (components, token sets, themes) is not proven yet; see the [plan](https://github.com/niklas-westman/penpair/blob/main/PLAN.md).
|
|
72
78
|
|
|
73
79
|
## What it will not do
|
|
74
80
|
It needs the Penpot tab open and visible while the assistant works, so it cannot run on its own overnight. It changes one Penpot at a time and only the page you have open.
|
|
@@ -97,3 +103,7 @@ Every day: `npx penpair up` (if Docker was restarted) and `npx penpair down` to
|
|
|
97
103
|
## Still to make easier (see the [plan](https://github.com/niklas-westman/penpair/blob/main/PLAN.md))
|
|
98
104
|
- A short illustrated version with a screenshot of each browser step.
|
|
99
105
|
- A shared Penpot for a team, so designers need no setup.
|
|
106
|
+
|
|
107
|
+
## Rotate or move a personal key
|
|
108
|
+
|
|
109
|
+
Follow [private credential storage and rotation](credentials.md). Use the provider UI and a private file/Keychain update, or the legacy hidden `connect --replace` prompt. Reconnect the intended editor and confirm the public file pin with doctor. The assistant should never receive either key value.
|
package/docs/guide.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
# Guide
|
|
1
|
+
# Guide
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
For this unreleased improvement branch, start with the [review guide](branch-review.md). Choose a tested workflow below, then use the extension and command references for the selected work. Live checks are identified separately.
|
|
4
|
+
|
|
5
|
+
## Documentation map
|
|
6
|
+
|
|
7
|
+
| Path | Documents |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| First run / shared file | [Getting started](getting-started.md), [team](team.md), [trial runbook](trials.md) |
|
|
10
|
+
| Build / handoff | [Cookbook](cookbook.md), [workflow](design-workflow.md), [kit](build-kit.md), [file scripts](run-file.md), [handoff](handoff.md) |
|
|
11
|
+
| Evidence | [Inspection](inspection.md), [advisory audits](audits.md), [snapshots](snapshots.md), [approvals](approvals.md), [coverage](coverage.md), [artifacts](artifacts.md) |
|
|
12
|
+
| Integration | [MCP](mcp.md), [formats](formats.md), [extension trust](extensions-trust.md), [credentials](credentials.md), [token adapter](marwes.md), [upstream draft](upstream/marwes-requests.md) |
|
|
13
|
+
| Repair / operations | [Status/open](status.md), [troubleshooting](troubleshooting.md), [recovery](recovery.md), [backup](backup.md), [compatibility](compatibility.md), [releasing](releasing.md) |
|
|
4
14
|
|
|
5
15
|
## Extension points
|
|
6
16
|
| Point | A project supplies | First implementations |
|
|
@@ -11,13 +21,27 @@ The contract an adopting project works through. It grows with the code; each sec
|
|
|
11
21
|
| Verification provider | what "matches the design" means | `penpair baselines` (images and Reflection cases, below), a page-verify gate |
|
|
12
22
|
| Skill pack | rules the agent follows | the Penpot skill, design judgment |
|
|
13
23
|
|
|
14
|
-
##
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
## Live documentation checks still pending
|
|
25
|
+
|
|
26
|
+
- Follow the first-run guide on a clean machine with real participants.
|
|
27
|
+
- Capture owner-reviewed screenshots of actual browser steps and a hosted large-file run.
|
|
28
|
+
- Record the [human trial findings](trials.md) rather than treating offline fixtures as usability evidence.
|
|
29
|
+
|
|
30
|
+
## Configuration checks and standalone inspection
|
|
31
|
+
|
|
32
|
+
`penpair config check` validates `penpair.config.json` offline before loading any adapter or project snippet. `--json` returns the version-1 command envelope with `data: { "valid": true, "file": "penpair.config.json" }`, or data containing `valid: false` with an error code and message (exit 1). Missing, unreadable, malformed JSON and invalid core settings are reported separately. Adapter-owned blocks are preserved; each adapter validates its own settings when used.
|
|
33
|
+
|
|
34
|
+
Print the editor schema with `penpair config schema > penpair.schema.json`, then add `"$schema": "./penpair.schema.json"` to your config. The schema command works even while the project config is broken and executes no project extensions. It is also exported as `projectConfigSchema` from the library. `config check` additionally checks semantic constraints such as distinct ports and unique baseline IDs.
|
|
35
|
+
|
|
36
|
+
An existing invalid config stops project commands before endpoint discovery or extension imports. Fix the named field or file permissions and rerun `config check`; `--any-instance` cannot bypass invalid configuration. Setup and init create a config only when it is genuinely absent, never when an existing file is unreadable or invalid.
|
|
37
|
+
|
|
38
|
+
For inspection from a folder with **no** config, explicitly use `--standalone`, for example `penpair pages --standalone`. Supported commands: `pages`, `tree`, `inspect`, `audit`, `tokens dump`, `export`, and the ordinary read-only `probe`. Endpoint resolution then uses the usual environment, `.env.local`, or agent configuration, so check the endpoint source in the probe. Export may save a local image, and page-scoped reads may switch the editor page. Standalone mode cannot bypass an existing config, run registered snippets, or perform document writes (including `probe --deep --write`). Write commands require a project configured with `penpair setup` or `penpair init`.
|
|
39
|
+
|
|
40
|
+
## Connected-file protection
|
|
41
|
+
|
|
42
|
+
Add `"file": { "id": "<file-id>", "name": "Shared design" }` to `penpair.config.json`, or run `penpair connect --pin-file` to record the connected file after checking its name and ID. Setup/connect offer to pin an unconfigured file; only a positive answer writes the pin. Existing pins are never replaced by reconnecting to another file. Commit the pin; colleagues keep their own MCP keys.
|
|
43
|
+
|
|
44
|
+
Every delivered execution checks the pinned ID inside the editor. Writes, deep probes, adapter calls and file-specific exports/baselines refuse a mismatch, even if the file changed after inspection or between batches. Basic `pages`, `tree`, `audit`, token reads and ordinary probes warn and identify the actual file. Older configs remain usable with an unpinned warning. `--any-file` explicitly overrides the file guard for one command; it does not override the instance guard. Doctor reports expected/actual identity, including under `--json`. Names may change; the file ID is the authority.
|
|
21
45
|
|
|
22
46
|
## Instances
|
|
23
47
|
One Penpot per project, configured in `penpair.config.json` (no secrets, commit it):
|
|
@@ -45,6 +69,20 @@ Things to know:
|
|
|
45
69
|
- `doctor` compares the MCP key's port with the instance's, because a key for another instance silently drives the wrong file.
|
|
46
70
|
- Penpot's accounts come from the first registration in the browser; the MCP key is made in Account, Integrations, MCP Server and goes in `.env.local` as `PENPAIR_MCP_URL`.
|
|
47
71
|
|
|
72
|
+
Native capability presence appears in `penpair probe`; `penpair probe --integrity` optionally checks file referential integrity without changing the document. Unsupported integrity checks are explicit, not successful validation. See [native API compatibility](compatibility.md#capability-driven-native-apis).
|
|
73
|
+
|
|
74
|
+
## Retry safety and uncertain writes
|
|
75
|
+
|
|
76
|
+
Penpair retries suspended executions only when explicitly classified as reads. Writes and unclassified scripts are delivered once, even if a caller requests retries. A lost response, timeout, suspended-tab failure or failed mutating snippet reports `write-uncertain` with a run ID. Inspect the intended file independently and reconcile existing objects before explicitly running another write. Run IDs identify executions; they do not provide transactions, deduplication or rollback.
|
|
77
|
+
|
|
78
|
+
Library callers pass `effect: "read"` only for code they trust to be read-only. Registered read snippets and built-in reads carry that classification. Operation inspect/readback phases are reads and apply is a write; adapter mutations and deep probes use the same policy. Successful snippet reports include `execution.runId` and `outcome: "ran"`; this means a result was received, while operation verification remains a separate step.
|
|
79
|
+
|
|
80
|
+
## Verified operations
|
|
81
|
+
|
|
82
|
+
A received result (`execution.outcome: "ran"`) is an acknowledgment, not verification. An operation reports `outcome: inspected`, `verified`, or `failed`; an ambiguous apply throws `write-uncertain`. Inspect/apply require explicit `ok: true`. Readback must supply real observations; empty objects, primitives and `problems: []` alone do not verify a write. Failed independent verification retains inspect/apply/readback evidence in the report and causes CLI writes to exit nonzero.
|
|
83
|
+
|
|
84
|
+
For registered writes, supply an explicit `verify({ inspect, apply, readback })` returning a list of problems, or return `verification: { expected: { count: 2 }, actual: { count: measuredCount } }` from readback. Both observations must be nonempty objects; the default verifier compares them structurally. Read `actual` from the real file independently. Code that copies its expected values into actual is not independent evidence. The verifier and read declarations remain trusted project code. Structural verification, visual review and owner approval are separate steps.
|
|
85
|
+
|
|
48
86
|
## Baselines for a check
|
|
49
87
|
|
|
50
88
|
`penpair baselines` hands a page's design to a check that compares the implementation against images. It reads the `baselines` block of `penpair.config.json`:
|
|
@@ -91,3 +129,39 @@ export default defineReflection({
|
|
|
91
129
|
`baselineRoot` in the generated cases is relative to the Reflection config's folder, so keep the two in the same project root. The same images work with any other image comparison; the Reflection cases are one output of the manifest.
|
|
92
130
|
|
|
93
131
|
The percentage a comparison reports is not a verdict: a correct implementation differs from a Penpot render by about 1 to 2% on text alone, so read the diff image.
|
|
132
|
+
|
|
133
|
+
Interrupted write recovery, run inspection and optional checkpoints: [recovery guide](recovery.md).
|
|
134
|
+
|
|
135
|
+
Baseline schema 2 keeps current capture and original approval provenance separate, publishes immutable image generations, and requires a complete capture. See [artifact publication](artifacts.md) for paths, migration and interruption behavior.
|
|
136
|
+
|
|
137
|
+
For scripts and tools, use the versioned [command result contract](command-contract.md): command-specific JSON now lives under `data`, progress uses stderr, and incomplete/uncertain/cancelled outcomes have explicit exit codes.
|
|
138
|
+
|
|
139
|
+
Adapters, snippet definitions and theme files execute trusted project code. Built-in help/inspection avoid adapter imports; use `snippets --builtins-only` for the shipped registry. See [extension trust boundaries](extensions-trust.md).
|
|
140
|
+
|
|
141
|
+
Use `skills install --agents AGENTS.md --dry-run` to preview owned-marker instruction integration, then repeat without dry-run. Default destination selection and conflicting instruction files are explained in [skill installation](skill-installation.md).
|
|
142
|
+
|
|
143
|
+
Use `export --name <exact-name> --page <page> <out.png>` when a rebuild changed IDs, or `shots --page <page> --prefix <prefix>` for ad-hoc captures without baseline approval. See [named exports and shots](shots.md).
|
|
144
|
+
|
|
145
|
+
Normal operations and captures now use [bounded layout settling](layout-settling.md). Layout evidence, independent postcondition checks, stable renders and visual approval remain distinct.
|
|
146
|
+
|
|
147
|
+
## Complete inspection
|
|
148
|
+
|
|
149
|
+
Use `inspect <shape-id> --page <name> --all` for bounded structured evidence with full text and typed properties. `tree` and audit examples remain previews. See [inspection formats, budgets and migration](inspection.md) before consuming captures or cursors.
|
|
150
|
+
|
|
151
|
+
## Token editing
|
|
152
|
+
|
|
153
|
+
`tokens add-set`, `set`, `remove` and `promote` inspect first and require `--apply` for guarded writes. See [semantics, bounds and recovery](token-editing.md).
|
|
154
|
+
|
|
155
|
+
## Plugin bodies from files
|
|
156
|
+
|
|
157
|
+
`run-file script.js --include helpers.js --param key=value --page Candidate` runs trusted declared reads. Reviewed write files require explicit inspection/readback files, idempotency declarations and `--apply`. See [script contracts, examples and recovery](run-file.md).
|
|
158
|
+
|
|
159
|
+
## Build helpers and recipes
|
|
160
|
+
|
|
161
|
+
`run-file --include @kit` adds neutral token-aware helpers; configured adapters can supply explicit additional aliases. `kit check` compiles selected kits offline and `recipes` lists their metadata. See [build kit, recipes and scratch probe](build-kit.md).
|
|
162
|
+
|
|
163
|
+
## State, theme and responsive coverage
|
|
164
|
+
|
|
165
|
+
Add explicit `frames[].case` metadata and a required matrix under `baselines.coverage`. `baselines coverage --json` validates approved images offline and exposes missing/unsupported slots. Rich cases remain pending browser setup mappings; see [coverage semantics and approval](coverage.md).
|
|
166
|
+
|
|
167
|
+
For project-specific agent tools, use the [explicit-root stdio server and client examples](mcp.md). It exposes typed guarded services and defaults to omitting design-write tools.
|
package/docs/handoff.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Derived design handoff
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
penpair spec --page Dashboard --frame FRAME_ID --out design/specs/dashboard.md
|
|
5
|
+
penpair spec --from design/inspections/dashboard.json --map design/component-map.json --out design/specs/dashboard.md
|
|
6
|
+
penpair spec check --from design/inspections/dashboard.json --map design/component-map.json --out design/specs/dashboard.md
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The live command reuses the complete, bounded I8 inspection under the configured strict file guard. The offline command accepts a complete `inspect ID --page PAGE --all --out FILE` capture. Incomplete, redacted, disconnected or inconsistent trees refuse publication. The command writes only a local derived document; page switching is the usual inspection operation. `--frame` is an immutable ID; resolve names explicitly with the existing inspection tools first.
|
|
10
|
+
|
|
11
|
+
The schema-1 handoff records exact file/page/frame/revision, deterministic structured source hash and explicit mapping hash. It preserves hierarchy, layout, geometry, full text, style, token bindings, component source/overrides and per-field unknowns. A single atomically written Markdown document embeds its provenance and literal JSON evidence. Design text, names and mapping hints remain untrusted data in a safely sized fence, with bidirectional controls escaped; they never become executable JSX or agent instructions. Review unknown semantics before implementing.
|
|
12
|
+
|
|
13
|
+
An optional schema-1 component map names exact source identities:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"schemaVersion": 1,
|
|
18
|
+
"components": [{
|
|
19
|
+
"libraryId": "OWNER_REVIEWED_LIBRARY_ID",
|
|
20
|
+
"componentId": "OWNER_REVIEWED_COMPONENT_ID",
|
|
21
|
+
"codeComponent": "StatTile",
|
|
22
|
+
"props": {"tone":"success"},
|
|
23
|
+
"textProps": {"label":"EXACT_DESCENDANT_TEXT_NODE_ID"}
|
|
24
|
+
}]
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Names and equal pixels do not establish a mapping. There are no guessed library IDs in shipped maps: the adapter's native component catalogue awaits C1 proof. Static scalar props are owner-declared hints; text props resolve only explicit descendants of that instance. Missing text IDs stay unknown. No inferred click handlers, state transitions, keyboard behavior, accessibility roles, focus order or responsive layout claims are emitted. The current recorded state does not describe every breakpoint or theme.
|
|
29
|
+
|
|
30
|
+
`spec check` regenerates from the supplied structured capture and map, detecting manual edits, source/revision changes and mapping changes (exit 2). It does not contact Penpot or establish current live freshness. A PNG export manifest alone cannot prove structural/text freshness; use a new structured inspection rather than treating an unchanged image as proof. Live human handoff/adoption acceptance remains pending under I12; native mapping generation remains gated under C1. JSON output uses the shared command envelope.
|
|
31
|
+
|
|
32
|
+
Owner review can be retained as an [exact-artifact approval record](approvals.md). Changed baseline references require matching supplied owner words or an explicitly labeled waiver; a comparison metric does not supply approval.
|