diff --git a/docs/assets/screenshots/PROVENANCE.txt b/docs/assets/screenshots/PROVENANCE.txt
index 11c63fb..029eb86 100644
--- a/docs/assets/screenshots/PROVENANCE.txt
+++ b/docs/assets/screenshots/PROVENANCE.txt
@@ -43,6 +43,30 @@ program-workbench-cli.png
concepts/program-visualizer.md. SHA-256:
aa5ff1e1455b0444f234f398e3f645490b974c3b48c5e38156fd041964fec4d2.
+composed-parent-graph.png
+ HTML output of `openadapt flow visualize` on a two-child compose directory
+ (`composition.json`, schema `openadapt.composition/v1`). The fixture is the
+ synthetic intake/posting composition from the visualize emission in
+ OpenAdaptAI/openadapt-flow at commit
+ 3d085d219c31e30577d42a9b55004fc15bb48605 (process-contract visualize
+ branch, which includes compose-parent rendering). Headless Google Chrome
+ capture of the self-contained page, light color scheme. Used on
+ concepts/program-visualizer.md and guides/compose-multi-application.md.
+ SHA-256:
+ 83c58002551372df0a9eae936b92408c18d691775230e087b5736a304919691d.
+
+process-parent-graph.png
+ HTML output of `openadapt flow visualize` on a process-contract directory
+ (`process-contract.json`, schema `openadapt.process-contract/v0`). The
+ fixture is a representative synthetic process parent with admitted children
+ intake and posting. Admission ids and digests are fixtures, not a live
+ tenant. Captured from the same Flow commit as composed-parent-graph.png.
+ Headless Google Chrome, light color scheme, cropped to the cards and
+ handoff list. Used on concepts/program-visualizer.md,
+ concepts/process-contract.md, and guides/compose-multi-application.md.
+ SHA-256:
+ 7507af9db132d424f93735c746151f1063fdb704ea8128e6e8446b65806746e7.
+
program-workbench-desktop.png
The development-only OpenAdapt Desktop preview that renders the production
qualification workbench with a public synthetic graph. It has no bound live
diff --git a/docs/assets/screenshots/composed-parent-graph.png b/docs/assets/screenshots/composed-parent-graph.png
new file mode 100644
index 0000000..fa2d214
Binary files /dev/null and b/docs/assets/screenshots/composed-parent-graph.png differ
diff --git a/docs/assets/screenshots/process-parent-graph.png b/docs/assets/screenshots/process-parent-graph.png
new file mode 100644
index 0000000..ed2659e
Binary files /dev/null and b/docs/assets/screenshots/process-parent-graph.png differ
diff --git a/docs/assets/visual-palette.json b/docs/assets/visual-palette.json
index 137817d..1ae42b1 100644
--- a/docs/assets/visual-palette.json
+++ b/docs/assets/visual-palette.json
@@ -283,6 +283,50 @@
}
]
},
+ "screenshots/composed-parent-graph.png": {
+ "source_repository": "OpenAdaptAI/openadapt-flow",
+ "source_path": null,
+ "note": "Self-contained `openadapt flow visualize` HTML for a two-child compose parent. Generated output rather than product chrome. Ground is the page white plus the dark program-map canvas.",
+ "sha256": "83c58002551372df0a9eae936b92408c18d691775230e087b5736a304919691d",
+ "width": 2464,
+ "height": 1604,
+ "dominant_colors": [
+ {
+ "hex": "#ffffff",
+ "share_percent": 25.14
+ },
+ {
+ "hex": "#0b1220",
+ "share_percent": 20.39
+ },
+ {
+ "hex": "#111a29",
+ "share_percent": 11.25
+ }
+ ]
+ },
+ "screenshots/process-parent-graph.png": {
+ "source_repository": "OpenAdaptAI/openadapt-flow",
+ "source_path": null,
+ "note": "Self-contained `openadapt flow visualize` HTML for a process-contract parent. Generated output rather than product chrome. Ground is plain white.",
+ "sha256": "7507af9db132d424f93735c746151f1063fdb704ea8128e6e8446b65806746e7",
+ "width": 1336,
+ "height": 553,
+ "dominant_colors": [
+ {
+ "hex": "#ffffff",
+ "share_percent": 58.52
+ },
+ {
+ "hex": "#e8f0fe",
+ "share_percent": 13.46
+ },
+ {
+ "hex": "#f3f4f6",
+ "share_percent": 9.03
+ }
+ ]
+ },
"screenshots/program-workbench-desktop.png": {
"source_repository": "OpenAdaptAI/openadapt-desktop",
"source_path": null,
diff --git a/docs/concepts/index.md b/docs/concepts/index.md
index c94af03..3095793 100644
--- a/docs/concepts/index.md
+++ b/docs/concepts/index.md
@@ -69,6 +69,10 @@ jump to what you need.
`lint` reports gaps, `certify` refuses an unsafe bundle before it deploys.
+- [__Read a compiled program__](program-visualizer.md)
+
+ The program map, live evidence, a composed parent, and a process parent.
+
- [__Process contracts__](process-contract.md)
A parent receipt over independently admitted capabilities. Handoffs copy
diff --git a/docs/concepts/process-contract.md b/docs/concepts/process-contract.md
index b79e706..e629df0 100644
--- a/docs/concepts/process-contract.md
+++ b/docs/concepts/process-contract.md
@@ -39,8 +39,34 @@ is refused, because those children aren't admitted. Each child runs through
A compiled bundle still has its own ProgramGraph. `visualize` on a process
parent shows admitted children, handoff edges, and a terminal labeled End of
-declared steps. Open the child bundle for its steps. See
-[Read a compiled program](program-visualizer.md).
+declared steps. Open the child bundle for its steps.
+
+```bash
+openadapt flow visualize process-parent -o process.html
+openadapt flow visualize process-parent --format mermaid
+```
+
+```mermaid
+flowchart TD
+ intake["intake adm 11111111 digest aaaaaaaa web"]
+ posting["posting adm 77777777 digest bbbbbbbb linux"]
+ end_declared_steps["End of declared steps"]
+ intake --> posting
+ posting --> end_declared_steps
+ intake -.->|patient_id| posting
+ classDef admitted fill:#e8f0fe,stroke:#3b6ea5,color:#111;
+ classDef terminal fill:#f3f4f6,stroke:#6b7280,color:#111;
+ class intake,posting admitted;
+ class end_declared_steps terminal;
+```
+
+
+ { width="900" }
+ A process parent of two admitted capabilities. Representative synthetic process contract. The admission_id and digest values are fixtures, not a live tenant.
+
+
+See [Read a compiled program](program-visualizer.md) and
+[Sequence work across two applications](../guides/compose-multi-application.md).
RFC-0001 is the name of this contract. Qualify each child first:
[Qualify a workflow](../guides/qualify-a-workflow.md).
diff --git a/docs/concepts/program-visualizer.md b/docs/concepts/program-visualizer.md
index 5ede4c5..83b2f81 100644
--- a/docs/concepts/program-visualizer.md
+++ b/docs/concepts/program-visualizer.md
@@ -60,6 +60,31 @@ It does not prove `VERIFIED`. The run outcome still depends on the exact
authorization, identity, postcondition, and effect evidence required by the
execution profile.
+`--format mermaid` writes the same map as a flowchart you can paste into a
+review note. This one is the public-safe projection of a bounded loop:
+
+```mermaid
+flowchart TD
+ n0{"Repeat the bounded steps"}
+ n1("Enter an approved input")
+ n2("Enter an approved input")
+ n3("Send an approved key effect ยท irreversible")
+ n4{{"End of declared steps"}}
+ n0 -->|declared loop| n1
+ n1 --> n2
+ n2 --> n3
+ n3 --> n0
+ n0 --> n4
+ classDef irreversible stroke:#b4530a,stroke-width:2px;
+ classDef halt stroke:#b21f2d,stroke-width:2px;
+ class n3 irreversible;
+ class n3 halt;
+```
+
+`n0` owns the loop. The edge from `n3` back to `n0` is the next item. The edge
+from `n0` to `n4` is the exit. Open the HTML export to inspect each node's
+resolution, identity, screen, and effect lanes.
+
## Parents of children stay parents
`visualize` on a compiled bundle emits that bundle's ProgramGraph: steps,
@@ -74,6 +99,49 @@ window title or a URL. Sequence edges follow `--after`, or `--child` order.
`openadapt.process-contract/v0`) draws each independently admitted child
(name, `admission_id`) and the same kind of handoff edge.
+This is the HTML `visualize` writes for a two-child compose directory. Each
+child is one node. The handoff is the effect-bound parameter `patient_id`.
+Intake's own steps stay inside `intake-bundle`.
+
+
+ { width="1180" }
+ A compose parent. Two child bundles, one handoff, one terminal. Representative synthetic composition from the visualize emission for composition.json.
+
+
+```mermaid
+flowchart TD
+ n0(["intake web"])
+ n1(["posting linux"])
+ n2{{"End of declared steps"}}
+ n0 --> n1
+ n1 --> n2
+ n0 -->|patient_id| n1
+ classDef irreversible stroke:#b4530a,stroke-width:2px;
+ classDef halt stroke:#b21f2d,stroke-width:2px;
+```
+
+A process parent uses the same two children after each one is admitted. Each
+node carries a short `admission_id` and digest. Handoff edges are dashed.
+
+
+ { width="900" }
+ A process parent of two admitted capabilities. Representative synthetic process contract. The admission_id and digest values are fixtures, not a live tenant.
+
+
+```mermaid
+flowchart TD
+ intake["intake adm 11111111 digest aaaaaaaa web"]
+ posting["posting adm 77777777 digest bbbbbbbb linux"]
+ end_declared_steps["End of declared steps"]
+ intake --> posting
+ posting --> end_declared_steps
+ intake -.->|patient_id| posting
+ classDef admitted fill:#e8f0fe,stroke:#3b6ea5,color:#111;
+ classDef terminal fill:#f3f4f6,stroke:#6b7280,color:#111;
+ class intake,posting admitted;
+ class end_declared_steps terminal;
+```
+
Both parents end at a terminal titled End of declared steps, not Success.
Traversal ended. The parent is `VERIFIED` only when every child's receipt says
so.
@@ -168,6 +236,10 @@ openadapt flow visualize bundle --profile remote-safe -o review.html
openadapt flow visualize bundle --profile public-synthetic -o public.html
openadapt flow visualize bundle --format mermaid
openadapt flow visualize bundle --format json
+openadapt flow visualize composed -o composed.html
+openadapt flow visualize composed --format mermaid
+openadapt flow visualize process-parent -o process.html
+openadapt flow visualize process-parent --format mermaid
```
diff --git a/docs/get-started/first-workflow.md b/docs/get-started/first-workflow.md
index b42a217..5d2dc96 100644
--- a/docs/get-started/first-workflow.md
+++ b/docs/get-started/first-workflow.md
@@ -132,6 +132,16 @@ OpenAdapt classifies write-shaped clicks such as save, submit, create, and
delete as irreversible. Treat that classification as a stop signal. Review the
bundle before any replay.
+Open the compiled program before you lint it:
+
+```bash
+openadapt flow visualize bundle -o graph.html
+```
+
+The page lists every step, the evidence it needs, and where the run can stop.
+A task that spans two applications is a parent of two child nodes. See
+[Read a compiled program](../concepts/program-visualizer.md).
+
## 3. Lint and review
```bash
@@ -203,6 +213,7 @@ its policy. Use the governed `run` path only after those checks pass.
## What is next
+- See the compiled program: [Read a compiled program](../concepts/program-visualizer.md)
- Build the full qualification project: [Qualify a workflow](../guides/qualify-a-workflow.md)
- Enforce a workload policy: [Write and enforce a policy](../guides/policy-and-certification.md)
- Audit the evidence from a run: [Read and audit run reports](../guides/run-reports.md)
diff --git a/docs/get-started/index.md b/docs/get-started/index.md
index 1c2f7b2..0c4cc43 100644
--- a/docs/get-started/index.md
+++ b/docs/get-started/index.md
@@ -79,6 +79,10 @@ openadapt flow visualize openadapt-quickstart/bundle --out graph.html
openadapt flow lint openadapt-quickstart/bundle
```
+Open `graph.html` in a browser. That page is the compiled program: the steps
+it can take, the evidence each one needs, and the paths that stop the run.
+See [Read a compiled program](../concepts/program-visualizer.md).
+
When you move from the tutorial to your own work, qualification tests the
workflow against real failures in its environment before it runs.
@@ -87,6 +91,7 @@ After the first run, choose the path that matches your goal:
| Goal | Next guide |
|---|---|
| Record one real, read-only browser workflow | [Your first workflow](first-workflow.md) |
+| See what the compiled program looks like | [Read a compiled program](../concepts/program-visualizer.md) |
| Use the Desktop application | [Install Desktop](../desktop/install.md) |
| Use native desktop, RDP, or Citrix | [Install a different execution surface](#install-a-different-execution-surface) |
| Prepare a qualified production run | [Move from demo to deployment](#move-from-demo-to-deployment) |
@@ -181,7 +186,21 @@ openadapt flow compose \
--out composed
```
-See [Sequence work across two applications](../guides/compose-multi-application.md).
+`visualize composed` draws those two children and the `patient_id` handoff.
+Each child stays its own compiled program:
+
+```mermaid
+flowchart TD
+ n0(["intake web"])
+ n1(["posting linux"])
+ n2{{"End of declared steps"}}
+ n0 --> n1
+ n1 --> n2
+ n0 -->|patient_id| n1
+```
+
+See [Sequence work across two applications](../guides/compose-multi-application.md)
+and [Read a compiled program](../concepts/program-visualizer.md).
[Durable runs](../concepts/durable-runtime.md) explains how an operator can
resume from the last verified checkpoint after a halt.
@@ -196,6 +215,10 @@ resume from the last verified checkpoint after a halt.
The bundle, the run report, and what each artifact is for.
+- [__Read a compiled program__](../concepts/program-visualizer.md)
+
+ The program map, a composed parent, and a process parent.
+
- [__Qualification evidence__](what-works-today.md)
Accepted substrate results, exact environments, and deployment boundaries.
diff --git a/docs/get-started/what-you-get.md b/docs/get-started/what-you-get.md
index 12d950e..2b2e240 100644
--- a/docs/get-started/what-you-get.md
+++ b/docs/get-started/what-you-get.md
@@ -11,8 +11,16 @@ per-step evidence the replayer needs to re-find each target, and the policy
metadata `lint` and `certify` read.
You can audit the bundle before it runs: which steps write, which clicks are
-identity armed, and which postconditions each step asserts. See
-[The bundle format](../reference/bundle-format.md) for the full layout.
+identity armed, and which postconditions each step asserts.
+
+```bash
+openadapt flow visualize bundle -o graph.html
+```
+
+That page is the program map. A compose directory and a process-contract
+directory take the same command. Each child stays one node. See
+[Read a compiled program](../concepts/program-visualizer.md) and
+[The bundle format](../reference/bundle-format.md).
## The run report
diff --git a/docs/guides/compose-multi-application.md b/docs/guides/compose-multi-application.md
index 7632550..5e8e102 100644
--- a/docs/guides/compose-multi-application.md
+++ b/docs/guides/compose-multi-application.md
@@ -67,11 +67,31 @@ intake's program graph.
```bash
openadapt flow visualize composed -o composed.html
+openadapt flow visualize composed --format mermaid
openadapt flow visualize intake-bundle -o intake.html
```
+
+ { width="1180" }
+ The parent graph for the compose directory above. Two children, one patient_id handoff, terminal End of declared steps. Representative synthetic composition.
+
+
+```mermaid
+flowchart TD
+ n0(["intake web"])
+ n1(["posting linux"])
+ n2{{"End of declared steps"}}
+ n0 --> n1
+ n1 --> n2
+ n0 -->|patient_id| n1
+ classDef irreversible stroke:#b4530a,stroke-width:2px;
+ classDef halt stroke:#b21f2d,stroke-width:2px;
+```
+
Flags and the `certify` / `run` path are in the
-[CLI reference](../reference/cli.md#compose).
+[CLI reference](../reference/cli.md#compose). See
+[Read a compiled program](../concepts/program-visualizer.md) for the child
+program map.
## Qualify and admit each child
@@ -119,5 +139,24 @@ and End of declared steps. That label means the declared sequence ended. It
doesn't mean `VERIFIED`. Parent `VERIFIED` requires every child `VERIFIED`
and zero model calls.
+```mermaid
+flowchart TD
+ intake["intake adm 11111111 digest aaaaaaaa web"]
+ posting["posting adm 77777777 digest bbbbbbbb linux"]
+ end_declared_steps["End of declared steps"]
+ intake --> posting
+ posting --> end_declared_steps
+ intake -.->|patient_id| posting
+ classDef admitted fill:#e8f0fe,stroke:#3b6ea5,color:#111;
+ classDef terminal fill:#f3f4f6,stroke:#6b7280,color:#111;
+ class intake,posting admitted;
+ class end_declared_steps terminal;
+```
+
+
+ { width="900" }
+ The process parent for the same two children after admission. Representative synthetic process contract. The admission_id and digest values are fixtures.
+
+
Open the child bundle when you need its steps. The parent view won't inline
them.
diff --git a/docs/guides/index.md b/docs/guides/index.md
index 0e45e2b..ecf9e58 100644
--- a/docs/guides/index.md
+++ b/docs/guides/index.md
@@ -22,7 +22,8 @@ How-to guides for real deployments. Each assumes you have
- [__Sequence work across two applications__](compose-multi-application.md)
Record one program per surface, sequence the compiled recordings with
- `compose`, then after admission author a ProcessContract parent.
+ `compose`, then after admission author a ProcessContract parent. The
+ parent graph shows two child nodes and the handoff.
- [__Write and enforce a policy__](policy-and-certification.md)