docs: pandoc-based site and v0.1.0 groundwork (#5)

* chore(prose): remove em-dashes from config files

* chore(prose): remove em-dashes from android sdk config

* docs(spec-api): remove em-dash from README

* fix(doctor): reword sidecar-jar error without em-dash

* test(sidecar): reword assertion message without em-dash

* docs: add CLAUDE.md with project conventions

* build: add docs target for pandoc site

* docs(site): add pandoc template and stylesheet

* docs(site): add pandoc build script

* docs(site): add landing pages

* docs(manual): add getting-started

* docs(manual): add writing-specs

* docs(manual): add runs

* docs(manual): add cli reference

* docs(dev): add design principles

* docs(dev): add architecture

* ci: deploy docs site to github pages

* docs: rewrite README as entry point to docs site
This commit is contained in:
pj authored and GitHub committed 2026-04-18 14:00:57 +07:00
1 parent a74d9fbeae
commit e62319e916
25 files changed
+920 -56

No files matched your search

+69
View File
@@ -0,0 +1,69 @@
---
title: Architecture
---
# Architecture
Three processes, two transports.
```mermaid
flowchart TB
subgraph Go["uatu (Go)"]
Bundler[Bundler<br/>esbuild] --> Verifier[Verifier<br/>goja + LTL]
Verifier <--> Runner[Runner]
Runner --> Trace[Trace writer<br/>JSONL + PNG]
Runner <--> Driver[Driver iface]
end
subgraph Sidecar["Maestro Sidecar (JVM)"]
Maestro[maestro-client]
end
subgraph Device["Emulator"]
subgraph App["Android app (debug)"]
SDK[uatu-sdk<br/>pause / hierarchy<br/>logs / coverage]
end
end
Driver -- gRPC --> Maestro
Maestro -- UIAutomator --> App
Runner -- Unix socket --> SDK
Trace --> Runs[(runs/)]
```
## Processes
**uatu (Go).** The top-level binary. Bundles the spec with esbuild, evaluates it in goja, runs the main loop, dispatches actions through the driver, writes the trace.
**Maestro sidecar (JVM).** A Kotlin process that wraps `maestro-client` and exposes a gRPC surface matching the `driver.Driver` interface. Handles UI input, screenshots, the system accessibility tree, and OS-level alerts.
**In-app SDK.** A Kotlin (or Swift for iOS) library linked into the app under test. Exposes a Unix socket to the runner. Provides pause and resume, view-hierarchy dumps, coverage reads, log capture, and user-registered state extractors.
## Transports
| Channel | Transport | Purpose |
|---|---|---|
| Go to Maestro sidecar | gRPC (localhost TCP) | UI input, screenshots, system alerts |
| Go to in-app SDK | Unix domain socket | Pause / resume, hierarchy, coverage, logs, extractors |
The split exists for one reason: only real UI events need the cost of crossing process and OS-API boundaries. Introspection is cheap, frequent, and lives on a fast local socket directly to the app.
## Per-step cycle
The heart of the system is:
```
pause ─► capture state ─► evaluate properties ─► pick action ─► resume ─► dispatch
```
1. The runner asks the driver to wait until the UI is idle.
2. The runner sends `PAUSE` to the SDK over the agent socket. The SDK freezes the main runloop at a safe point.
3. The SDK sends back a `STATE` message: view hierarchy, coverage delta, logs since last step, exception list, snapshot values.
4. The runner feeds state into goja. Extractors re-read; properties re-evaluate; the action generator returns a weighted tree.
5. The runner writes the trace entry for this step.
6. The runner picks an action by weight.
7. The runner sends `RESUME` to the SDK, then dispatches the action through the driver (gRPC to sidecar, which talks to Maestro, which talks to UIAutomator or XCTest).
8. Loop.
The cycle runs hundreds of times per minute. Every step produces one row in `trace.jsonl` and one screenshot.