|
1 | | -# Architecture |
| 1 | +# droid-control architecture |
2 | 2 |
|
3 | | -## The problem |
| 3 | +`droid-control` is built around one constraint: the agent operating the tool is also the runtime. Architecture is therefore not just code organization. It is information architecture for a droid that must decide what to load, what to ignore, what to delegate, and what evidence proves the work. |
4 | 4 |
|
5 | | -Put all driver knowledge, recording lifecycle, video rendering, and verification logic in one skill and two things happen. First, the droid loads 3000 tokens of Windows KVM docs to record a tuistory demo on Linux. Second, and this is the one that actually hurts, the droid gets all the information at once and has to figure out what's relevant *right now*. It makes worse decisions, skips steps it shouldn't, and invents steps it doesn't need to. |
| 5 | + |
6 | 6 |
|
7 | | -## UX for droids |
| 7 | +Editable source: [`diagrams/architecture-routing.excalidraw`](diagrams/architecture-routing.excalidraw) |
8 | 8 |
|
9 | | -Droids aren't exempt from information architecture. They have finite context, they get distracted by irrelevant detail, and they degrade under overload. |
| 9 | +## What the architecture optimizes for |
10 | 10 |
|
11 | | -Every skill in this plugin is a surface the droid interacts with at a specific moment in a workflow: scoped to what it needs right now, actionable on first read, with an explicit handoff to the next surface. The same instincts that make a good CLI or a good API apply. Don't dump everything. Sequence the information. Make the next step obvious. |
| 11 | +The plugin is designed to keep a droid focused while it operates real software: |
12 | 12 |
|
13 | | -A command like `/demo` doesn't contain Remotion props or driver-specific logic. It parses intent, builds commitments, and tells the droid which skills to load. The droid never sees video rendering details while it's still planning what to record. |
| 13 | +- **Low context load:** load the Linux tuistory path without dragging in Windows KVM notes, macOS VM controls, browser automation, and Remotion internals. |
| 14 | +- **Evidence-first workflows:** every command starts by making commitments, then ends by verifying the artifact against those commitments. |
| 15 | +- **Parallel execution:** before/after captures and render jobs can run in worker droids without sharing session names or output paths. |
| 16 | +- **Clear ownership:** commands decide *what* must be produced; atom skills decide *how* to execute their slice. |
| 17 | +- **Platform specificity:** OS-specific mechanics live in platform subdocuments, not in global instructions. |
14 | 18 |
|
15 | | -## Waterfall routing |
| 19 | +## Commands are intent contracts |
16 | 20 |
|
17 | | -Skills chain into each other without hardcoding. The orchestrator doesn't call skills or build a pipeline. It tells the droid which skills to load based on three independent lookups. Once loaded, each skill's exit is the next skill's entry: |
| 21 | +The three user-facing commands are deliberately thin: |
18 | 22 |
|
19 | | -``` |
20 | | -/demo parses intent, commits deliverables |
21 | | - → orchestrator routes to driver + stage + artifact skills |
22 | | - → capture launches the app, records, hands off clips + metadata |
23 | | - → compose receives clips, builds Remotion props, renders video |
24 | | - → verify checks the output against the original commitments |
25 | | -``` |
| 23 | +| Command | Contract | |
| 24 | +|---|---| |
| 25 | +| `/demo` | Turn a PR or feature description into a visible proof story and a video deliverable. | |
| 26 | +| `/verify` | Test a claim as an investigator and report whether the evidence confirms or refutes it. | |
| 27 | +| `/qa-test` | Drive a terminal, browser, or Electron flow and report step-level pass/fail evidence. | |
| 28 | + |
| 29 | +A command parses arguments into **commitments**: layout, comparison mode, evidence type, video/showcase requirements, keystroke overlays, and any user-specified constraints. Those commitments are not suggestions. The `verify` stage later checks them explicitly. |
| 30 | + |
| 31 | +This is the first guardrail against agent drift. The droid does not start with "make something impressive." It starts with a checklist it must satisfy. |
| 32 | + |
| 33 | +## Orchestrator: route, do not execute |
26 | 34 |
|
27 | | -No state machine or orchestration framework. Just documents whose outputs naturally feed into the next document's inputs. The droid follows the waterfall because each skill makes the next step obvious, not because something forces it to. Complex multi-stage workflows emerge from skill composition rather than control flow. |
| 35 | +`skills/droid-control/SKILL.md` is an orchestrator, not a controller. It does not run a state machine or encode every workflow. It performs three independent routing lookups and tells the droid which atom skills to load. |
28 | 36 |
|
29 | | -## Task delegation |
| 37 | +| Route | Question | Examples | |
| 38 | +|---|---|---| |
| 39 | +| **Target** | What are we driving? | Droid CLI, other terminal TUI, web/Electron app, raw PTY bytes | |
| 40 | +| **Stage** | What does the workflow need? | capture, compose, verify | |
| 41 | +| **Artifact** | Does compose need polish tools? | showcase presets, effects, keystroke overlays | |
30 | 42 |
|
31 | | -Because each stage's inputs and outputs are explicit, mechanical work naturally decomposes into worker tasks. The parent agent retains planning and editorial control; workers execute exact commands and return file paths. |
| 43 | +The routes compose without a cross-product explosion. Adding a new target means writing one target skill and one routing row; capture, compose, and verify can work with it immediately if the handoff shape is respected. |
32 | 44 |
|
33 | | -Capture workers for both branches run in parallel. They need tctl commands and worktree paths, not PR context. The render worker gets a props JSON and clip paths. It doesn't need to know what the PR does or why the demo matters. Verification stays with the parent because it requires the original commitments and judgment about whether the evidence holds up. |
| 45 | +## Atom skills are runtime surfaces |
34 | 46 |
|
35 | | -The skill boundaries are the delegation boundaries. You don't need a separate delegation framework because the decomposition into self-contained stages already defines what can be farmed out, what needs creative judgment, and what's too trivial to be worth the overhead. |
| 47 | +Each atom skill is a self-contained surface the droid reads at a specific point in the workflow: |
36 | 48 |
|
37 | | -## Orthogonal routing |
| 49 | +| Atom type | Skills | Responsibility | |
| 50 | +|---|---|---| |
| 51 | +| Driver atoms | `tuistory`, `true-input`, `agent-browser` | How to drive a class of environment. | |
| 52 | +| Target atoms | `droid-cli`, `pty-capture` | Target-specific shortcuts, launch rules, and byte-capture patterns. | |
| 53 | +| Stage atoms | `capture`, `compose`, `verify` | Lifecycle phases with explicit inputs and outputs. | |
| 54 | +| Polish atom | `showcase` | Visual presets and cinematic layer guidance. | |
38 | 55 |
|
39 | | -The orchestrator makes three independent lookups: |
| 56 | +The important property is not just smaller files. It is temporal relevance: the droid reads the capture rules while capturing, the compose rules while composing, and the verification rules when it has something to check. |
40 | 57 |
|
41 | | -- **Target**: what are you driving? (droid-cli, other TUI, web app, byte capture) |
42 | | -- **Stage**: what does the workflow need? (capture, compose, verify) |
43 | | -- **Artifact**: does compose need polish tools? (showcase) |
| 58 | +## Waterfall by handoff, not framework |
44 | 59 |
|
45 | | -These compose without cross-product explosion. 6 targets + 3 stages + 1 artifact route = 10 skills, not 18. Adding a new target means writing one skill and adding one row to the routing table. Every existing stage and artifact skill works with it immediately. |
| 60 | +The workflow is a waterfall because each skill hands the next skill exactly what it needs: |
| 61 | + |
| 62 | +```text |
| 63 | +command commitments |
| 64 | + -> routed atom set |
| 65 | + -> capture outputs clips, screenshots, byte dumps, metadata |
| 66 | + -> compose outputs a rendered artifact and render metadata |
| 67 | + -> verify checks technical quality and original commitments |
| 68 | + -> report summarizes evidence and conclusion |
| 69 | +``` |
| 70 | + |
| 71 | +No central engine enforces this order. The documents make the next step obvious enough that the droid follows the flow naturally. This keeps the system easy to extend: new behavior is usually a new atom or a new row, not a new orchestration framework. |
46 | 72 |
|
47 | 73 | ## Hybrid handoffs |
48 | 74 |
|
49 | | -Commands hand off to the compose stage with two sections: structured fields for mechanical decisions, natural language for creative ones. |
| 75 | +The compose handoff has two halves: |
| 76 | + |
| 77 | +- **Mechanical fields:** layout, labels, clip paths, speed, fidelity, preset, output path, effects tier. |
| 78 | +- **Creative intent:** what the viewer should understand, which moments matter, and how to frame the proof. |
| 79 | + |
| 80 | +Mechanical fields prevent hallucinated parameters. Creative intent prevents paint-by-numbers output. The effects tier is the pattern in miniature: the command commits `none`, `utilitarian`, or `full`; compose chooses specific zooms, spotlights, and overlays only after it has real recordings to inspect. |
| 81 | + |
| 82 | +## Delegation boundaries |
| 83 | + |
| 84 | +The parent droid keeps judgment. Workers get exact commands. |
| 85 | + |
| 86 | +| Work | Owner | Reason | |
| 87 | +|---|---|---| |
| 88 | +| Interpret PR / claim / QA goal | Parent | Requires context and judgment. | |
| 89 | +| Write the interaction script | Parent | Defines the proof story. | |
| 90 | +| Capture baseline and candidate branches | Worker droids | Independent, mechanical, parallelizable. | |
| 91 | +| Render Remotion video | Worker droid | Mechanical once props and clips are fixed. | |
| 92 | +| Verify commitments | Parent | Requires the original contract and evidence judgment. | |
| 93 | + |
| 94 | +This boundary follows the stage handoffs. Capture workers need resolved `tctl` commands and worktree paths, not PR context. Render workers need a props JSON and clip paths, not a feature explanation. |
| 95 | + |
| 96 | +## Runtime artifact pipeline |
| 97 | + |
| 98 | + |
| 99 | + |
| 100 | +Editable source: [`diagrams/capture-compose-verify.excalidraw`](diagrams/capture-compose-verify.excalidraw) |
| 101 | + |
| 102 | +Every workflow starts by creating a run scope: |
| 103 | + |
| 104 | +```bash |
| 105 | +RUN_ID="$(date +%s)-$$" |
| 106 | +RUN_DIR="$(mktemp -d /tmp/droid-run-${RUN_ID}-XXXXXX)" |
| 107 | +``` |
| 108 | + |
| 109 | +The run scope is not cosmetic. `tctl` sessions share `/tmp/tctl-sessions/`, and many droids may be filming on the same machine. Session names must be prefixed with `RUN_ID`; recordings, props, screenshots, and rendered videos must live under `RUN_DIR`. |
| 110 | + |
| 111 | +## `tctl`: one terminal control boundary |
| 112 | + |
| 113 | +Terminal workflows use `bin/tctl` as the only launch/control boundary. It hides two very different execution paths behind the same command shape: |
| 114 | + |
| 115 | +| Backend | What `tctl` manages | Best for | |
| 116 | +|---|---|---| |
| 117 | +| `tuistory` | Virtual PTY sessions, deterministic waits/snapshots, asciinema recording at launch. | Fast TUI automation and most demo captures. | |
| 118 | +| `true-input` | Headless Wayland compositor, real terminal emulator, native key injection, PTY log/screenshot/video capture. | Real terminal rendering or keyboard-encoding proof. | |
50 | 119 |
|
51 | | -Structured: layout, speed, preset, fidelity, effects tier. These have correct answers. A side-by-side layout is either `side-by-side` or it isn't. |
| 120 | +`tctl` also enforces Droid CLI launch invariants. `droid-dev` sessions must provide `--repo-root`, which lets `tctl` set `DROID_DEV_REPO_ROOT` and record provenance for the captured branch and commit. |
52 | 121 |
|
53 | | -Natural language: what the viewer should take away, which moments to hold, how to frame the story. These are editorial judgments that benefit from the droid's understanding of the PR context. |
| 122 | +Browser and Electron workflows intentionally do **not** go through `tctl`; they use `agent-browser`, whose persistent Playwright-backed daemon is the right control boundary for DOM snapshots, screenshots, and CDP-connected apps. |
54 | 123 |
|
55 | | -Two failure modes this prevents: over-specifying creative decisions up front (the droid produces rigid, paint-by-numbers output) and under-specifying mechanical params (the droid hallucinates presets and layouts). The effects tier is a concrete example. The command commits a single word ("utilitarian" or "full"), and compose makes specific, grounded choices after capture, when it has actual recordings to look at. |
| 124 | +## Video composition |
| 125 | + |
| 126 | +The compose stage uses the Remotion project in `remotion/` as a single video engine. The droid writes a `Showcase` props JSON; `scripts/render-showcase.sh` handles the mechanical rendering pipeline: |
| 127 | + |
| 128 | +1. Normalize props and choose fidelity. |
| 129 | +2. Convert `.cast` recordings through `agg` and `ffmpeg`. |
| 130 | +3. Stage clips into Remotion `public/`. |
| 131 | +4. Auto-detect `clipDuration` with `ffprobe` when omitted. |
| 132 | +5. Render the `Showcase` composition. |
| 133 | +6. Clean staged clips and temporary conversion outputs. |
| 134 | + |
| 135 | +This keeps droids out of the common failure modes: stale files in `public/`, mismatched `clipDuration`, wrong `agg` theme, invalid pixel formats, and hand-written Remotion commands with missing encode flags. |
56 | 136 |
|
57 | 137 | ## Platform isolation |
58 | 138 |
|
59 | | -Platform-specific content lives in `platforms/` subdirs under the relevant skill. A droid on Linux loads `true-input/platforms/linux.md`. It never sees the Windows KVM or macOS QEMU docs. This is a routing decision, not a reading-comprehension test. |
| 139 | +Platform-specific mechanics live below the atom that needs them: |
| 140 | + |
| 141 | +```text |
| 142 | +skills/true-input/platforms/linux.md |
| 143 | +skills/true-input/platforms/windows.md |
| 144 | +skills/true-input/platforms/macos.md |
| 145 | +skills/pty-capture/platforms/linux.md |
| 146 | +skills/pty-capture/platforms/windows.md |
| 147 | +skills/pty-capture/platforms/macos.md |
| 148 | +``` |
| 149 | + |
| 150 | +A Linux droid reads Linux Wayland instructions. A Windows VM byte-capture task reads Windows KVM instructions. The system does not rely on the droid to skim irrelevant sections correctly. |
| 151 | + |
| 152 | +## Extending the plugin |
| 153 | + |
| 154 | +Use the same composition rules when adding capability: |
| 155 | + |
| 156 | +| Change | Preferred shape | |
| 157 | +|---|---| |
| 158 | +| New user workflow | Add a command that parses arguments into commitments, then routes through existing atoms. | |
| 159 | +| New target type | Add one target atom and one target-route row. | |
| 160 | +| New capture backend | Add a driver atom or extend `tctl` only if it belongs behind the same terminal boundary. | |
| 161 | +| New visual treatment | Add Remotion props/schema support and document compose/showcase behavior. | |
| 162 | +| New platform mechanics | Add a `platforms/<os>.md` file under the relevant atom. | |
| 163 | + |
| 164 | +If a change makes every droid read more global instructions, it is probably fighting the architecture. Prefer a new scoped surface over a larger shared surface. |
| 165 | + |
| 166 | +## Mental model |
| 167 | + |
| 168 | +`droid-control` is a small composition system for agent attention: |
| 169 | + |
| 170 | +```text |
| 171 | +intent contract + orthogonal routing + scoped atom surfaces + explicit handoffs |
| 172 | += real-app automation that stays focused, parallelizable, and verifiable |
| 173 | +``` |
0 commit comments