Editor support
Hand-authored YAML flows get autocomplete, hover docs, and inline validation in any editor that speaks JSON Schema. There is no klera-specific editor extension — the schema is exported, the editor reads it, you type.
Export the schema
klera schema --out .klera/flow.schema.json --prettyThe schema is derived from the same Zod IR the parser uses, so anything the runtime accepts the editor knows about — and anything the editor flags is something the parser would reject at run time.
Flags:
--out <path>— where to write the schema. Without it, prints to stdout.--pretty— pretty-print the JSON (recommended for committed files; diffs stay readable).
klera init runs this automatically as part of the scaffold and points
the YAML schema directive at it.
Wire it up in your YAML
Add the # yaml-language-server comment at the top of every flow file:
# yaml-language-server: $schema=../.klera/flow.schema.json
name: Login smoke
steps:
- tap: Sign In
- type: { into: email, value: pm@example.com }
- tap: Continue
- assert: { visible: Welcome back }klera init adds the directive automatically when it scaffolds the
YAML opt-in (init --yaml). Existing flows just need the one-line
header.
The path is relative to the flow file. For nested layouts
(flows/auth/login.flow.yaml), bump the .. count to reach the
schema:
# yaml-language-server: $schema=../../.klera/flow.schema.jsonWhat you get for free
Any editor with a JSON Schema-aware YAML extension picks up the schema without extra config:
| Editor | Provider |
|---|---|
| VS Code | redhat.vscode-yaml |
| JetBrains | Built-in YAML support (IntelliJ, WebStorm, RubyMine, …) |
| Neovim | yamlls via nvim-lspconfig |
| Helix | Built-in YAML LSP |
| Sublime | LSP + LSP-yaml |
All of them deliver the same three things: completions, hover docs, inline validation.
Completions
Type - and the editor offers every step keyword. Type tap: and you
get the target-spec fields. Type target: and you get
testID / text / accessibilityLabel / role / scope.
steps:
- █ # cursor here
# ↓ completion popup
# tap
# type
# assert
# waitForIdle
# visualSnapshot
# swipe
# scroll
# …Hover docs
Hover any keyword to see its description from the Zod schema —
including value constraints (role is one of button | link | …,
durationMs is a positive integer).
Inline validation
Misspelled keys, wrong types, missing required fields, and unknown variants are flagged before you save.
steps:
- tap:
testid: login-submit
# ↑ Property "testid" is not allowed. Did you mean "testID"?
- type:
into: { testID: login-email }
# missing: value (required)The schema is strict — every Step variant uses Zod’s .strict(), so
multi-keyword steps like { tap: …, type: … } are flagged as
“Unrecognized key” instead of silently parsing as the first variant.
This is the same gate the parser applies; the editor is just surfacing
it earlier.
Schema-as-code
The schema is derived from the Zod IR via zod-to-json-schema, so it
follows the IR in lockstep:
- Add a new step variant to
@klera/protocol→ bump → re-runklera schema→ editors see it. - Tighten an existing field’s type → same flow.
There is no second source of truth and no hand-maintained schema file in the repo. Editor validation matches runtime validation.
Refreshing the schema
Bump @klera/cli (or @klera/protocol), then re-run:
klera schema --out .klera/flow.schema.json --prettyCommit the regenerated file. Reviewers see the schema diff alongside the version bump — useful context when a release adds a new step.
CI can gate on schema freshness the same way it gates on prose-cache
freshness. A klera schema --out /tmp/check.json --pretty && diff .klera/flow.schema.json /tmp/check.json step fails the build if
someone bumped klera but forgot to regenerate.
See also
- Planner transports — for prose flows the LLM produces the IR and the cache; the schema applies to the YAML escape hatch and to anything you author by hand.