kaloko 0.3.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.
Files changed (68) hide show
  1. package/README.md +119 -0
  2. package/bin/kaloko.mjs +4 -0
  3. package/bin/qawalk.mjs +4 -0
  4. package/package.json +42 -0
  5. package/schemas/bundle.v1.json +19 -0
  6. package/schemas/config.v1.json +268 -0
  7. package/schemas/revision.v1.json +36 -0
  8. package/schemas/run.v1.json +549 -0
  9. package/schemas/scenario.v1.json +668 -0
  10. package/schemas/tokens.v1.json +102 -0
  11. package/skills/kaloko/SKILL.md +94 -0
  12. package/skills/kaloko/reference/acceptance.md +208 -0
  13. package/skills/kaloko/reference/apps.md +161 -0
  14. package/skills/kaloko/reference/collaboration.md +218 -0
  15. package/skills/kaloko/reference/design.md +143 -0
  16. package/skills/kaloko/reference/documentation.md +72 -0
  17. package/skills/kaloko/reference/environments.md +140 -0
  18. package/skills/kaloko/reference/evaluation.md +62 -0
  19. package/skills/kaloko/reference/execution.md +75 -0
  20. package/skills/kaloko/reference/mcp.md +69 -0
  21. package/skills/kaloko/reference/stacks.md +122 -0
  22. package/src/cli.mjs +1344 -0
  23. package/src/lib/access.mjs +169 -0
  24. package/src/lib/apps/capture.mjs +59 -0
  25. package/src/lib/apps/drivers.mjs +284 -0
  26. package/src/lib/apps/helper.swift +102 -0
  27. package/src/lib/apps/tree.mjs +222 -0
  28. package/src/lib/browser-daemon.mjs +41 -0
  29. package/src/lib/browser.mjs +161 -0
  30. package/src/lib/build.mjs +149 -0
  31. package/src/lib/calibrate.mjs +97 -0
  32. package/src/lib/capture.mjs +233 -0
  33. package/src/lib/compare.mjs +88 -0
  34. package/src/lib/config.mjs +117 -0
  35. package/src/lib/console.mjs +13 -0
  36. package/src/lib/coverage.mjs +75 -0
  37. package/src/lib/design-cli.mjs +440 -0
  38. package/src/lib/design-core.mjs +163 -0
  39. package/src/lib/design.mjs +164 -0
  40. package/src/lib/doctor.mjs +149 -0
  41. package/src/lib/draft.mjs +76 -0
  42. package/src/lib/drift.mjs +145 -0
  43. package/src/lib/evaluate.mjs +222 -0
  44. package/src/lib/git.mjs +70 -0
  45. package/src/lib/htmlview.mjs +130 -0
  46. package/src/lib/jev.mjs +95 -0
  47. package/src/lib/mail.mjs +182 -0
  48. package/src/lib/manifest-core.mjs +127 -0
  49. package/src/lib/pack-help.mjs +55 -0
  50. package/src/lib/packs.mjs +121 -0
  51. package/src/lib/pr.mjs +78 -0
  52. package/src/lib/probe.mjs +379 -0
  53. package/src/lib/recheck.mjs +70 -0
  54. package/src/lib/run.mjs +85 -0
  55. package/src/lib/scenario.mjs +98 -0
  56. package/src/lib/schema.mjs +25 -0
  57. package/src/lib/secrets.mjs +59 -0
  58. package/src/lib/service.mjs +52 -0
  59. package/src/lib/stack.mjs +130 -0
  60. package/src/lib/tokens.mjs +352 -0
  61. package/src/lib/util.mjs +97 -0
  62. package/templates/ACCEPTANCE.md +55 -0
  63. package/templates/cs/ACCEPTANCE.md +55 -0
  64. package/templates/kaloko.config.yml +76 -0
  65. package/templates/mail/letter-opener.mjs +47 -0
  66. package/templates/scenario.yml +119 -0
  67. package/templates/steps/consent.mjs +33 -0
  68. package/viewer/index.html +2772 -0
@@ -0,0 +1,218 @@
1
+ # Collaboration: share, feedback, inbox
2
+
3
+ A run becomes useful when the people who decide can see it. The loop that
4
+ works for teams using Kaloko:
5
+
6
+ 1. **Share the run** (`kaloko share`, tester token, after asking). The
7
+ command prints the canvas URL.
8
+ 2. **Put the link where the work is tracked.** When the branch has a pull
9
+ request and `gh` is signed in, `kaloko share --pr` posts one comment per
10
+ scenario on it (summary line, canvas link, criteria that need attention
11
+ with evidence) and updates that same comment on every later run, so the
12
+ PR never fills up with Kaloko noise. Otherwise write the comment yourself:
13
+ what was tested (scenario, environment, locales), the summary line
14
+ (`n/m steps passed`), every failing or `needs_review` criterion with
15
+ evidence, and the canvas URL. Reviewers accept, return or comment on the
16
+ canvas.
17
+ When the organization connected the Kaloko GitHub App (Settings →
18
+ Integrations), the same share also creates a check on the pull request
19
+ that waits for review and turns green or red with the verdict; do not
20
+ report it as passed before a person accepted the run.
21
+ 3. **Read feedback before continuing.** `kaloko feedback` lists the run
22
+ verdict, open rejections and comments, and failed manual criteria.
23
+ `kaloko inbox` lists what needs your attention across runs: mentions,
24
+ returned runs, rejected steps in your runs, new runs of scenarios you
25
+ reviewed, and expiry warnings. Both take `--json`; `kaloko inbox --read`
26
+ marks the shown items read.
27
+ 4. **Work through the comments, then close them.** See *Processing
28
+ feedback* below.
29
+ 5. **A returned run means fix, then a new run.** Runs are immutable; never
30
+ patch a shared run. Start a new one on the same scenario, share it and
31
+ reply in the tracker with the new link. The reviewer who returned it is
32
+ told about the new run automatically.
33
+
34
+ ## Processing feedback
35
+
36
+ Comments are threads in three places:
37
+
38
+ - **A step:** optionally pinned to a position on the screenshot
39
+ (`pin: {x, y}` as fractions, per viewport) or to an element of a live
40
+ design step (`anchor`).
41
+ - **The whole run:** `node_id` is `''`.
42
+ - **The whole flow:** these stay across runs, e.g. "add the empty-cart
43
+ state".
44
+
45
+ `kaloko feedback` (or MCP `get_feedback` / `list_comments`) shows the open
46
+ ones with their ids and replies. A comment written by an agent carries the
47
+ agent's name (`KALOKO_AGENT`, e.g. `claude-code`), so people can tell who
48
+ said what.
49
+
50
+ The loop, for every open thread:
51
+
52
+ 1. **Understand it.** Open the canvas link when a pin or an element
53
+ matters; the position is on the screenshot of that viewport and locale.
54
+ 2. **Fix it** in the code or the scenario. When the comment asks for a
55
+ change of intent (criteria, scope), ask the person first.
56
+ 3. **Answer and close.** Use
57
+ `kaloko comment --resolve <id> --note "Fixed in <commit>: <what changed>"`
58
+ (add `--flow` for flow comments; MCP `resolve_comment` takes the same
59
+ `note`). The closing note is a reply in the thread, and the author is
60
+ told in their inbox.
61
+ 4. **When you disagree or need a decision,** reply with
62
+ `kaloko comment --reply <id> --note "…"` and leave the thread open.
63
+ Mention the person with `@name` when they must act; mentions are mailed
64
+ at once.
65
+ 5. **Share a new run** once the fixes are in, and link it in the tracker.
66
+ Resolved threads stay visible under "Resolved" on the canvas.
67
+
68
+ Rules:
69
+
70
+ - Never resolve a thread you did not address.
71
+ - Never delete other people's comments; the service refuses anyway.
72
+ - Your own comment may be edited (`--edit <id>`) or deleted (`--delete <id>`).
73
+ - A rejected step (`status: rejected`) is feedback like any other: fix it,
74
+ resolve it, share again.
75
+
76
+ People see open counts next to flows and runs in the app, on map nodes and
77
+ index rows, and in the canvas's *Comments* panel (`#comments=all|run|flow`
78
+ in a link). Mails:
79
+
80
+ - **Right away:** mentions, rejected steps, returned runs and runs waiting
81
+ for approval.
82
+ - **In the digest:** new comments, replies, resolutions and new runs, as a
83
+ daily or weekly mail grouped by flow.
84
+
85
+ ## Presenting a run
86
+
87
+ For stakeholders who do not read canvases, open the run in **Replay**
88
+ (button in the top bar, key `R`, or `#replay=1` in the URL): one step at a
89
+ time with its screenshot, purpose and criteria, a single *Next* action, and a
90
+ choice of branch at every decision node. `#replay=1&step=<id>&path=a,b,c`
91
+ deep-links a specific path, so an issue comment can point at "the sign-in
92
+ branch, step 3". Replay reads the manifest only; nothing is uploaded.
93
+
94
+ For people who work through a list rather than a flow (QA leads, content
95
+ and SEO teams, big runs), switch the canvas to **Index**. Use *Map | Index*
96
+ in the top bar, the key `I`, or `#mode=index` in the URL.
97
+
98
+ - **Rows:** every step in flow order, grouped by section. Each row shows
99
+ a thumbnail, status, passed criteria, failing criteria, HTTP status and
100
+ console errors.
101
+ - **Filtering:** by status, plus search over titles, paths and criteria.
102
+ The search also reaches the pages inside stacks.
103
+ - **Stacks:** a stack step is a folder. Opening it shows its page index
104
+ with a breadcrumb back to the run.
105
+ - **Navigation:** the sidebar selects rows, and the lightbox's previous and
106
+ next follow the filtered list.
107
+ - **Export:** CSV of the rows.
108
+ - **Links:** `#mode=index&step=<stack>` links straight into a folder.
109
+
110
+ ## Public runs
111
+
112
+ An admin can make one run per scenario **public** (canvas report → *Make
113
+ public*, or `kaloko public --run <id>`): readable without sign-in, reviewer
114
+ names hidden, embeddable in an iframe. Use it for demos, status pages or
115
+ sharing with people outside the organization, and only for scenarios that
116
+ show no personal data. A tester token may later move the flag to a newer run
117
+ of that scenario, which is how a scheduled demo refresh works.
118
+
119
+ ## Staying informed without the app
120
+
121
+ Members choose in Settings → Profile a daily or weekly e-mail digest of
122
+ their unread inbox and whether to get an immediate mail when their run is
123
+ returned or a step rejected; every mail has an unsubscribe link. Admins can
124
+ connect one Slack channel (Settings → Integrations, "Add to Slack") that
125
+ receives new shared runs, rejected steps and run verdicts. None of this
126
+ changes what agents do: share the run, post the link, read the feedback.
127
+
128
+ ## Mentions
129
+
130
+ `@name` in a comment or verdict note notifies that colleague in the app
131
+ (the part of their e-mail before `@`, e.g. `@anna` or `@anna.novak`; a full
132
+ e-mail works too). Use it when a step needs a decision from a specific person
133
+ (design, legal, product owner) instead of asking in chat.
134
+
135
+ ## Verdicts and baselines
136
+
137
+ - Reviewers set a **run verdict**: accepted, returned (with a note) or
138
+ pending. Testers see the note in `kaloko feedback` and in the inbox.
139
+ - An accepted run may be the scenario's **baseline**. Later runs compare
140
+ against it; report differences against the baseline, not only against the
141
+ previous run.
142
+ - `kaloko compare [--run <id>] [--baseline <id>] [--json]` prints the text
143
+ diff (step statuses, criterion verdicts, scores, evidence) of the current
144
+ run against the baseline, or the previous run when there is no baseline.
145
+ Put the relevant lines in the issue comment. On the canvas the same
146
+ comparison is the **Compare** selector in the top bar (or `#cmp=<run>` in
147
+ the URL): pixel differences per step, changed criteria, and a side-by-side
148
+ or diff view in the lightbox. Pixel diffs are computed in the browser;
149
+ nothing is uploaded.
150
+ - **Manual criteria** are decided on the canvas by a reviewer; treat a
151
+ reviewer's `fail` like a failing deterministic check.
152
+ - Admins may name **required approvers** per scenario (Settings). Such a
153
+ run stays `pending` until every one of them approved; `kaloko feedback`
154
+ prints `awaiting approval from: …`, so do not treat a single approval as
155
+ acceptance there.
156
+
157
+ ## Cleaning up runs
158
+
159
+ Re-running a scenario after every fix is expected, and it fills the list: the
160
+ scenario list (the organization home) shows one row per scenario, and `/runs`
161
+ shows the newest run per scenario with "+ N older" unless a filter is set.
162
+ Clean up so the history stays readable; everything goes to the trash, which
163
+ can be restored until it is purged.
164
+
165
+ ```bash
166
+ npx kaloko runs # newest run per scenario, "+ N older"
167
+ npx kaloko runs --scenario TASK-1273-cart # every run of one scenario
168
+ npx kaloko trash <run-id>... # soft delete (uploader or admin); kaloko restore <run-id>
169
+ npx kaloko prune --scenario TASK-1273-cart --keep 3 # dry run: lists what would go
170
+ npx kaloko prune --scenario TASK-1273-cart --keep 3 --yes # ask first
171
+ npx kaloko keep <run-id> # never expires, never pruned (--off to undo)
172
+ npx kaloko archive TASK-1273-klub # retired scenario, ask first (admin); --undo
173
+ ```
174
+
175
+ - **Without asking:** trash runs you uploaded in this session that were
176
+ superseded before anyone looked at them (debug rounds without comments or a
177
+ verdict), and a dry-run `prune`.
178
+ - **Ask first:** `prune --yes`, trashing someone else's run, archiving a
179
+ scenario.
180
+ - **Never:** trash an accepted run, a baseline, a run with review comments, or a
181
+ run linked from an open PR or issue comment. `prune` already keeps kept,
182
+ accepted, baseline, design-reference and commented runs, and without the admin
183
+ role it trashes only your own runs.
184
+ - After splitting or renaming a scenario, propose archiving the old one
185
+ (`archived: true` in its file, or `kaloko archive <id>`). `kaloko validate`
186
+ warns when the service still lists a scenario whose file is gone.
187
+ - Report clean-ups in the tracker next to the run links: which runs went to the
188
+ trash and why.
189
+
190
+ An organization admin can turn on automatic clean-up after each share in
191
+ Settings → Storage (keep the newest N per scenario and environment).
192
+
193
+ ## API for agents and CI
194
+
195
+ Everything above is available over the API with an organization token:
196
+
197
+ - `GET /api/v1/orgs/<org>/feedback?run=<id|latest>[&scenario=<id>]`
198
+ - `GET|POST /api/v1/orgs/<org>/runs/<id>/comments` (a step: `node_id`;
199
+ the whole run: `node_id: ""`), `GET|POST …/scenarios/<id>/comments`
200
+ (the whole flow), and per comment `PATCH`, `DELETE`, `POST …/<cid>/resolve`
201
+ (with `note`) and `…/<cid>/reopen`; `GET /api/v1/orgs/<org>/comments?state=open|all&scenario=&run=&mine=1`
202
+ across the organization. Lists of runs and scenarios carry `open_comments`.
203
+ - `GET /api/v1/orgs/<org>/notifications[?unread=1]`, `POST` with
204
+ `{"read": "all"}` or `{"read": [ids]}`
205
+ - `GET /api/v1/orgs/<org>/runs[?project=&scenario=&kind=&verdict=&author=&environment=&branch=&q=][&latest=1]`
206
+ (`latest=1`: the newest run per scenario with `older`), `GET /api/v1/orgs/<org>/runs/<id>`
207
+ - Clean-up: `DELETE …/runs/<id>` (trash), `POST …/runs/<id>/restore`,
208
+ `POST …/runs/<id>/keep` with `{"keep": true|false}`,
209
+ `POST /api/v1/orgs/<org>/runs/prune` with `{ scenario?, project?, environment?, keep_latest: 3, older_than_days?, dry_run: true }`
210
+ (answers `trash` and `kept` with reasons), `POST …/scenarios/<id>/archive`
211
+ and `…/unarchive` (admin)
212
+ - `GET /api/v1/orgs/<org>/runs/<id>/export.zip` (`kaloko export`): the whole
213
+ run as a zip before it expires; keep it with the issue when the evidence
214
+ must outlive the retention period.
215
+ - MCP server for agents: see [mcp.md](mcp.md).
216
+
217
+ Read-only tokens may list but not change anything; keep CI tokens read-only
218
+ unless the job publishes runs.
@@ -0,0 +1,143 @@
1
+ # Design with Kaloko
2
+
3
+ Kaloko hosts designs as live HTML steps of the same scenario that development and QA use. You design with
4
+ whatever skill, model and style the person uses; Kaloko keeps the draft, the versions, the comments and the
5
+ design reference, and checks the implementation against it. This reference says how to fit your work into
6
+ that. It says nothing about how a design should look.
7
+
8
+ ## Design environments
9
+
10
+ A design environment is a folder the CLI serves while it walks:
11
+
12
+ ```yaml
13
+ # kaloko.config.yml
14
+ environments:
15
+ design: { kind: design, serve: design }
16
+ ```
17
+
18
+ `kaloko start --scenario qa/flows/checkout.yml --env design` starts a run of it. The scenario is the one the
19
+ implementation uses: same step ids, same criteria. Design steps meet the acceptance criteria too (headings,
20
+ labels, semantic questions), so a design is accepted before anyone builds it. Checks against the design
21
+ reference (`design_pixels`, `design_structure`) are left out on a design environment.
22
+
23
+ ## The bundle
24
+
25
+ ```
26
+ design/
27
+ tokens.json token set (W3C DTCG), optional
28
+ _shared/app.css shared files: fonts, styles, images, scripts
29
+ cart/index.html one folder per step id
30
+ cart/cs/index.html optional override for a locale
31
+ payment/index.html
32
+ ```
33
+
34
+ - Plain HTML, CSS, JS and assets only (`qawalk.bundle.v1`: html, css, js, mjs, json, svg, woff2, woff, png,
35
+ jpg, webp, avif, gif, mp4, webm, txt). No build step on the service side: build locally, keep the output.
36
+ - A step's revision is its page, the files next to it and everything its page references (stylesheets,
37
+ images, fonts, module imports, `fetch('./fixtures/x.json')`). Links to other steps are not files it needs.
38
+ - Live steps run sandboxed on their own origin with `connect-src 'self'`: no real APIs. Use JSON fixtures in
39
+ the bundle.
40
+ - Prototype links: `<a data-qawalk-go="payment">` moves the canvas to that step, whatever the `href` says.
41
+ - Reference token values as CSS custom properties (`var(--color-accent)`), so the inspector and the token
42
+ check see where values come from.
43
+
44
+ ## Sync and publish
45
+
46
+ - `kaloko walk` renders only revisions whose captures are missing (same files, same capture).
47
+ - `kaloko status` shows each step: synced, changed here, changed in the draft, conflict; and its step status.
48
+ - `kaloko sync` saves your changed steps into the shared draft and takes steps others changed. A step changed
49
+ on both sides is a conflict: name it with `--mine <step>` or `--theirs <step>`; never delete to resolve.
50
+ - `kaloko share` on a design environment publishes a version of the flow (`v4 · 3 changed, 17 unchanged`).
51
+ A version counts as a shared run. Publish when the person asks, not after every change.
52
+ - Step status (`in progress`, `ready for review`, `ready for dev`) is set in the canvas or with MCP
53
+ `set_step_status`; `ready for dev` notifies followers.
54
+ - Set `KALOKO_AGENT=<your name>` so people see your writes as yours in presence, history and audit.
55
+
56
+ ## The loop
57
+
58
+ 1. Design or change steps in the folder with the person's design skill.
59
+ 2. `kaloko walk` (and `kaloko evaluate` if the step has semantic criteria), `kaloko sync`.
60
+ 3. Read `kaloko feedback` on the design environment: open comments, pinned ones with their element
61
+ (`on main > label`). People comment in the canvas; they may be looking right now.
62
+ 4. Change what the comments ask, sync again, then answer in the comment thread (MCP `add_draft_comment`).
63
+ 5. When the person is happy, `kaloko share --name "…"` publishes a version.
64
+
65
+ ## References
66
+
67
+ - The design reference is an accepted version: `kaloko reference --design --version 4` (a person accepts the
68
+ version first; ask before setting a reference).
69
+ - The baseline stays the last good implementation run: `kaloko reference --baseline --run <id>`.
70
+ - Changing the design reference changes what implementation runs are checked against: tell the team.
71
+
72
+ ## Handoff
73
+
74
+ Development builds from the design reference:
75
+
76
+ - `kaloko export --live [--version n] --out design/` writes the live files into a folder.
77
+ - MCP `get_step` (scenario, step, `ref: design`) returns the file list, a signed entry URL, the token set, the
78
+ page structure and open comments; `list_step_changes` names the steps that changed since the last reference.
79
+ - Translate to the project's stack with the project's own skills; keep the step ids and the token names.
80
+
81
+ ## Tokens
82
+
83
+ - The set is W3C DTCG. Both value styles are read: strings (`"#2E6BFF"`, `"16px"`) and the current format's
84
+ objects (`{ "colorSpace": "srgb", "components": [...], "hex": "#2e6bff" }`, `{ "value": 16, "unit": "px" }`),
85
+ composite types (typography, shadow, border, transition, gradient), aliases `{group.token}` and
86
+ `{ "$ref": "#/json/pointer" }`, `$extends`, `$root` and `$deprecated`. New sets: prefer the object values.
87
+ - Modes (light, dark): a DTCG resolver `design/tokens.resolver.json` (sets plus a `theme` modifier whose
88
+ contexts point at files) wins over `tokens.json`; `push` inlines its files. Older sets with top-level
89
+ `light`/`dark` groups still work. `tokens_mode` in the environment picks the mode the checks use.
90
+ - `kaloko tokens validate` reports names with `{`, `}` or `.`, references that point nowhere and values that
91
+ cannot be read; `push` refuses a set with problems, so does the service.
92
+ - `kaloko tokens push` stores the set as the project's next token set version; `pull` gets it.
93
+ - `kaloko tokens check` lists raw colors, fonts, sizes, spacing and radii in the design folder that are not in
94
+ the set, with the nearest token; a value that only a deprecated token has is named with its note.
95
+
96
+ ## Checking implementation
97
+
98
+ Turn on `packs: [design]` (usually `[design, a11y]`) for the steps in the implementation scenario:
99
+
100
+ | Id | Checks |
101
+ |---|---|
102
+ | AC801 | pixels: under 3 % differ from the design reference (same algorithm as the canvas) |
103
+ | AC802 | structure: headings, landmarks, actions and form fields as in the reference |
104
+ | AC803 | tokens: authored colors, fonts, sizes, spacing and radii come from the token set |
105
+
106
+ Contrast and the other accessibility basics come from the `a11y` pack: `packs: [design, a11y]`.
107
+
108
+ `kaloko evaluate` fetches the design reference (of the design branch linked to the git branch, if any) and
109
+ fills the checks. Findings name what differs and the token to use; fix the implementation, not the reference.
110
+
111
+ ## Canvas edits
112
+
113
+ People can change a step's text and assign tokens in the canvas inspector. Each edit is a new revision; a file
114
+ shared by several locales changes for all of them. `kaloko sync` pulls the edit into the folder as a
115
+ `<style data-qawalk-edits>` block and changed text: fold the rules into the real stylesheet when you next touch
116
+ the step, then sync.
117
+
118
+ ## Branches
119
+
120
+ - `kaloko branch create redesign --git feat/redesign` starts a branch of the draft; `--from v4` starts from a
121
+ version. Work on it with `--branch redesign` on `sync`, `status` and `share`.
122
+ - The folder mirrors one branch at a time; switching (`kaloko sync --branch main`) takes that branch's steps
123
+ and never pushes the other branch into it.
124
+ - Merging is the person's decision: `kaloko branch merge redesign`; steps changed on both sides need
125
+ `--take-branch <step>` or `--keep-main <step>`.
126
+
127
+ ## HTML view
128
+
129
+ Experimental, Business plan. `html_view: true` on an app environment keeps a static, script-free copy of each
130
+ captured page (secrets and hidden values removed) that opens in the canvas like a live step, so the inspector
131
+ works on the real product. It is refused on production pages behind a sign-in. `kaloko export --live --views
132
+ --run <id> --out design/` turns those copies into design steps: a redesign that starts from the product.
133
+
134
+ ## Bring your own design skill
135
+
136
+ Any skill works if it writes the bundle layout above:
137
+
138
+ - a design skill of Claude or another agent: ask it to write `design/<step>/index.html` per scenario step and
139
+ shared files into `design/_shared/`;
140
+ - a brand or design-system skill: have it produce `tokens.json` and the shared CSS;
141
+ - a Figma export through the person's own tooling (for example a Figma MCP server): convert frames to HTML
142
+ per step, then walk and sync;
143
+ - hand-written HTML is fine.
@@ -0,0 +1,72 @@
1
+ # Documentation from runs
2
+
3
+ A run is also a library of reference captures: every step, locale and
4
+ viewport has a screenshot and the HTML. On the Business plan the service
5
+ gives each step a stable address, lists what changed, and calls you when a
6
+ run is accepted, so a manual, a course or product documentation can be
7
+ rebuilt from the newest accepted run instead of screenshotting by hand.
8
+
9
+ ## Prepare the run
10
+
11
+ - Walk the scenario as usual and let a person accept the run on the canvas;
12
+ documentation should come from accepted (or baseline) runs only.
13
+ - Tag the release (`git tag v2.4.0`) before `kaloko start`, or pass
14
+ `--app-version 2.4.0`; the version lands in the manifest as `app_version` and in every
15
+ latest-capture answer, so the documentation can say which version it shows.
16
+ - Accepted and baseline runs do not expire on Business and Enterprise.
17
+
18
+ ## Stable URLs
19
+
20
+ With an organization token (`Authorization: Bearer qwk_…`, a read-only
21
+ viewer token is enough):
22
+
23
+ ```
24
+ GET /api/v1/orgs/<org>/scenarios/<scenario>/steps step index with links
25
+ GET /api/v1/orgs/<org>/scenarios/<scenario>/steps/<step>/latest.json metadata (run with app_version, captured_at, page URL, size)
26
+ GET /api/v1/orgs/<org>/scenarios/<scenario>/steps/<step>/latest.image the screenshot (latest.webp or latest.png when you know the format)
27
+ GET /api/v1/orgs/<org>/scenarios/<scenario>/steps/<step>/latest.html the captured HTML (served sandboxed)
28
+ GET /api/v1/orgs/<org>/scenarios/<scenario>/changes steps changed since the previous accepted run
29
+ ```
30
+
31
+ Add `?locale=cs&viewport=desktop` (defaults: the run's first locale and
32
+ viewport) and `&accepted=1` to use the newest accepted run instead of the
33
+ newest run. Files answer with an `ETag`; send `If-None-Match` and a 304 means
34
+ nothing to download.
35
+
36
+ ## Only rebuild what changed
37
+
38
+ `changes` (MCP `list_step_changes`) compares the newest run with the previous
39
+ accepted one, or with `?since=<run id>`. A step is listed when it is new, its
40
+ image bytes differ, or its status changed; `removed` lists steps that are
41
+ gone. Timestamps or animations make a page count as changed, so keep
42
+ captures stable (fixed test data, no clocks on screen) for documentation
43
+ scenarios.
44
+
45
+ ## Webhooks
46
+
47
+ Settings → Integrations → Webhooks (admin): an https URL and the events
48
+ `run.accepted` and/or `run.shared`. Each call is a JSON POST
49
+ `{ id, type, created_at, org, data: { run, steps, steps_url, changes_url } }`
50
+ with `QAwalk-Signature: t=<unix time>,v1=<hex HMAC-SHA256 of "<t>.<body>">`
51
+ signed with the webhook's secret (copy it from Settings). Verify the
52
+ signature and the time (reject older than 5 minutes), answer 2xx within 5
53
+ seconds, and do the work asynchronously. Also over the API:
54
+ `GET|POST /api/v1/orgs/<org>/webhooks`, `DELETE …/webhooks/<id>`.
55
+
56
+ ## Export into a folder
57
+
58
+ ```bash
59
+ npx kaloko export --scenario checkout --accepted --out docs/assets/checkout
60
+ ```
61
+
62
+ writes `steps/<step>/<locale>/<viewport>.<ext>` and `.html` plus
63
+ `index.json` (run with app_version, captured_at, page URL per file). Run it again and
64
+ files from an unchanged run are kept, so a documentation repository sees only
65
+ real changes. `examples/docs-pipeline.mjs` in the Kaloko repository shows a
66
+ complete loop that rebuilds a Markdown manual and touches only changed steps.
67
+
68
+ ## Done means
69
+
70
+ The manual or course references the exported files (or the stable URLs), says
71
+ which application version it shows, and a re-run after a new accepted run
72
+ changes only the pages of steps listed by `changes`.
@@ -0,0 +1,140 @@
1
+ # Environments
2
+
3
+ Profiles live in `kaloko.config.yml` under `environments`. The CLI enforces
4
+ them; do not work around a block.
5
+
6
+ - `local`, `review`, `staging`: you may create the test data a scenario
7
+ needs (users with roles, carts, orders in test payment mode).
8
+ - `production`: always readonly, regardless of config. Only scenarios with
9
+ `readonly: true`, as an ordinary visitor or customer. No admin, no sign-in
10
+ to back offices, no data creation, no orders. Typical: SEO checks, landing
11
+ pages, checkout up to payment.
12
+
13
+ Test data preparation for review and staging belongs to the project's CI
14
+ prepare step; assume it exists and create only what the scenario itself needs.
15
+
16
+ ## Who does what
17
+
18
+ Kaloko needs evidence in its format: captures of screens and e-mails in a run.
19
+ How you get to them depends on the project's stack, and that part is yours.
20
+
21
+ - **The CLI handles the standards**: HTTP Basic and header tokens in front of
22
+ an environment, client certificates, a saved browser session, the readonly
23
+ policy, Mailpit, and e-mails as `.eml`, `.html`, `.json` or `.txt`.
24
+ - **You arrange the rest for this project** with its own tools and common
25
+ practice: how test users are created and signed in, where the application's
26
+ e-mails end up, how a review app's URL is known. Write that down once in the
27
+ project (config, step scripts, a mail adapter, a project skill) so the next
28
+ run does not rediscover it.
29
+ - **You ask the person** for secret values and for anything only a person can
30
+ do (an SSO or MFA sign-in, VPN access, a new test account in a system you
31
+ cannot reach).
32
+
33
+ ## Access to an environment
34
+
35
+ Three layers, each in its own place:
36
+
37
+ | Layer | Examples | Where |
38
+ |---|---|---|
39
+ | Gate in front of the whole environment | HTTP Basic, Cloudflare Access service token, Vercel protection bypass, a custom header, mutual TLS | `environments.<env>.access` |
40
+ | Sign-in to the application | form login, SSO/OAuth, MFA/TOTP | scenario `sessions` + `environments.<env>.accounts` + step scripts |
41
+ | Network | VPN, IP allowlist | not config: the machine running the agent must have access; say so when it does not |
42
+
43
+ ```yaml
44
+ environments:
45
+ staging:
46
+ base_url: https://staging.example.com
47
+ access:
48
+ origins: [https://staging.example.com, https://api.staging.example.com] # default: base_url origins
49
+ basic: { user_env: STAGING_USER, password_env: STAGING_PASSWORD }
50
+ headers:
51
+ CF-Access-Client-Id: { env: CF_ACCESS_CLIENT_ID }
52
+ CF-Access-Client-Secret: { env: CF_ACCESS_CLIENT_SECRET }
53
+ client_certificate: { cert_file: certs/qa.pem, key_env: QA_CLIENT_KEY }
54
+ accounts:
55
+ member: { user: member@example.test, password_env: STAGING_MEMBER_PASSWORD }
56
+ admin: { user_env: STAGING_ADMIN_USER, password_env: STAGING_ADMIN_PASSWORD, totp_env: STAGING_ADMIN_TOTP }
57
+ sso: {}
58
+ review:
59
+ base_url: https://${REVIEW_HOST} # review apps: CI provides the variable
60
+ ```
61
+
62
+ Rules:
63
+
64
+ - Secrets never go into `kaloko.config.yml`, a scenario or a step script.
65
+ Every `*_env` and `{ env: NAME }` names a variable; the values live in the
66
+ environment, the project `.env` (ignored by git) or `~/.config/kaloko/.env`.
67
+ Choose names that fit the project; ask the person for the values.
68
+ - The gate is sent only to `access.origins`, never to third parties (analytics,
69
+ CDNs, payment providers). List an API on another host explicitly;
70
+ `https://*.example.com` covers subdomains.
71
+ - The CLI applies the gate and the readonly policy to every browser context it
72
+ creates: the shared browser, `walk` sessions and one-off captures. A context
73
+ you create yourself over CDP does not get them; work in the shared browser's
74
+ default context, or use `walk`.
75
+ - Values the CLI knows as secrets are replaced by `[redacted]` in captured HTML,
76
+ page text and console entries. Screenshots are not redacted: do not capture
77
+ a screen that shows a secret.
78
+ - `kaloko doctor` checks that the variables are set, that the gate lets you in
79
+ (HTTP 401/403 is a failure) and that each account can sign in or has a
80
+ saved session.
81
+
82
+ ## Accounts and sign-in
83
+
84
+ A scenario session's `account` is a key; `environments.<env>.accounts.<key>`
85
+ maps it to credentials in that environment. Step scripts receive them as
86
+ `session.credentials` (`user`, `password`, `totp()`, `storage_state`) and sign
87
+ in the way the application does it:
88
+
89
+ ```js
90
+ export default async ({ page, url, session }) => {
91
+ const { user, password } = session.credentials
92
+ await page.goto(url('sign-in'))
93
+ await page.fill('input[type=email]', user)
94
+ await page.fill('input[type=password]', password)
95
+ await page.click('button[type=submit]')
96
+ if (await page.locator('input[autocomplete=one-time-code]').isVisible()) await page.fill('input[autocomplete=one-time-code]', session.credentials.totp())
97
+ }
98
+ ```
99
+
100
+ SSO or MFA that a script cannot pass: ask the person to run
101
+ `kaloko auth save --env <env> --account <key>` once. They sign in in a
102
+ visible browser; the session is saved under the output directory (owner-only,
103
+ git-ignored, never uploaded) and `walk` loads it into that account's sessions.
104
+ When the application asks for sign-in again, the session expired: ask for a
105
+ new `auth save`. `kaloko auth list` shows the saved sessions and their age.
106
+
107
+ Prefer, in this order: a test account the project already has for QA; a
108
+ seeded or API-created account on non-production environments; a saved
109
+ session. Never use a real person's account.
110
+
111
+ ## E-mails
112
+
113
+ Flows that send e-mails need the message as an `email` step. Where the
114
+ message is depends on the stack:
115
+
116
+ - **Mailpit** (built in): `mail: { provider: mailpit, url, auth, address }`.
117
+ `auth` takes `basic` and `headers` like `access`. `address` with `{run}`
118
+ gives every run its own recipient, so shared mailboxes stay apart.
119
+ - **Anything else** (letter_opener, Mailosaur, MailSlurp, IMAP, a log, the
120
+ application's own API): write a small adapter and set
121
+ `mail: { provider: script, script: qa/mail/inbox.mjs, options: {...} }`.
122
+ Its default export is `async ({ to, subject, since, options, root, env })`
123
+ and returns the newest matching message
124
+ `{ id, subject, from, to: [address], date, html, text }` or `null`;
125
+ `kaloko mail` and `walk` poll it. The package ships an example to copy:
126
+ `node_modules/kaloko/templates/mail/letter-opener.mjs`.
127
+ - **One-off or unusual**: get the message yourself and hand it over:
128
+ `kaloko mail --step <id> --file message.eml` (also `.html`, `.json` with the
129
+ message shape, `.txt`).
130
+
131
+ `kaloko mail` and `walk` take only messages received after the run started
132
+ (adapters get it as `since`), so a staging mailbox that collects everyone's
133
+ mail cannot hand over an old message silently. `--since <ISO date>` moves the
134
+ boundary, `--any-time` drops it, and `--id <message id>` takes one exact
135
+ message (subjects repeat). The canvas shows when the message arrived and warns
136
+ when it predates the run.
137
+
138
+ Pick what fits the project and keep it in the project; do not change how the
139
+ application sends mail just for QA unless the person agrees (switching a Rails
140
+ app from letter_opener to SMTP locally, for example).
@@ -0,0 +1,62 @@
1
+ # Evaluation
2
+
3
+ `kaloko walk` sends the semantic questions of each step as soon as it is captured and ends with the
4
+ verdicts: what fails and what a person should look at, per step, locale and viewport. Use that list to fix
5
+ things right away. Steps captured later with `kaloko capture` need `kaloko evaluate`; it reuses every cached
6
+ answer, so running it again is cheap.
7
+
8
+ `kaloko evaluate` combines, per capture:
9
+
10
+ - deterministic results computed in the live page at capture time (with
11
+ evidence: selector snippet, measured value);
12
+ - the semantic evaluator for semantic criteria. It is a replaceable provider;
13
+ the default is JEV by TypeSafe (`TYPESAFE_API_KEY`), which returns only a
14
+ probability per question (`score`, 0–1). Verdicts: `pass` ≥ 0.85,
15
+ `fail` ≤ 0.15, otherwise `needs_review` (thresholds in config);
16
+ - `manual` criteria stay `not_evaluated` until a reviewer decides.
17
+
18
+ Where the evaluator runs: with `TYPESAFE_API_KEY` set locally, your own key; without it, the organization's
19
+ service evaluates with its key (Team plan and up, a monthly allowance of questions; `kaloko evaluate` prints
20
+ "via Kaloko (340 of 1000 questions this month)"). Answers are cached by content locally and in the service, so
21
+ evaluating the same capture again costs nothing. `evaluators.jev.hosted: false` keeps it to your own key.
22
+ When neither is available, or the allowance is used up, semantic criteria stay `not_evaluated`; say so in the
23
+ report with the reason `kaloko evaluate` gives.
24
+
25
+ Results are cached by content hash, so re-running is cheap. The default
26
+ evaluator is text-only and most accurate in English; it is weak at numbers,
27
+ which is why those are deterministic.
28
+
29
+ When a criterion comes back `needs_review`, read the reduced state the
30
+ evaluator saw (`steps/<node>/<locale>/<viewport>.capture.json`, key `state`)
31
+ and the screenshot. Either the page is genuinely unclear (report it), the
32
+ reducer missed something (report a Kaloko bug), or the question is too broad
33
+ (narrow it with `scope`, `true`/`false`; this changes mechanics, not intent).
34
+ Check evidence of passing deterministic checks too: a match in the wrong
35
+ region (e.g. a shipping threshold instead of the product price) means the
36
+ selector needs a scope.
37
+
38
+ When the check itself was wrong (selector, pattern too broad) and the step
39
+ cannot be repeated (data created, an e-mail sent once, a state that moved
40
+ on), fix the scenario and run `kaloko evaluate --recheck [--steps a,b]`: the
41
+ deterministic checks run again against the stored HTML with page scripts off
42
+ and are marked `rechecked`; console errors, overflow and performance keep
43
+ their live result. When the page content itself is in question, capture again.
44
+
45
+ ## Quick signals
46
+
47
+ Beside the criteria, every captured screen gets three cheap questions in the same evaluator request: does the
48
+ page do what the step's `purpose` says, is its text in the expected language, does it look broken (an error,
49
+ placeholder text, a blank page). They never change a verdict; the canvas marks a screen with ⚠ when one is
50
+ off (purpose or language at 30 % or less, broken at 70 % or more). Mention them in the report when they
51
+ disagree with passing criteria: it usually means a criterion is missing. `evaluators.jev.signals: false`
52
+ turns them off; they do not count against the hosted allowance.
53
+
54
+ ## Reporting
55
+
56
+ After `kaloko build`, report: the summary line, each failing or
57
+ `needs_review` criterion with step, locale, viewport and evidence, blocked
58
+ requests if any, and the preview path. Do not claim a criterion passed when
59
+ it was not evaluated.
60
+
61
+ `needs_review` is not a failure: look at the screenshot and state your
62
+ reading, or leave it to the reviewer.