← AutonomCONTENT HISTORY

Update to Autonom

Snapshot Oct 24, 2026 · 13:54 UTC · version 0.30.0

Collection source: downloaded plugin package.

WHAT CHANGED

First saved snapshot

No earlier snapshot is available to establish a change.

Save Autonom and check future changes in Following.

Up to 10 plugins free · no card required.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "description": "Author, validate, and run repeatable Flow v1 files for AI agents — strict YAML flows with exact selectors, polling assertions, single-fire mutations, failure classes, and per-run event evidence via the Autonom CLI.",
  "included_files": [
    {
      "relative_path": "agents/openai.yaml",
      "size_in_bytes": 409
    }
  ],
  "name": "mobile-flow",
  "skill_md_contents": "---\nname: mobile-flow\ndescription: Author, validate, and run repeatable Flow v1 files for AI agents — strict YAML flows with exact selectors, polling assertions, single-fire mutations, failure classes, and per-run event evidence via the Autonom CLI.\n---\n\n# Mobile Flow (Android + iOS Simulator)\n\n## Purpose\n\nTurn a working journey into a **repeatable, reviewable flow file** — and run\nit with exact semantics. A flow is strict YAML in the app repository\n(conventionally `.autonom/flows/`, shared steps in `.autonom/subflows/`);\nruntime artifacts land under `~/.autonom/sessions/<id>/flows/<run_id>/`.\n\nThe language refuses what it cannot execute exactly: unknown commands,\nfuzzy-by-default matching, YAML cleverness (anchors, block scalars, tabs),\nand implicit retries of mutating actions. Every rejection carries\n`file:line:column` and a stable `error_code`. Full reference: `docs/FLOW.md`.\n\n## CLI\n\n```bash\n# Validate (whole runFlow graph, no device needed)\npython3 <autonom-root>/scripts/autonom.py flow check .autonom/flows\npython3 <autonom-root>/scripts/autonom.py flow check login.yaml\n\n# Canonical form — expands shorthand, materializes `match: exact`\npython3 <autonom-root>/scripts/autonom.py flow fmt login.yaml --write\npython3 <autonom-root>/scripts/autonom.py flow fmt .autonom/flows --check   # exit 1 = needs formatting\npython3 <autonom-root>/scripts/autonom.py flow fmt login.yaml --write --drop-comments   # only when losing comments is intended\n\n# Enumerate: file, id, name, tags, platforms\npython3 <autonom-root>/scripts/autonom.py flow list\n\n# Run (needs an active session — see mobile-session)\npython3 <autonom-root>/scripts/autonom.py flow run login.yaml\npython3 <autonom-root>/scripts/autonom.py flow run .autonom/flows --include-tag smoke --exclude-tag flaky\npython3 <autonom-root>/scripts/autonom.py flow run login.yaml --secret TEST_PASSWORD --env LOCALE=en_US\npython3 <autonom-root>/scripts/autonom.py flow run login.yaml --events     # NDJSON stream on stdout\npython3 <autonom-root>/scripts/autonom.py flow run login.yaml --dry-run    # pre-flight only; top-level status \"planned\", `planned` list with runtime indexes\n\n# Approve for promotion: N consecutive clean replays of the current bytes\npython3 <autonom-root>/scripts/autonom.py teach approve login.yaml --run --minimum-runs 3 --secret TEST_PASSWORD --env LOCALE=en_US\n```\n\n`flow check` catches what used to fail only on the device: negative\n`timeoutMs`/`delayMs`/`durationMs`/`maxSwipes`/`chars`, a latitude or\nlongitude out of range, an empty selector string, and a `match: regex`\npattern that does not compile (`timeoutMs: 0` is legal: one check). An\nunknown command, argument, selector field, or match mode names its closest\nlegal spelling (`Did you mean 'tapOn'?`). `flow fmt --write` refuses with\n`comments_would_be_lost` rather than silently dropping YAML comments; in a\ndirectory nothing is written until every file is safe.\n\n## A minimal flow\n\n```yaml\nschema: autonom.dev/flow/v1\nappId: com.example.app\nname: Login\ntags: [smoke, auth]\n---\n- launchApp\n- tapOn: Sign in\n- inputText:\n    value: ${TEST_EMAIL}\n    sensitive: true\n- assertVisible:\n    selector:\n      id: home_screen\n    timeoutMs: 7000\n```\n\n`flow fmt` expands `- tapOn: Sign in` into the explicit selector form with\n`match: exact`. Selectors: `id`, `text`, `description`, `role`, plus\n`enabled`/`checked`/`selected` and `index`. **iOS puts the visible label in\n`description`, not `text`** — cross-platform flows prefer `id`, then\n`description`.\n\n## Reading a run\n\n- Exit `0`: passed. Exit `1`: a **test failure** — the app did not do what\n  the flow asserts; the stdout summary carries `status: \"failed\"` and\n  `failure.failure_class: \"test_failure\"`. Exit `2`: the flow or the\n  machine is wrong (definition/infrastructure) — stderr envelope as usual.\n- Assertions poll (default 10 s, per-step `timeoutMs`); mutating steps fire\n  **exactly once** — a duplicate selector match refuses instead of tapping.\n- Selectors match **on-screen** nodes only, and duplicates and `index` are\n  counted among them: iOS lists Flutter's scroll cache at a 0x0 frame, and a\n  flow never asserts, taps, or counts such a node (`scrollUntilVisible` keeps\n  scrolling until it is really on screen). Whitespace in a label is\n  normalised, so one selector matches the label iOS joins with a newline and\n  Android with a space. Before a tap on a sheet that is still animating in,\n  add `waitForSettled` — it waits for a still tree and never fails the flow.\n- A directory suite runs on one target and skips a flow that cannot run there\n  (declared for the other platform, or an Android-only step on iOS) with a\n  `flow_skipped_for_platform` warning; `flow list` shows each flow's\n  inferred `platforms` up front.\n- Per-step events: `~/.autonom/sessions/<id>/flows/<run_id>/events.ndjson`;\n  a failing step leaves a screenshot and a hierarchy dump automatically.\n- `onFlowComplete` cleanup always runs; its failures are reported separately\n  (`hook_failures`) and never mask the primary outcome.\n- A test failure also carries `repair`: the `--until-step` command that\n  reconstructs the state the failed step assumed, `ui tree`, the old selector\n  as a widened `ui find … --mode contains --all`, and the re-verification\n  commands, with advice keyed by the error code. It names the step that\n  ended the run (never a recovered retry or a cleanup hook), the file that\n  holds it (`flow`; `root_flow` is what gets replayed), and `--secret NAME` /\n  `--env NAME=<value>` placeholders — never values. When the failing step's\n  hierarchy was captured, `candidates` ranks up to five on-screen nodes by\n  similarity to the failed selector, each with a ready Flow `selector` and\n  the `ui find` command that confirms it. Run them in order, confirm a\n  candidate, edit the YAML, and re-run — the brief never rewrites the flow\n  for you.\n- A run that aborted on a definition or infrastructure error is a JUnit\n  `<error>` (`errors=\"1\"`), never a green suite.\n\n## Rules\n\n1. Never put credentials in a flow file. Pass `--secret NAME`; reference it\n   as `${NAME}`. Values never enter the file, events, journal, or summary.\n   An `--env` value that reaches a `sensitive: true` slot is treated as a\n   secret too (redacted, reproduced as `--secret NAME`, and flagged with a\n   `flow_env_value_sensitive` warning) — switch it to `--secret`.\n2. Prefer `id`, then unique visible text (`description` on iOS). Use\n   `index` only for a justified duplicate, never to paper over a bad\n   selector.\n3. Do not fight a `test_failure` by retrying the flow — read the failure\n   evidence first; the app state, not the harness, is what changed.\n   `launchApp` starts the app fresh (cleared task; `resume: true` to\n   continue where it was), and `inputText` polls for a focused field before\n   typing (`timeoutMs`), so the two first-step failures seen on real devices\n   — a resumed subscreen and typing before the field existed — no longer\n   need hand-written waits.\n4. Keep subflows atomic (login, dismiss-permissions) and let `runFlow`\n   compose them; recursion and paths escaping the workspace are refused.\n5. Approvals are bound to content. `teach approve` counts only replays whose\n   recorded `flow_sha256` (and every `runFlow` child's `subflow_sha256`)\n   matches the current bytes; the receipt stores both, and `app-skill\n   promote` refuses a flow edited since. Edit, then replay again — an\n   mtime-preserving copy does not count.\n6. Flow files are source — commit them. If the repository blanket-ignores\n   `.autonom/`, un-ignore the flows subtree (`!.autonom/flows/**`).\n\n## Failure codes\n\n| error_code | Meaning |\n| --- | --- |\n| `flow_parse_error` | YAML-subset violation; `file`/`line`/`column`/`reason` extras |\n| `flow_unknown_command` / `flow_command_invalid` | not a v1 command / bad arguments |\n| `flow_selector_invalid` | unknown or deferred selector field, bad match mode |\n| `flow_file_not_found` / `flow_path_escapes_workspace` / `flow_cycle_detected` | runFlow graph problems |\n| `flow_assertion_timeout` | test failure: the asserted state never held |\n| `flow_no_focused_field` | test failure: `inputText` found nothing with keyboard focus to type into (`requireFocus: false` opts out) |\n| `flow_var_undefined` / `flow_secret_undefined` | `${VAR}` unresolved / `--secret` not in the environment |\n| `flow_no_flows_found` | no flow files (or none match the tag filters) |\n| `flow_source_changed` | `teach approve` / `app-skill promote`: the flow or a `runFlow` child changed since its replays or receipt |\n| `comments_would_be_lost` | `flow fmt --write` would drop comments; pass `--drop-comments` to accept that |\n| `no_active_session` | run `session start` first (see mobile-session) |\n\n## Related\n\n- `mobile-session` — owning the device session a flow runs in.\n- `mobile-screen` — exploring the UI to find stable selectors first.\n- `mobile-memory` — prose runbooks; convert a stable runbook into a flow.\n- `docs/FLOW.md` — the machine-checked language reference.\n"
}

SHA-256 of public snapshot: 9d2d9ad29a629ee926a73c487a64b0df266f9fd5adf665d60554bda273a5211b