kaloko 0.4.7 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -64,6 +64,32 @@ npx kaloko share --pr # upload to kaloko.app, comment on the PR
64
64
  `npx kaloko help` lists every command. When something does not work (Chrome,
65
65
  token, environment URL, evaluator key), `npx kaloko doctor` says what to fix.
66
66
 
67
+ ## Review only what changed
68
+
69
+ After `kaloko share`, steps that look exactly as they did in the last accepted
70
+ run (same screenshots, same criteria, automatic checks passing) keep the
71
+ approval a person gave them, with who and when. The rest waits in review
72
+ mode: one step at a time on the canvas, `J`/`K` to move, `A` to approve, `R`
73
+ to return with a note. The share says it in one line:
74
+
75
+ ```
76
+ 12 steps unchanged, approvals carried over; 5 need review: https://kaloko.app/acme/runs/…/#review
77
+ ```
78
+
79
+ `npx kaloko review` (or `--json`, or MCP `get_review_queue`) tells an agent
80
+ what still waits for a person, so it can pass the link on. Agents never
81
+ approve for people: their decisions are marked and do not count as a
82
+ person's.
83
+
84
+ Every AI verdict comes with one sentence saying why. Criteria marked
85
+ `vision: true`, and answers the text evaluator is unsure about, get a second
86
+ look at the screenshot from a vision model (`ANTHROPIC_API_KEY`, or through
87
+ Kaloko); `kaloko build` lists what to act on with the score and the reason.
88
+ The `a11y` pack walks the page with Tab (order, visible focus, traps, skip
89
+ link) and reads names from the accessibility tree. Pixel diffs skip the
90
+ regions a step ignores; `kaloko walk --stability 3` and `kaloko stability`
91
+ find the clocks, ads and carousels worth ignoring.
92
+
67
93
  ## Design (Kaloko Design)
68
94
 
69
95
  Design the screens of a flow as live HTML with your own agent and skills, in the same scenario that development
@@ -81,6 +107,17 @@ npx kaloko share --name "Checkout v2" # a version of the whole flow
81
107
  npx kaloko reference --design --version 2 # after the team accepted it
82
108
  ```
83
109
 
110
+ Developers and their agents build from what was approved. *Dev mode* (`D` in the step detail) shows each
111
+ element's box, sizes and distances, its colors, type and spacing with the token every value comes from (or a
112
+ warning when it is not a token), contrast against WCAG AA, the `:hover`, `:focus`, `:active` and disabled states,
113
+ and its images. The same data is the step spec an agent reads, and `kaloko drift` checks the implementation
114
+ against it:
115
+
116
+ ```bash
117
+ npx kaloko spec payment # elements, styles → tokens, states (also MCP get_step_spec)
118
+ npx kaloko walk && npx kaloko drift # expected token vs actual value per element; exit 1 while it differs
119
+ ```
120
+
84
121
  On the canvas, *Prototype* (or `P`) presents the steps full screen as live pages: click through links between
85
122
  steps, switch the device, walk with the arrow keys, and share a link that opens straight into a step. The rules
86
123
  for pages that work everywhere are in `skills/kaloko/reference/portable-html.md`.
@@ -121,10 +158,12 @@ captured HTML, page text and console output.
121
158
  - **E-mails**: built-in Mailpit client; any other mailbox through a small
122
159
  adapter module (`provider: script`, example in `templates/mail/`), or hand a
123
160
  message over with `npx kaloko mail --step <id> --file message.eml`.
124
- - **Service and evaluator**: `KALOKO_TOKEN` for `share`, `feedback`, `inbox` and clean-up (`runs`, `trash`, `prune`, `keep`, `archive`)
161
+ - **Service and evaluator**: `KALOKO_TOKEN` for `share`, `feedback`, `review`, `inbox` and clean-up (`runs`, `trash`, `prune`, `keep`, `archive`)
125
162
  (`npx kaloko login` approves one in the browser and saves it to `~/.config/kaloko/.env`, or create it in your
126
163
  organization's settings); `TYPESAFE_API_KEY` for the
127
- semantic evaluator (optional). Both names can be changed in the config.
164
+ semantic evaluator and `ANTHROPIC_API_KEY` for the vision evaluator (both
165
+ optional; without them Kaloko evaluates on your plan's allowance). The names
166
+ can be changed in the config.
128
167
 
129
168
  `npx kaloko doctor` checks that every variable the config names is set and that
130
169
  each environment lets you in.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kaloko",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "description": "See what your AI agents built: every screen, language and device walked, assessed and approved on one canvas.",
5
5
  "keywords": [
6
6
  "qa",
@@ -45,6 +45,32 @@
45
45
  "signals": { "type": "boolean", "default": true, "description": "Quick signals on every screen (purpose met, expected language, looks broken); never change verdicts." },
46
46
  "concurrency": { "type": "integer", "minimum": 1, "maximum": 16, "default": 6, "description": "Evaluator requests in flight at once." }
47
47
  }
48
+ },
49
+ "vision": {
50
+ "description": "Second, vision-capable evaluator (#17): sees the screenshot (a crop for scoped criteria) and answers with a probability and a one-sentence reason. Asked only for criteria with vision: true and for text answers in the uncertain band; false turns it off.",
51
+ "oneOf": [
52
+ { "const": false },
53
+ {
54
+ "type": "object",
55
+ "additionalProperties": false,
56
+ "properties": {
57
+ "provider": { "enum": ["anthropic"], "default": "anthropic" },
58
+ "model": { "type": "string", "default": "claude-opus-5-5", "description": "Model id of the provider (Anthropic Messages API with image input)." },
59
+ "api_key_env": { "type": "string", "default": "ANTHROPIC_API_KEY" },
60
+ "base_url": { "type": "string", "default": "https://api.anthropic.com" },
61
+ "when": { "enum": ["uncertain", "flagged", "always", "off"], "default": "uncertain", "description": "flagged: only criteria with vision: true; uncertain: those plus text answers in the uncertain band; always: every semantic criterion (most expensive)." },
62
+ "uncertain": { "type": "array", "items": { "type": "number", "minimum": 0, "maximum": 1 }, "minItems": 2, "maxItems": 2, "default": [0.15, 0.85], "description": "Text scores strictly between these go to the vision evaluator." },
63
+ "max_calls": { "type": "integer", "minimum": 0, "default": 40, "description": "Vision requests per evaluation (uncached); the rest stay with the text answer." },
64
+ "max_width": { "type": "integer", "minimum": 320, "maximum": 1568, "default": 1000, "description": "Images are scaled down to this width (px)." },
65
+ "tile_height": { "type": "integer", "minimum": 400, "maximum": 1568, "default": 1400, "description": "A full page is cut into tiles of this height." },
66
+ "max_tiles": { "type": "integer", "minimum": 1, "maximum": 4, "default": 2, "description": "Tiles of a full page sent at most (from the top); scoped criteria get a crop instead." },
67
+ "effort": { "enum": ["low", "medium", "high"], "default": "low" },
68
+ "reason_language": { "type": "string", "default": "en", "description": "Language of the one-sentence reasons (en, cs, …)." },
69
+ "hosted": { "type": "boolean", "default": true, "description": "Without a local key, ask through the organization's service (counts against the monthly allowance; one vision question counts as 5)." },
70
+ "concurrency": { "type": "integer", "minimum": 1, "maximum": 8, "default": 3 }
71
+ }
72
+ }
73
+ ]
48
74
  }
49
75
  }
50
76
  },
@@ -262,6 +262,11 @@
262
262
  "capture": {
263
263
  "$ref": "#/$defs/capture"
264
264
  },
265
+ "ignore": {
266
+ "type": "array",
267
+ "description": "Regions left out of pixel comparisons (clocks, ads, carousels): a selector, or a rectangle in page pixels of one viewport. kaloko stability suggests them.",
268
+ "items": { "$ref": "#/$defs/ignoreRegion" }
269
+ },
265
270
  "items": {
266
271
  "type": "object",
267
272
  "additionalProperties": false,
@@ -500,6 +505,13 @@
500
505
  "a11y_contrast",
501
506
  "a11y_main",
502
507
  "a11y_unique_ids",
508
+ "a11y_focus_order",
509
+ "a11y_focus_visible",
510
+ "a11y_keyboard_trap",
511
+ "a11y_skip_link",
512
+ "a11y_ax_names",
513
+ "a11y_landmarks",
514
+ "a11y_aria",
503
515
  "perf_lcp",
504
516
  "perf_cls",
505
517
  "perf_ttfb",
@@ -588,6 +600,10 @@
588
600
  "console"
589
601
  ],
590
602
  "description": "console: the evaluator reads the captured console errors with the step purpose (triage) instead of the page"
603
+ },
604
+ "vision": {
605
+ "type": "boolean",
606
+ "description": "Also show the evaluator the screenshot (a crop of scope when set): layout, imagery, brand. Needs a vision evaluator (evaluators.vision)."
591
607
  }
592
608
  }
593
609
  },
@@ -632,6 +648,22 @@
632
648
  }
633
649
  }
634
650
  },
651
+ "ignoreRegion": {
652
+ "type": "object",
653
+ "additionalProperties": false,
654
+ "oneOf": [
655
+ { "required": ["selector"] },
656
+ { "required": ["rect", "viewport"] }
657
+ ],
658
+ "properties": {
659
+ "selector": { "type": "string", "minLength": 1, "description": "CSS selector; every visible match is ignored." },
660
+ "rect": { "type": "array", "items": { "type": "number", "minimum": 0 }, "minItems": 4, "maxItems": 4, "description": "[x, y, width, height] in CSS pixels of the page." },
661
+ "viewport": { "type": "string", "description": "The viewport a rect belongs to." },
662
+ "viewports": { "type": "array", "items": { "type": "string" }, "description": "Only in these viewports (selector)." },
663
+ "locales": { "type": "array", "items": { "type": "string" }, "description": "Only in these locales." },
664
+ "note": { "type": "string" }
665
+ }
666
+ },
635
667
  "capture": {
636
668
  "type": "object",
637
669
  "additionalProperties": false,
@@ -0,0 +1,60 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://qawalk.com/schemas/spec.v1.json",
4
+ "title": "qawalk.spec.v1",
5
+ "description": "The step spec (#42 Dev mode): what to build for one step as it was approved. Written by the in-page engine src/lib/devspec.mjs at capture (steps/<step>/<locale>/<viewport>.spec.json, and the capture record of a design revision); the canvas Dev mode runs the same engine on the live page. Served by GET …/scenarios/<id>/steps/<step>/spec, MCP get_step_spec and kaloko spec. Elements are listed in page order; a style lists only what differs from what the element inherits (page, then the parent element).",
6
+ "type": "object",
7
+ "required": ["schema", "elements"],
8
+ "$defs": {
9
+ "value": {
10
+ "type": "object",
11
+ "description": "A computed value (colors as #rrggbb[aa], lengths in px) and the token it maps to. token: the DTCG path (several, space-separated, for a shorthand such as padding; 0 for a zero side); null when the set has tokens of that kind but none fits and none is near. nearest: the closest token when the value is not one. mode: the mode whose value it is (light, dark, …). hard: the stylesheet typed the raw value although the token exists. var: the custom property the author used when it names no token.",
12
+ "required": ["value"],
13
+ "properties": {
14
+ "value": { "type": "string" },
15
+ "token": { "type": ["string", "null"] },
16
+ "nearest": { "type": "string" },
17
+ "mode": { "type": "string" },
18
+ "hard": { "type": "boolean" },
19
+ "var": { "type": "string" }
20
+ },
21
+ "additionalProperties": false
22
+ },
23
+ "styles": {
24
+ "type": "object",
25
+ "description": "CSS property → value: color, background-color, border-color, font-family, font-size, font-weight, line-height, letter-spacing, padding, gap, row-gap, column-gap, border-width, border-radius, box-shadow, opacity, display and flex or grid properties.",
26
+ "additionalProperties": { "$ref": "#/$defs/value" }
27
+ }
28
+ },
29
+ "properties": {
30
+ "schema": { "const": "qawalk.spec.v1" },
31
+ "title": { "type": "string" },
32
+ "lang": { "type": ["string", "null"] },
33
+ "viewport": { "type": "array", "items": { "type": "number" }, "minItems": 2, "maxItems": 2 },
34
+ "size": { "type": "array", "items": { "type": "number" }, "minItems": 2, "maxItems": 2, "description": "Document width and height." },
35
+ "tokens": { "type": ["object", "null"], "description": "The token set the values were mapped with (the step's tokens.json); null without one.", "properties": { "count": { "type": "integer" }, "modes": { "type": "array", "items": { "type": "string" } } } },
36
+ "page": { "$ref": "#/$defs/styles", "description": "Typography and text color of the page (body), inherited by every element that does not say otherwise." },
37
+ "elements": {
38
+ "type": "array",
39
+ "items": {
40
+ "type": "object",
41
+ "required": ["i", "parent", "tag", "sel", "styles"],
42
+ "properties": {
43
+ "i": { "type": "integer" },
44
+ "parent": { "type": "integer", "description": "Index of the nearest listed ancestor, -1 at the top." },
45
+ "tag": { "type": "string" },
46
+ "role": { "type": ["string", "null"], "description": "ARIA role, explicit or implicit (button, link, heading, main, textbox, …)." },
47
+ "name": { "type": ["string", "null"], "description": "Accessible name or own text (at most 80 characters)." },
48
+ "sel": { "type": "string", "description": "A CSS selector of the element in the design page (ids, data-testid and classes first)." },
49
+ "box": { "type": "array", "items": { "type": "number" }, "minItems": 4, "maxItems": 4, "description": "x, y, width, height in CSS px of the page." },
50
+ "styles": { "$ref": "#/$defs/styles" },
51
+ "contrast": { "type": "object", "properties": { "ratio": { "type": "number" }, "aa": { "type": "boolean" } } },
52
+ "states": { "type": "object", "description": "hover, focus, active, disabled → the styles that change in that state (the page's rules forced on the element).", "additionalProperties": { "$ref": "#/$defs/styles" } },
53
+ "asset": { "type": "object", "properties": { "kind": { "enum": ["img", "svg"] }, "src": { "type": "string" }, "size": { "type": "array" }, "alt": { "type": ["string", "null"] } } }
54
+ }
55
+ }
56
+ },
57
+ "used": { "type": "object", "description": "Token path → number of values that use it.", "additionalProperties": { "type": "integer" } },
58
+ "off": { "type": "array", "description": "Values outside the token set, most frequent first.", "items": { "type": "object", "properties": { "prop": { "type": "string" }, "value": { "type": "string" }, "count": { "type": "integer" }, "nearest": { "type": ["string", "null"] }, "sel": { "type": "string" } } } }
59
+ }
60
+ }
@@ -11,7 +11,9 @@ description: >
11
11
  reviewer rejected on a canvas, what is waiting in the Kaloko inbox, or how
12
12
  to report a run in an issue, and when designing screens of a flow in a
13
13
  design environment (live HTML steps, drafts, versions, the design
14
- reference, checking implementation against it).
14
+ reference, checking implementation against it), and when implementing a
15
+ screen that has an approved design (read the step spec, build with its
16
+ tokens, check drift).
15
17
  ---
16
18
 
17
19
  # Kaloko
@@ -28,9 +30,14 @@ the canvas, storage and collaboration are the service.
28
30
  `kaloko capture` run `kaloko evaluate`) and `kaloko build` ran; you report the summary line,
29
31
  failing criteria with evidence, and the preview path (or shared URL).
30
32
  - When the run was shared, its URL and the summary are in the issue or PR
31
- the work belongs to, and you read `kaloko feedback` and `kaloko inbox`
32
- before continuing on that task.
33
+ the work belongs to, the person got the review-mode link with what waits
34
+ for them (`kaloko share` prints it; `kaloko review` repeats it), and you
35
+ read `kaloko feedback` and `kaloko inbox` before continuing on that task.
33
36
  - Changes to intent are written back to `ACCEPTANCE.md` (change log row).
37
+ - When you implemented a step from an approved design: you read its spec
38
+ (`kaloko spec <step>`), walked the implementation with `packs: [design]`,
39
+ and `kaloko drift` is clean or the PR names each difference left for a
40
+ person to decide.
34
41
  - On a design environment: the folder follows the bundle rules and
35
42
  `kaloko design lint` shows no error, `kaloko walk` and `kaloko sync` ran,
36
43
  `kaloko status` shows no conflict, and you read the draft's feedback; a
@@ -56,12 +63,17 @@ a step in a sync conflict (`--mine`), turning on `html_view`, a real clean-up
56
63
  (`kaloko prune --yes`), trashing someone else's run, archiving a scenario, and
57
64
  anything the environment profile blocks. Never trash an accepted run, a
58
65
  baseline, a run with review comments, or a run linked from an open PR or issue
59
- comment. Ask the person
66
+ comment. Never approve a
67
+ step or accept a run on a person's behalf; report what waits for them
68
+ (`kaloko review`, MCP `get_review_queue`) instead. Ask the person
60
69
  for secret values (passwords, tokens, gate credentials) and for sign-ins only
61
70
  they can do; never write secrets into the config, a scenario or a script.
62
71
 
63
72
  ## Where to look
64
73
 
74
+ - A new project or an organization without runs of its own (install, sign in,
75
+ the sample run, the first flow from a URL or a task, share, point the person
76
+ to the canvas): [reference/first-run.md](reference/first-run.md)
65
77
  - Writing or updating the plan and scenario: [reference/acceptance.md](reference/acceptance.md)
66
78
  - Android, iOS (Simulator), Electron and macOS apps, or screens captured by
67
79
  another tool (Maestro, Appium, XCUITest) with their UI tree:
@@ -71,12 +83,14 @@ they can do; never write secrets into the config, a scenario or a script.
71
83
  [reference/stacks.md](reference/stacks.md)
72
84
  - Choosing playwright, agent or manual per step, and driving the shared
73
85
  browser with your capabilities: [reference/execution.md](reference/execution.md)
74
- - Evaluation, JEV thresholds and reading results: [reference/evaluation.md](reference/evaluation.md)
86
+ - Evaluation, thresholds, the vision evaluator and its reasons, reading
87
+ results: [reference/evaluation.md](reference/evaluation.md)
75
88
  - Environments, access (gates, accounts, sign-in), e-mails, readonly and
76
89
  production rules, and what is yours to arrange for the project's stack:
77
90
  [reference/environments.md](reference/environments.md)
78
- - Sharing, reviewer feedback, mentions, inbox, verdicts and baselines, and
79
- cleaning up runs (trash, prune, keep, archive):
91
+ - Sharing, review mode and approvals carried over unchanged steps, reviewer
92
+ feedback, mentions, inbox, verdicts and baselines, and cleaning up runs
93
+ (trash, prune, keep, archive):
80
94
  [reference/collaboration.md](reference/collaboration.md)
81
95
  - Reading runs, feedback and the inbox over MCP instead of the CLI:
82
96
  [reference/mcp.md](reference/mcp.md)
@@ -87,6 +101,9 @@ they can do; never write secrets into the config, a scenario or a script.
87
101
  references, handoff, tokens, the design pack, canvas edits, branches, HTML
88
102
  view, presenting the prototype, exports, bringing your own design skill):
89
103
  [reference/design.md](reference/design.md)
104
+ - Implementing a screen from the approved design: read the step spec, build
105
+ with its tokens, walk, check drift, fix:
106
+ [reference/design.md#implement-from-the-approved-design](reference/design.md#implement-from-the-approved-design)
90
107
  - Writing design pages that work on the live step, from disk and in other
91
108
  tools (relative URLs, no CDNs, state in the URL, deterministic content,
92
109
  links between steps; what `kaloko design lint` checks):
@@ -40,8 +40,21 @@ for public pages and landings; task flows keep their own criteria.
40
40
 
41
41
  - `a11y` (`AC3xx`): images with alt, links and buttons with a name, labelled
42
42
  fields, heading levels not skipped, WCAG AA text contrast, a `main`
43
- landmark, unique ids. A subset of WCAG 2.2 AA checked in the page; it does
44
- not replace an audit with a screen reader.
43
+ landmark, unique ids (`AC301`–`AC307`, read from the page). After the
44
+ screenshot the walk also presses Tab through the page: `AC308` tab order
45
+ (hidden focus, big jumps back, positive `tabindex`, controls left out or
46
+ mouse-only), `AC309` visible focus with at least 3 : 1 contrast (each stop
47
+ screenshotted focused and unfocused), `AC310` no keyboard trap (a modal
48
+ dialog may keep focus), `AC311` a skip link or main content within three
49
+ stops, `AC312` names from Chrome's accessibility tree (what a screen
50
+ reader announces). `AC313` landmarks (one `main`, labelled repeats) and
51
+ `AC314` ARIA (unknown roles and attributes, references to missing ids,
52
+ `aria-hidden` over focusable content) are read from the page. The first
53
+ five focus stops are kept as screenshots and the canvas can draw the tab
54
+ order on the capture. The walk only moves focus: nothing is clicked or
55
+ typed, and the page is left unfocused at the top. Stack steps walk the
56
+ keyboard on their first five pages. Still a subset of WCAG 2.2 AA; it
57
+ does not replace an audit with a screen reader.
45
58
  - `perf` (`AC4xx`): LCP ≤ 2.5 s, CLS ≤ 0.1, TTFB ≤ 800 ms, page weight ≤ 3 MB,
46
59
  measured in this walk's browser since the page load (lab values: the
47
60
  machine and network of the walk matter; compare runs, not absolutes).
@@ -227,3 +240,22 @@ skips a session's nodes there. The canvas shows a chip with the person on
227
240
  every step, groups the step list by person and draws hand-offs between
228
241
  people as dashed arrows. Sessions run one after another, never in parallel,
229
242
  and never share cookies.
243
+
244
+ ## Ignore regions
245
+
246
+ Clocks, ads, carousels and "3 minutes ago" change on every capture and make
247
+ pixel diffs noisy. List them on the step and both the canvas diff and the
248
+ design pixel check (`AC801`) leave them out:
249
+
250
+ ```yaml
251
+ - id: home
252
+ ignore:
253
+ - { selector: "#clock" } # every visible match
254
+ - { selector: ".ad-slot", viewports: [desktop] }
255
+ - { rect: [0, 620, 1280, 240], viewport: desktop } # page pixels of one viewport
256
+ ```
257
+
258
+ Do not guess them: `kaloko walk --stability 3` notes what moves while the
259
+ page sits still, and `kaloko stability` compares the step with earlier runs
260
+ and writes suggestions (see [execution.md](execution.md)). Ignore only noise;
261
+ a region that matters to a criterion stays in.
@@ -4,7 +4,10 @@ A run is only worth something once the people who decide have seen it. The
4
4
  loop teams use:
5
5
 
6
6
  1. **Share the run** (`kaloko share`, tester token, after asking). The
7
- command prints the canvas URL.
7
+ command prints the canvas URL and one line on what waits for a person,
8
+ e.g. `12 steps unchanged, approvals carried over; 5 need review: <link>`.
9
+ Give the person that review-mode link (it ends in `#review`) with the
10
+ counts, not just the canvas.
8
11
  2. **Put the link where the work is tracked.** When the branch has a pull
9
12
  request and `gh` is signed in, `kaloko share --pr` posts one comment per
10
13
  scenario on it (summary line, canvas link, criteria that need attention
@@ -19,7 +22,10 @@ loop teams use:
19
22
  that waits for review and turns green or red with the verdict; do not
20
23
  report it as passed before a person accepted the run.
21
24
  3. **Read feedback before continuing.** `kaloko feedback` lists the run
22
- verdict, open rejections and comments, and failed manual criteria.
25
+ verdict, returned steps first (with the reviewer's note), open comments,
26
+ failed manual criteria and how many steps still wait for a person.
27
+ `kaloko review` (or MCP `get_review_queue`) says exactly what a person
28
+ still has to decide; see *Review mode* below.
23
29
  `kaloko inbox` lists what needs your attention across runs: mentions,
24
30
  returned runs, rejected steps in your runs, new runs of scenarios you
25
31
  reviewed, and expiry warnings. Both take `--json`; `kaloko inbox --read`
@@ -31,6 +37,34 @@ loop teams use:
31
37
  reply in the tracker with the new link. The reviewer who returned it is
32
38
  told about the new run automatically.
33
39
 
40
+ ## Review mode
41
+
42
+ Reviewers decide in **review mode** on the canvas (`Q`, the Review button,
43
+ or a link ending in `#review`): one step at a time, the steps that need a
44
+ person first (failed, returned, the AI was unsure or did not evaluate,
45
+ changed since the last accepted run, open comments), with the accepted run
46
+ beside it. `J`/`K` move, `A` approves, `R` returns with a note, `C`
47
+ comments; at the end they accept or return the run.
48
+
49
+ - **Approvals carry over unchanged steps.** When a new run is shared, a step
50
+ whose screenshots are byte-identical to the last accepted run, whose
51
+ criteria are the same and whose deterministic checks pass keeps the
52
+ approval a person gave it there, with its origin (who, when, which run).
53
+ Only changed or failing steps go to the queue. Anyone can revoke a carried
54
+ approval; the step then waits again. Organizations on Business can turn
55
+ this off (Settings → Approvals).
56
+ - A carried approval never accepts the run and never counts for required
57
+ approvers: the run verdict is always a person's decision.
58
+ - **Report what waits**, do not decide it: run `kaloko review` (add `--json`
59
+ for the data, `--run <id>` for another run) or MCP `get_review_queue` and
60
+ tell the person how many steps wait and give them `review_url`.
61
+ - **Never approve or accept on a person's behalf.** Decisions by tokens and
62
+ agents (MCP `decide_step`, `add_comment` with `approved`) are recorded as
63
+ yours, shown apart, and do not count as a person's unless the organization
64
+ allows it. Return a step only when you found a real problem, with a note.
65
+ - Returned steps are feedback: fix them, share a new run, and resolve the
66
+ thread with what changed (see below).
67
+
34
68
  ## Processing feedback
35
69
 
36
70
  Comments are threads in three places:
@@ -195,6 +229,15 @@ Settings → Storage (keep the newest N per scenario and environment).
195
229
  Everything above is available over the API with an organization token:
196
230
 
197
231
  - `GET /api/v1/orgs/<org>/feedback?run=<id|latest>[&scenario=<id>]`
232
+ - `GET /api/v1/orgs/<org>/runs/<id>/review-queue` (or
233
+ `GET /api/v1/orgs/<org>/review-queue?run=<id|latest>&scenario=<id>`):
234
+ `items` in review order with `reasons`, `decision` (approved, returned or
235
+ carried, with who and how), `unconfirmed` (an agent's or token's decision
236
+ that does not count), `changed`, criteria with evidence, `screenshots` and
237
+ `ref_screenshots`; `carried` with provenance; `counts` (`queue`,
238
+ `decided`, `pending`, `carried`, `clear`); `reference` (the accepted run);
239
+ `review_url`. Decisions use the comment and verdict routes;
240
+ `POST …/runs/<id>/carried/<step>/revoke` revokes a carried approval.
198
241
  - `GET|POST /api/v1/orgs/<org>/runs/<id>/comments` (a step: `node_id`;
199
242
  the whole run: `node_id: ""`), `GET|POST …/scenarios/<id>/comments`
200
243
  (the whole flow), and per comment `PATCH`, `DELETE`, `POST …/<cid>/resolve`
@@ -39,8 +39,10 @@ design/
39
39
  the bundle.
40
40
  - Links between steps are plain relative links to the page: `<a href="../payment/index.html">`. The canvas
41
41
  follows them; `data-kaloko-go="payment"` (or `data-qawalk-go`) moves to that step whatever the `href` says.
42
- - Reference token values as CSS custom properties (`var(--color-accent)`), so the inspector and the token
43
- check see where values come from.
42
+ - Reference token values as CSS custom properties named after the token path (`color.accent` →
43
+ `var(--color-accent)`), so Dev mode, the step spec and the token check see which token a value comes from.
44
+ Define interaction states in CSS (`:hover`, `:focus-visible`, `:active`, `:disabled`): Dev mode and the spec
45
+ read them from the stylesheet.
44
46
  - Write pages by the portable HTML rules ([portable-html.md](portable-html.md)): relative URLs only, bundled
45
47
  fonts, no CDNs, state in the URL instead of storage, deterministic content, viewport meta and `lang`.
46
48
  `kaloko design lint` checks the folder; `kaloko sync` runs it first and stops on errors (things that break on
@@ -94,8 +96,39 @@ Development builds from the design reference:
94
96
  - `kaloko export --live [--version n] --out design/` writes the live files into a folder.
95
97
  - MCP `get_step` (scenario, step, `ref: design`) returns the file list, a signed entry URL, the token set, the
96
98
  page structure and open comments; `list_step_changes` names the steps that changed since the last reference.
99
+ - MCP `get_step_spec` (or `kaloko spec <step>`) returns what to build, element by element, with tokens; see
100
+ [Implement from the approved design](#implement-from-the-approved-design).
97
101
  - Translate to the project's stack with the project's own skills; keep the step ids and the token names.
98
102
 
103
+ ## Implement from the approved design
104
+
105
+ Use this when you build or change a screen that has an approved design step (a design reference, or a version
106
+ the person names). The step spec says what was approved in the terms you write code in: elements in page order
107
+ with role, accessible name and selector, and their colors, typography, spacing, radius, shadow and layout, each
108
+ value with the DTCG token it comes from. People see the same data in the canvas: *Dev mode* (`D`) in the step
109
+ detail.
110
+
111
+ 1. **Read the spec** of each step you build: `kaloko spec <step>` (default `--ref design`; `--ref v4`, `draft` or a
112
+ run id), or MCP `get_step_spec`. `--json` gives `qawalk.spec.v1` (`schemas/spec.v1.json`).
113
+ 2. **Implement with the tokens.** A line such as `button "Pay" 120×44 bg #2e6bff=color.brand.primary · pad 12px
114
+ 20px=space.3 space.5` means `background: var(--color-brand-primary); padding: var(--space-3) var(--space-5)`
115
+ (the custom property is the token path with dots as dashes) or the project's own token mechanism. `not a token;
116
+ nearest x` means the design itself used a raw value: ask the designer before you copy it, and say so in the PR.
117
+ `:hover`, `:focus`, `:active` and `:disabled` lines are states to build; `(light)` names the mode of a value.
118
+ Keep the roles and names: they are how the implementation is matched with the design.
119
+ 3. **Walk it** with `packs: [design]` on the implementation steps; the capture then stores the implementation's
120
+ spec next to the screenshot.
121
+ 4. **Check drift**: `kaloko drift [step]` compares the walked run with the design reference of the linked design
122
+ branch and exits 1 while something differs. A shared run: MCP `get_step_drift` (`run`: id or `latest`).
123
+ Findings name the element, the expected token and value, and what the page has; `typed raw` means the value
124
+ is right but should come from the token; `not found` means the design's element (by role and name) is missing.
125
+ 5. **Fix and repeat** until drift is clean or what is left is a decision for a person (a missing element on
126
+ purpose, a raw value the designer accepted); report those in the PR instead of hiding them.
127
+
128
+ Specs exist for captures made with the current CLI: walk the design and sync again if `kaloko spec` says there is
129
+ none. The pixel, structure and token checks of the design pack (`AC801`–`AC803`) still run in `kaloko evaluate`;
130
+ drift is the per-element view an agent can act on.
131
+
99
132
  ## Your data is yours
100
133
 
101
134
  Everything exports in open formats, readable without Kaloko:
@@ -10,9 +10,11 @@ answer, so running it again is cheap.
10
10
  - deterministic results computed in the live page at capture time (with
11
11
  evidence: selector snippet, measured value);
12
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);
13
+ the default is JEV by TypeSafe (`TYPESAFE_API_KEY`), which reads the
14
+ reduced page state (no images) and returns only a probability per question
15
+ (`score`, 0–1). Verdicts: `pass` ≥ 0.85, `fail` ≤ 0.15, otherwise
16
+ `needs_review` (thresholds in config);
17
+ - a vision evaluator for a second look with the screenshot (below);
16
18
  - `manual` criteria stay `not_evaluated` until a reviewer decides.
17
19
 
18
20
  Where the evaluator runs: with `TYPESAFE_API_KEY` set locally, your own key; without it, the organization's
@@ -25,6 +27,47 @@ report with the reason `kaloko evaluate` gives.
25
27
  The default evaluator is text-only and most accurate in English. It is weak
26
28
  at numbers, which is why those are checked deterministically.
27
29
 
30
+ ## Vision and reasons
31
+
32
+ Every semantic verdict carries one sentence, `reason`, shown as "Why" next to
33
+ the score on the canvas, in `kaloko build`, in the walk summary and in
34
+ `get_run_summary`. With only the text evaluator the sentence says what it
35
+ read and how sure it was (JEV gives no explanation). The vision evaluator
36
+ gives a real one: it sees the screenshot, or a crop of the criterion's
37
+ `scope` (or `highlight`), and answers with a probability and what in the
38
+ image decided it. It is asked for:
39
+
40
+ - criteria with `vision: true` on the check (layout, imagery, "looks like the
41
+ brand", anything the text cannot show);
42
+ - text answers in the uncertain band (0.15–0.85 by default), which would
43
+ otherwise go to a person.
44
+
45
+ Its answer replaces the score (the text score stays as `text_score` in the
46
+ evaluation). Cost stays bounded: only those criteria, one request per
47
+ capture, images scaled to 1000 px wide and at most two tiles of a full page,
48
+ at most 40 uncached requests per evaluation, and answers cached by content
49
+ like the text ones. The provider is Anthropic's Messages API
50
+ (`ANTHROPIC_API_KEY`, model from `evaluators.vision.model`, default
51
+ `claude-opus-5-5`). Without the key it goes through the organization's
52
+ service, where one vision question counts as five of the monthly allowance;
53
+ when the text evaluator runs with your own `TYPESAFE_API_KEY`, the vision
54
+ evaluator also waits for your own key (`evaluators.vision.hosted: true`
55
+ lets it use the service anyway).
56
+ Configure or switch it off in `kaloko.config.yml`:
57
+
58
+ ```yaml
59
+ evaluators:
60
+ vision:
61
+ when: uncertain # flagged (only vision: true) | always | off
62
+ uncertain: [0.15, 0.85]
63
+ max_calls: 40
64
+ reason_language: en # cs for Czech reviewers
65
+ # vision: false # text evaluator only
66
+ ```
67
+
68
+ Report the reason with each `needs_review` or failing criterion; when the
69
+ evaluator saw the screenshot, say so.
70
+
28
71
  When a criterion comes back `needs_review`, read the reduced state the
29
72
  evaluator saw (`steps/<node>/<locale>/<viewport>.capture.json`, key `state`)
30
73
  and the screenshot. Either the page is genuinely unclear (report it), the
@@ -61,3 +104,8 @@ it was not evaluated.
61
104
 
62
105
  `needs_review` is not a failure: look at the screenshot and state your
63
106
  reading, or leave it to the reviewer.
107
+
108
+ After a share, steps that did not change since the last accepted run keep a
109
+ person's approval; only the rest waits in review mode. Report it as the
110
+ share prints it ("12 steps unchanged, approvals carried over; 5 need review:
111
+ <link>") and never call a carried or agent approval a person's acceptance.
@@ -73,3 +73,21 @@ The environment policy and gate apply to every context the CLI creates (the
73
73
  shared browser, `walk` sessions, one-off captures): blocked paths and, when
74
74
  readonly, non-GET requests outside `allowed_post_paths` fail and are listed as
75
75
  blocked requests in the capture; the gate's credentials go to its origins only.
76
+
77
+ ## Noisy regions (`--stability`, `kaloko stability`)
78
+
79
+ When pixel diffs between runs keep flagging the same clock, ad or carousel:
80
+
81
+ ```bash
82
+ kaloko walk --stability 3 # 3 screenshots per capture, a moment apart; what moved is noted
83
+ kaloko stability # this run against the 3 previous local runs of the scenario
84
+ kaloko stability --apply # adds the suggested ignore: to each step (block-style YAML only)
85
+ ```
86
+
87
+ `kaloko stability` writes `stability.json` and `stability.yml` into the run
88
+ and prints the suggestions per step: a selector when an element of the stored
89
+ page covers the region, otherwise a rectangle for one viewport. Look at the
90
+ screenshots before applying; a region that changed because the page really
91
+ changed is not noise. `--same-commit` compares only runs of the same commit,
92
+ `--runs a,b` names them, `--last N` sets how many runs are compared. Capture
93
+ the steps again after applying: the capture records the ignored regions.
@@ -0,0 +1,51 @@
1
+ # First run in a new project
2
+
3
+ Use this when the project has no `kaloko.config.yml` yet, or the organization
4
+ has no shared run of its own. The goal is one real flow on the canvas, shared,
5
+ with a person who knows where to approve it.
6
+
7
+ ## Where the organization stands
8
+
9
+ - `GET /api/v1/orgs/<org>/getting-started` (MCP tool `get_started`) answers
10
+ `stage` (`empty`, `sample`, `active`), the sample run's URL, how many real
11
+ runs exist, the next steps and a prompt to start from.
12
+ - Every new organization has a **sample run**: a tea-shop checkout in Czech
13
+ and English on desktop and mobile, with one failing step per language, one
14
+ overflow on the phone and one criterion waiting for a person. It does not
15
+ count toward the plan and expires after 30 days. `<service>/<org>/sample`
16
+ opens it; it carries a short guide for the person (open a step, approve,
17
+ return with a note, share).
18
+ - If the person has never reviewed a run, send them the sample link first:
19
+ they learn the canvas there, not on your first draft. When it is gone,
20
+ `POST /api/v1/orgs/<org>/sample` (MCP `add_sample_run`, needs an upload or
21
+ full token) adds it again. Do not delete it unless asked
22
+ (`DELETE /api/v1/orgs/<org>/sample`).
23
+
24
+ ## From zero to a first shared run
25
+
26
+ 1. `npm install --save-dev kaloko`, then
27
+ `npx kaloko init --agent claude --org <org>` (it prints the sample link
28
+ and these steps). Fill `environments` in `kaloko.config.yml` with the URL
29
+ the app runs on.
30
+ 2. `npx kaloko login`: the person approves a token in the browser. Ask them
31
+ to; never create or paste tokens yourself.
32
+ 3. `npx kaloko doctor` and fix what it marks ✕.
33
+ 4. Draft the first scenario:
34
+ - public pages: `npx kaloko draft <url> [url…]` writes a read-only
35
+ production scenario and a plan; sharpen purposes and criteria;
36
+ - a task or the main flow of the app: write `ACCEPTANCE.md` and
37
+ `qa/scenario.yml` as in [acceptance.md](acceptance.md). Pick the flow a
38
+ person would show a client (sign-up, checkout, the main form), not every
39
+ page.
40
+ 5. `npx kaloko validate qa/scenario.yml`, then
41
+ `npx kaloko start --scenario qa/scenario.yml --env local`, `kaloko walk`,
42
+ `kaloko build`. Fix scenario mechanics until every step has a capture.
43
+ 6. Ask before `kaloko share` (see *Ask first* in SKILL.md). After sharing,
44
+ give the person the canvas URL and say what to look at: the failing
45
+ criteria with their evidence and the steps that need a decision.
46
+ 7. Read `kaloko feedback` when they have looked; fix what they returned and
47
+ walk again.
48
+
49
+ Done means: the scenario validates, the run is shared, its URL and summary
50
+ line are in your reply (and in the issue or PR the work belongs to), and the
51
+ person knows whether the sample or this run is what they should open.