YamlCommandReader in Maestro: The Execution Pipeline's YAML Parser
The YamlCommandReader is the entry point that transforms declarative YAML test flows into executable MaestroCommand objects and extracts configuration metadata for the Maestro execution engine.
The YamlCommandReader serves as the critical bridge between static YAML flow definitions and Maestro's dynamic execution engine. Located in the mobile-dev-inc/Maestro repository, this component parses .yaml files into concrete command lists that the Orchestra engine can execute on mobile devices. Without this parser, the declarative test descriptions would remain inert text files rather than actionable device commands.
Core Responsibilities in the Execution Pipeline
Converting YAML Files to Command Lists
At the heart of the pipeline is the readCommands method in YamlCommandReader.kt. This method accepts a Path to a YAML flow file and returns a List<MaestroCommand> that represents the sequence of actions to perform.
According to the source code in maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt (lines 38–41), the method enables the transformation from declarative YAML to imperative command objects:
val commands = YamlCommandReader.readCommands(flowPath)
This list is what the Orchestra engine iterates over during test execution.
Extracting Flow Configuration
The reader handles two distinct configuration extraction scenarios. First, readConfig(Path) parses only the optional config block—containing properties like name, appId, and environment variables—without processing the entire command list (lines 47–50).
Second, after parsing the full command list, Orchestra.runFlow retrieves the configuration via YamlCommandReader.getConfig(commands) to initialize the JavaScript engine and AI components (as seen in Orchestra.kt, lines 65–68).
val config = YamlCommandReader.readConfig(flowPath) // Config-only parsing
val config = YamlCommandReader.getConfig(commands) // From parsed commands
Enabling Hot Reload with File Watching
For development workflows, the getWatchFiles method (lines 58–61) returns every file referenced by a flow, including the main flow file itself, initFlow dependencies, and media assets. This allows Maestro's file-watchers to trigger re-runs when any dependency changes.
val watchFiles = YamlCommandReader.getWatchFiles(flowPath)
Syntax Validation and Debugging Utilities
The reader provides checkSyntax (lines 74–76) to validate YAML snippets without executing them, surfacing parsing errors early in the development cycle. For debugging, formatCommands generates a nicely formatted string representation of the command list.
// Throws SyntaxError with visual cues if invalid
YamlCommandReader.checkSyntax(yamlSnippet)
Converting Exceptions to User-Friendly Errors
All parsing logic is wrapped in mapParsingErrors (lines 78–88), which transforms low-level FlowParseException instances into user-friendly SyntaxError objects. The errorMessage helper (lines 90–103) generates visual cues indicating the offending line in the YAML source.
Integration with the Orchestra Execution Engine
The YamlCommandReader does not operate in isolation—it feeds directly into the Orchestra class, the core execution engine. As implemented in maestro-orchestra/src/main/java/maestro/orchestra/Orchestra.kt, the runFlow method accepts the pre-parsed command list and configuration retrieved from the reader.
The CLI entry point in maestro-cli/src/main/java/maestro/cli/runner/TestRunner.kt demonstrates this pipeline: it loads the YAML flow using YamlCommandReader.readCommands, then hands the resulting list to Orchestra for execution on the connected device.
Practical Code Examples
Loading and Executing a Complete Flow
This example demonstrates the full path from file to execution:
import maestro.orchestra.yaml.YamlCommandReader
import maestro.orchestra.Orchestra
import maestro.Driver
import java.nio.file.Paths
// Resolve the YAML flow file
val flowPath = Paths.get("flows/login_test.yaml")
// Parse into executable commands (YamlCommandReader.kt:38-41)
val commands = YamlCommandReader.readCommands(flowPath)
// Extract configuration for environment setup
val config = YamlCommandReader.getConfig(commands)
// Execute via Orchestra (Orchestra.kt:65-68)
val orchestra = Orchestra(maestro = Driver())
val success = orchestra.runFlow(commands)
Validating YAML Syntax Without Execution
Use checkSyntax to catch errors before running tests:
import maestro.orchestra.yaml.YamlCommandReader
val snippet = """
- tapOn:
text: "Submit"
- assertVisible: "Success"
""".trimIndent()
// Validates and throws SyntaxError with line indicators if malformed
YamlCommandReader.checkSyntax(snippet)
Collecting Dependencies for File Watching
Identify all files that should trigger re-runs during development:
import maestro.orchestra.yaml.YamlCommandReader
import java.nio.file.Paths
val flowPath = Paths.get("flows/checkout.yaml")
val dependencies = YamlCommandReader.getWatchFiles(flowPath)
// Returns list including the flow and referenced sub-flows/media
println(dependencies.joinToString("\n"))
Key Source Files in the Architecture
maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt: Core parser implementingreadCommands,readConfig,getWatchFiles,checkSyntax, and error mapping logic.maestro-orchestra/src/main/java/maestro/orchestra/Orchestra.kt: Execution engine that consumes the command list and configuration provided by the reader.maestro-cli/src/main/java/maestro/cli/runner/TestRunner.kt: CLI integration point that orchestrates the YAML loading and execution phases.maestro-test/src/test/kotlin/maestro/orchestra/yaml/YamlCommandReaderTest.kt: Unit tests validating parsing accuracy, configuration extraction, and error handling.
Summary
- The YamlCommandReader transforms static YAML files into executable
MaestroCommandlists viareadCommands. - It extracts configuration metadata through both
readConfig(standalone) andgetConfig(from parsed commands) to initialize execution contexts. - File watching capabilities rely on
getWatchFilesto detect changes in flows and their dependencies. - Developer tooling benefits from
checkSyntaxfor early validation andmapParsingErrorsfor clear, actionable error messages. - It serves as the entry point for the execution pipeline, bridging declarative test definitions and the imperative
Orchestraengine.
Frequently Asked Questions
What does YamlCommandReader return when parsing a flow?
The readCommands method returns a List<MaestroCommand> representing the sequence of actions defined in the YAML. The readConfig method returns configuration metadata such as the flow name, target app ID, and environment variables without processing the command list.
How does YamlCommandReader handle malformed YAML?
All parsing operations wrap exceptions in mapParsingErrors (lines 78–88), which converts technical FlowParseException errors into user-friendly SyntaxError instances. These include the offending file path, line number, and a visual pointer to the exact error location in the source.
Where is YamlCommandReader invoked in the Maestro CLI?
The CLI runner in maestro-cli/src/main/java/maestro/cli/runner/TestRunner.kt invokes YamlCommandReader.readCommands to load flow files before passing them to the Orchestra execution engine. This occurs during both single-flow executions and continuous testing modes.
Can YamlCommandReader validate YAML without running the test?
Yes. The checkSyntax method (lines 74–76) accepts a YAML string and validates it against Maestro's command schema without executing any device actions. This is useful for CI/CD pipelines and IDE integrations that need to verify flow validity before deployment.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →