Kane CLI by TestMu AI (Formerly LambdaTest). Use kane-cli for end-to-end browser and mobile testing in natural language: generate tests from a PRD or spec, run them on Chrome, Android and iOS, and gate CI with evidence packs.
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Internal reference only. Everything in this section (field names, event types, JSON structure) is for you to parse programmatically. Never expose these internal terms to the user. The user should see plain-language summaries, not
run_end,final_state,bifurcation,NDJSON,session_dir, or any raw JSON fields.
With --agent, kane-cli outputs one JSON object per line to stdout. Progress UI renders to stderr.
On run, testmd run and testrun run, every stdout line carries two extra fields, and nothing that existed before changed:
| Field | Meaning |
|---|---|
v | Contract version, 1. It only bumps on a breaking change |
ts | ISO timestamp of when the event was emitted |
The first line on every surface is an opening event:
{"type":"stream_start","cli_version":"0.8.17","surface":"run","pid":16664,"v":1,"ts":"2026-09-21T08:47:26.889Z"}surface is run, testmd, testrun or explore (references/explore.md; it ends with done). Use cli_version to tell whether a newer event or flag is available. session_dir may also be present when a session already exists.
Rules a parser must follow:
v bump.run stay typeless (below). Do not look for type: "step".run_end for run, test_md_done for testmd run, testrun_done for testrun run (then remote_done on cloud grid runs). A run refused before it starts can end on an error with no completion event: read the exit code.The same stream is also written to disk, line by line as it happens: <session_dir>/events.ndjson, byte for byte what stdout printed. While a run is live, kane-cli keeps a small pointer file at ~/.testmuai/kaneai/sessions/active/<pid>.json (pid, cwd, surface, session_dir, started, cli_version, host_agent) and removes it on exit. You normally need neither: one blocking call hands you the whole stdout. They exist for watchers such as the live strip (references/live-strip.md), and the log is where a suite keeps each test's own events (references/testrun.md). The log holds exactly what stdout held, so treat it with the same care.
Progress events (a start and completion event per step):
{"step": 1, "status": "running", "remark": "Navigate to amazon.in"}
{"step": 1, "status": "done", "remark": "Navigated to amazon.in"}
{"step": 2, "status": "done", "remark": "Typed 'laptop' in search box"}
{"step": 3, "status": "failed", "remark": "Could not find Add to Cart button"}| Field | Type | Description |
|---|---|---|
step | number | Step index. It can run one ahead of the step the person would count (a bifurcation takes the first slot), so count completed done/failed lines for "steps taken" rather than reading the last index |
status | string | "running" at start; "done" or "failed" at completion |
remark | string | What the agent did or why it failed |
child_id | string, optional | The step belongs to a child flow. Keep children apart when step indices repeat |
These are untyped — they have no type field. Do not key on event.type === 'step_start' or 'step_end'; those event types are not emitted.
Flow events:
Event (type field) | Key Fields | Purpose |
|---|---|---|
project_folder_auto_defaulted | resolved project + folder (id, name) | Run-startup gate auto-resolved a project/folder when none was configured (or the cached one was stale/invalid). Fires before any progress event on run / testmd run. Translate to plain language (see references/test-manager.md). |
bifurcation | flows[], count | Agent split objective into sub-flows |
ask_user | question, step_index, options? | Agent needs user input |
error | message | Error occurred. On testmd run / testrun run in a folder linked to a shared project it also carries a code, and remedy, next or support_id when kane-cli has one (agent-contract.md §3.7) |
warning | code, message, … | (0.8.15+) Before any progress event: code: "unresolved_variables" — a {{name}} had no value; the run continues. Schema below. |
test_md_evidence_ingest | status: "ok"|"failed", evidence_id, stage? (failure only) | testmd run only: a replay's evidence pack published to the dashboard. Informational. |
test_md_bundle_sync | status: "ok"|"failed", commit_id, bytes? (success) / stage? (failure) | testmd run / testmd sync: test bundle pushed to the cloud after an authored commit. Informational. |
coverage | status (written, none, skipped, failed), pct?, reason?, pack | run / testmd run: one per sealed pack, just before the completion event, which repeats it as coverage. skipped (nothing to measure here, as in a folder with no assurance work): say nothing. In a linked folder: agent-contract.md §3.7 |
update_available | current, latest, severity | run (also generate --agent), at any point before run_end, or not at all: a newer kane-cli exists. Mention it once, after the result |
skill_update_available | current, latest, install_cmd | run only, like update_available: a newer skill exists. After the result, offer kane-cli install skill once (references/ready-check.md §4a) |
testrun_* family | see references/testrun.md | Emitted only by kane-cli testrun run; terminal event is testrun_done, not run_end. |
Note: The run stream has no run_start event; startup metadata or errors can precede progress.
Real devices (--target android|ios) add stderr lines, not events: Connecting to a real <OS> device…, Running on: Real device · <name> · <OS> <ver> · App <APP id> (the allocated device — report it), note: adaptive heal is off on real devices… on a replay, and warning: <reason> — the run continues, but the device and OS version are not checked… when the device list can't be read. A hub refusal ends the run with failed to open the mobile hub session: <reason> — a plan/concurrency problem, never retry it (see references/mobile.md §Real devices).
warning with code: "unresolved_variables" (0.8.15+)Emitted by run, testmd run and (after testrun_plan) testrun run when an authored step references a {{name}} that has no value. The run goes ahead: the name is typed as written unless a step sets it first. The warning does not change the exit code. A run given a Test Manager dataset row can emit a second warning with the same code for ${x} names that are no column of that row, still before any progress.
{"type":"warning","code":"unresolved_variables","message":"2 variable(s) have no value — typed as written unless a step sets them first",
"suggested_file":".testmuai/variables/variables.json",
"variables":[
{"name":"checkout_url","reason":"not_declared","used_by":[{"file":"objective","step":1}]},
{"name":"login_password","reason":"value_missing","file":".testmuai/variables/assurance.json","used_by":[{"file":"login_test.md","step":2}]}
]}| Field | Meaning |
|---|---|
variables[].reason | value_missing — the key exists in variables[].file with an empty value · not_declared — the key is in no variable file · not_a_dataset_column — a ${x} that is no column of the Test Manager dataset the run was given (variables[].dataset names it) |
variables[].file | the pool file that holds the empty key (value_missing only); --variables when it came inline |
variables[].used_by[] | {file, step} — file is objective for kane-cli run, else the test file (flattened step index) |
suggested_file | where to add a not_declared key; use it as given: .testmuai/variables/assurance.json in a folder with its own assurance store (.context/), .testmuai/variables/variables.json otherwise (a linked folder too: shared-projects.md §5) |
Report it with the run's outcome. If a later step failed on a literal placeholder, point at this.
runSince progress events lack a type field, distinguish them from typed events like this:
for each line of NDJSON:
if obj.type === "run_end" → terminal event, stop parsing
if obj.type === "bifurcation" → flow split
if obj.type exists → other typed event
if obj.step exists → progress event (step/status/remark)For one-shot run, build automation on run_end and process exit; other commands use the completion events listed below. Use progress events for live status display only.
One-shot run completion event (early refusals may exit without it):
{
"type": "run_end",
"status": "passed",
"summary": "Searched for laptop and added first result to cart",
"one_liner": "Searched for laptop on Amazon and added to cart",
"reason": "Objective completed",
"duration": 45.2,
"credits_consumed": 11.9,
"final_state": {
"price": "$29.99",
"product_name": "Wireless Headphones"
},
"context": {
"memory": {},
"variables": {},
"pointer": "(passed) Searched for laptop and added first result to cart"
},
"session_dir": "~/.testmuai/kaneai/sessions/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"run_dir": "~/.testmuai/kaneai/sessions/a1b2c3d4-e5f6-7890-abcd-ef1234567890/runs/0",
"test_url": "https://test-manager.lambdatest.com/projects/123/test-cases/456"
}Key run_end fields:
status — "passed" or "failed"summary — what the agent didone_liner — short summary for displayreason — why it stoppedcredits_consumed: credits the run used, a decimal number (when reported). Round it for display. Older releases and docs called this creditsfinal_state — extracted values from "store as" objectivestest_url — link to KaneAI dashboard (if upload succeeded)session_dir — session directory (session log + the sealed evidence pack under evidence/)run_dir — legacy: this directory is no longer created; run logs and screenshots live inside the evidence pack (references/debug.md has the layout)result_code (string, optional) — machine result classification. Under --bug-detection, a confirmed product bug arrives as result_code: "740" plus a verdict object (confirmed, family, category, severity, one_liner, confidence). Report it to the user as a product bug found, distinct from a test failure.The evidence hint is not an event. After a run, kane-cli prints evidence: view locally with `kane-cli evidence serve <path>` on stderr. Never look for it on stdout; see references/evidence.md for how to act on it. run_end itself carries no evidence-pack field.
ask_user (if stdin is a TTY){"type": "user_response", "answer": "Medium size"}To cancel a run:
{"type": "cancel"}The run_end parsing strategy applies to one-shot run only. For testmd run, collect test_md_done.overall_status, duration_s, session_id, and optional share_url; embedded run_end events can finish individual steps. Local suites emit testrun_done; dispatched remote suites then emit remote_done (retain status, exit, sessions_path). Assurance conversational agent streams end in done; review/read verbs have their own contracts. Always check process exit too: early refusal, invalid plan or dry-run can exit without the normal completion event.
Progress is for live display: count only done/failed completions, retaining child and execution context when step indices repeat.
.tessl-plugin
references
scripts