# YamlCommandReader in Maestro: Purpose, Methods, and Usage Examples

> Discover YamlCommandReader in Maestro for loading parsing and validating YAML flow definitions. This guide explains its purpose methods and usage examples.

- Repository: [Maestro/Maestro](https://github.com/mobile-dev-inc/Maestro)
- Tags: internals
- Published: 2026-03-20

---

**YamlCommandReader is the central entry point in the Maestro framework for loading, parsing, and validating YAML flow definitions, converting them into executable MaestroCommand objects while abstracting file I/O and error translation.**

The `YamlCommandReader` class serves as the primary façade for Maestro's YAML-based scripting engine. In the mobile-dev-inc/Maestro repository, this component bridges raw flow files written by developers and the internal orchestration system that executes mobile UI tests, handling everything from simple file reads to complex error reporting with line numbers.

## Core Responsibilities of YamlCommandReader

Located at [`maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt), this utility class delegates heavy parsing logic to `MaestroFlowParser` while managing the complete lifecycle of YAML flow processing:

- **Flow File Ingestion**: The `readCommands(flowPath)` method loads entire flow definitions from `.yaml` or `.yml` files, returning a `List<MaestroCommand>` ([source](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt#L38-L41))
- **Single Command Parsing**: `readSingleCommand(flowPath, appId, command)` handles inline command strings for API interactions like the Studio REPL ([source](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt#L43-L46))
- **Configuration Extraction**: `readConfig(flowPath)` isolates the `MaestroConfig` block without processing the full command list, useful for metadata inspection ([source](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt#L47-L50))
- **Workspace Configuration**: `readWorkspaceConfig(configPath)` parses the optional [`maestro.yaml`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro.yaml) workspace file or returns an empty `WorkspaceConfig` if absent ([source](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt#L52-L56))
- **File Watching**: `getWatchFiles(flowPath)` identifies dependent files—such as referenced `initFlow` scripts or media assets—that should trigger flow re-execution during hot-reloading ([source](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt#L58-L61))
- **Configuration Retrieval**: `getConfig(commands)` walks parsed command lists to extract the embedded `applyConfiguration` command ([source](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt#L63-L70))
- **Syntax Validation**: `checkSyntax(maestroCode)` performs dry parses to validate YAML structure without writing files to disk ([source](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt#L74-L76))

## Error Handling and Validation Strategy

YamlCommandReader implements sophisticated error translation through `mapParsingErrors` and `errorMessage` helper methods. Rather than exposing low-level exceptions like `FlowParseException` or `JsonProcessingException` directly, it catches these at the parsing boundary and transforms them into user-friendly `SyntaxError` instances with precise line numbers and contextual hints ([source](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-orchestra/src/main/java/maestro/orchestra/yaml/YamlCommandReader.kt#L78-L103)).

This abstraction ensures that CLI users, Studio interface consumers, and programmatic API callers receive consistent, actionable error messages when flow definitions contain syntax errors or schema violations.

## Practical Code Examples

### Loading an Entire Flow from Disk

The CLI's `TestRunner` uses this pattern to initialize test execution:

```kotlin
import maestro.orchestra.yaml.YamlCommandReader
import java.nio.file.Paths

val flowPath = Paths.get("samples/login_flow.yaml")
val commands = YamlCommandReader.readCommands(flowPath)   // Returns List<MaestroCommand>

```

*Reference:* See `TestRunner.runSingle` for production usage ([TestRunner.kt](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-cli/src/main/java/maestro/cli/runner/TestRunner.kt#L66-L68)).

### Parsing Inline Commands for REPL Interfaces

Studio server components utilize this method for real-time command testing:

```kotlin
val flowPath = Paths.get("")          // Dummy path for error reporting context
val appId    = "com.example.app"
val yamlCmd  = "- tapOn: \"Login\""

val command = YamlCommandReader.readSingleCommand(flowPath, appId, yamlCmd)

```

### Extracting Flow Configuration Metadata

```kotlin
val config = YamlCommandReader.readConfig(Paths.get("myflow.yaml"))
println(config?.name)   // Access flow name or other metadata

```

### Identifying Files for Hot-Reload Watching

```kotlin
val watchFiles = YamlCommandReader.getWatchFiles(Paths.get("myflow.yaml"))
watchFiles.forEach { println("Watching: $it") }

```

### Validating YAML Syntax Without File I/O

```kotlin
try {
    YamlCommandReader.checkSyntax("""
        - launchApp:
            packageName: "com.example"
    """.trimIndent())
    println("Syntax validation passed")
} catch (e: SyntaxError) {
    println("Invalid YAML: ${e.message}")
}

```

## Integration Points in the Maestro Codebase

YamlCommandReader operates as the linchpin between YAML DSL files and Maestro's execution engine, with critical dependencies across the project:

| Component | File Path | Usage Pattern |
|-----------|-----------|---------------|
| **CLI Test Runner** | [`maestro-cli/src/main/java/maestro/cli/runner/TestRunner.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-cli/src/main/java/maestro/cli/runner/TestRunner.kt) | Invokes `readCommands()` to load flows before execution ([source](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-cli/src/main/java/maestro/cli/runner/TestRunner.kt#L66-L70)) |
| **Studio Server** | [`maestro-studio/server/src/main/java/maestro/studio/DeviceService.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-studio/server/src/main/java/maestro/studio/DeviceService.kt) | Parses commands received from web UI via `readSingleCommand()` ([source](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-studio/server/src/main/java/maestro/studio/DeviceService.kt#L29-L32)) |
| **Parser Delegation** | [`maestro-orchestra/src/main/java/maestro/orchestra/yaml/MaestroFlowParser.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-orchestra/src/main/java/maestro/orchestra/yaml/MaestroFlowParser.kt) | Heavy-weight parser that YamlCommandReader delegates to for YAML-to-object conversion |
| **Exception Types** | [`maestro-orchestra/src/main/java/maestro/orchestra/yaml/FlowParseException.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro-orchestra/src/main/java/maestro/orchestra/yaml/FlowParseException.kt) | Internal exceptions that YamlCommandReader translates to public `SyntaxError` |

## Summary

- **YamlCommandReader** acts as the public façade for all YAML flow processing in Maestro, located in the `maestro-orchestra` module.
- It provides **nine primary operations** ranging from full flow loading to single command parsing and workspace configuration reading.
- **Error translation** converts low-level parsing exceptions into actionable `SyntaxError` instances with line number context.
- The class delegates actual YAML parsing to `MaestroFlowParser` while managing file I/O, path resolution, and validation workflows.
- Key consumers include the **CLI TestRunner** for batch execution and **Studio Server** for interactive command processing.

## Frequently Asked Questions

### What is the difference between YamlCommandReader and MaestroFlowParser?

**YamlCommandReader** serves as the high-level public API that handles file operations, path resolution, and error translation, while **MaestroFlowParser** performs the heavy-weight YAML syntax parsing and schema validation. The reader delegates to the parser but shields callers from implementation details like Jackson JSON processing exceptions and file system abstractions.

### How does YamlCommandReader handle invalid YAML syntax?

When `checkSyntax()` or read methods encounter malformed YAML, the internal `mapParsingErrors` function catches `FlowParseException` or `JsonProcessingException` instances and converts them into `SyntaxError` objects. These errors include specific line numbers and contextual messages generated by the `errorMessage` and `fallbackErrorMessage` helpers, providing clear feedback about missing colons, indentation errors, or invalid command keys.

### Can YamlCommandReader parse workspace configuration files?

Yes, the `readWorkspaceConfig(configPath)` method specifically handles the optional [`maestro.yaml`](https://github.com/mobile-dev-inc/Maestro/blob/main/maestro.yaml) workspace configuration files. If the file exists, it parses the workspace settings; if absent, it returns an empty `WorkspaceConfig` object, allowing the rest of the system to proceed with default configuration values.

### Where is YamlCommandReader used in the Maestro CLI?

The CLI's `TestRunner` class utilizes `YamlCommandReader.readCommands()` at the entry point of test execution (around line 66-68 in [`TestRunner.kt`](https://github.com/mobile-dev-inc/Maestro/blob/main/TestRunner.kt)) to transform YAML flow files into executable command lists. Additionally, Studio server components use `readSingleCommand()` to parse individual commands sent from the web interface during interactive debugging sessions.