mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-07 03:00:29 +00:00
Fill in core docs: How Arc Works, Models, Workflows, Nodes & Stages, Transitions
- How Arc Works: end-to-end architecture with diagram, execution loop, retries, sandboxes, observability, and resume - Models: multi-provider rationale, full catalog table, stylesheets, overrides via CLI and TOML, ensemble SVG - Workflows: anatomy SVG, key node types, branching/loops SVG, parallel SVG, model stylesheets, goal gates - Nodes & Stages: all node types with attributes, fidelity/thread_id tables, join/error/retry policy tables - Transitions: edge selection priority, condition expression language, agent transitions, human gates, weight tiebreaking - Remove workflows/ingestion page Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6970a7c0f6
commit
dd797cca1a
12 changed files with 1249 additions and 9 deletions
|
|
@ -3,3 +3,89 @@ title: "How Arc Works"
|
|||
description: "Understand the Arc architecture and execution model"
|
||||
---
|
||||
|
||||
Arc is a workflow engine that reads a graph definition, executes nodes one at a time (or in parallel), and uses edge selection rules to decide what happens next. Here's the end-to-end flow.
|
||||
|
||||
<Frame>
|
||||
<img src="/images/how-arc-works.svg" alt="How Arc works: author-time inputs flow into the workflow engine, which dispatches to handlers that interact with LLMs, sandboxes, and humans" />
|
||||
</Frame>
|
||||
|
||||
## Author time
|
||||
|
||||
You provide three inputs:
|
||||
|
||||
1. **Workflow graph** (`.dot`) — A Graphviz DOT file defining nodes, edges, and their attributes. This is the core of what Arc executes. See [Workflows](/core-concepts/workflows).
|
||||
2. **Run config** (`.toml`, optional) — Overrides for the default model, sandbox provider, setup commands, and variables. See [Run Configuration](/execution/run-configuration).
|
||||
3. **API keys** (`.env`) — Provider credentials for LLM APIs. See [Quick Start](/getting-started/quick-start).
|
||||
|
||||
## Parse and validate
|
||||
|
||||
When you run `arc run start`, Arc:
|
||||
|
||||
1. Parses the DOT file into an in-memory graph of nodes and edges
|
||||
2. Validates the graph structure (exactly one start node, one exit node, all edges point to valid nodes)
|
||||
3. Applies the [model stylesheet](/workflows/stylesheets) to resolve which LLM model each node uses
|
||||
4. Merges run config defaults with CLI flags (CLI flags override the config, config overrides graph defaults)
|
||||
|
||||
## The execution loop
|
||||
|
||||
The engine walks the graph starting from the start node. For each node it:
|
||||
|
||||
1. **Resolves context** — Assembles the node's input from prior stage outputs, run context, and the workflow goal. The [fidelity](/workflows/stages-and-nodes#agent) setting controls how much prior context is included.
|
||||
2. **Dispatches to a handler** — Each [node type](/workflows/stages-and-nodes) has a handler: the agent handler runs an LLM tool loop, the command handler runs a shell script, the human handler waits for input, and so on.
|
||||
3. **Collects the outcome** — The handler returns a status (`success`, `fail`, `partial_success`), optional routing directives, and any context updates.
|
||||
4. **Selects the next edge** — Arc evaluates outgoing edges using conditions, labels, and weights to pick the next node. See [Transitions](/workflows/transitions).
|
||||
5. **Checkpoints** — After each stage, Arc writes a checkpoint so the run can be resumed if interrupted.
|
||||
|
||||
This loop repeats until execution reaches the exit node or an unrecoverable error occurs.
|
||||
|
||||
## Retries and error handling
|
||||
|
||||
When a node fails, Arc consults its [retry policy](/workflows/stages-and-nodes#common-node-attributes). If retries remain, the node re-executes with exponential backoff. If all retries are exhausted, the failure propagates to edge selection — a `condition="outcome=fail"` edge can route to a fix node, creating a recovery loop.
|
||||
|
||||
For workflows with loops, Arc tracks failure signatures to detect infinite retry cycles. If the same failure repeats beyond the configured limit, the workflow aborts rather than looping forever.
|
||||
|
||||
## Goal gates
|
||||
|
||||
Before completing, Arc checks all nodes marked with `goal_gate=true`. If any goal gate node didn't succeed, the workflow fails — even though execution reached the exit node. This ensures critical quality checks can't be skipped by routing around them.
|
||||
|
||||
## Parallel execution
|
||||
|
||||
When the engine hits a [parallel fan-out node](/workflows/stages-and-nodes#parallel-fan-out), it spawns concurrent branches, each with an isolated copy of the context. A [merge node](/workflows/stages-and-nodes#merge-fan-in) collects the results according to the join policy before the workflow continues on a single path.
|
||||
|
||||
## Sandboxes
|
||||
|
||||
Node handlers execute tools (bash commands, file edits) inside a **sandbox**. Arc supports three sandbox modes:
|
||||
|
||||
| Sandbox | Description |
|
||||
|---|---|
|
||||
| `local` | Tools run directly on the host machine (default) |
|
||||
| `docker` | Tools run inside a Docker container |
|
||||
| `daytona` | Tools run in a cloud sandbox with SSH access |
|
||||
|
||||
The sandbox is configured per-run via CLI flags (`--sandbox docker`) or the run config TOML.
|
||||
|
||||
## Events and observability
|
||||
|
||||
Every significant action — stage starts, LLM calls, tool invocations, edge selections, stage completions — is emitted as a structured event. These events power:
|
||||
|
||||
- The **web UI** for real-time run monitoring
|
||||
- **Retrospectives** generated automatically after each run
|
||||
- **DuckDB queries** via `arc insights` for SQL-based analysis across runs
|
||||
|
||||
See [Insights](/execution/insights) for more on querying run data.
|
||||
|
||||
## Resuming runs
|
||||
|
||||
Because Arc checkpoints after every stage, interrupted runs can be resumed from where they left off:
|
||||
|
||||
```bash
|
||||
arc run start --resume path/to/checkpoint.json
|
||||
```
|
||||
|
||||
Or resume from a git run branch:
|
||||
|
||||
```bash
|
||||
arc run start --run-branch arc/runs/abc123
|
||||
```
|
||||
|
||||
The engine restores the full context, node visit counts, and retry state, then continues execution from the next node.
|
||||
|
|
|
|||
|
|
@ -3,3 +3,120 @@ title: "Models"
|
|||
description: "How Arc routes tasks to LLM models and providers"
|
||||
---
|
||||
|
||||
No single model is best at everything. Arc lets you assign the right model to each workflow step — cheap, fast models for boilerplate, frontier models for hard reasoning, and a different provider for cross-critique so the reviewer brings fresh eyes. When a provider goes down, Arc can fail over automatically.
|
||||
|
||||
<Frame>
|
||||
<img src="/images/ensemble-workflow.svg" alt="Ensemble workflow: fan out to Opus and Gemini Pro, merge, then synthesize" />
|
||||
</Frame>
|
||||
|
||||
## Model catalog
|
||||
|
||||
| Model | Provider | Aliases | Context | Cost (in/out per Mtok) | Speed |
|
||||
|---|---|---|---|---|---|
|
||||
| `claude-opus-4-6` | anthropic | `opus`, `claude-opus` | 1M | $15.00 / $75.00 | 25 tok/s |
|
||||
| `claude-sonnet-4-5` | anthropic | `sonnet`, `claude-sonnet` | 200K | $3.00 / $15.00 | 50 tok/s |
|
||||
| `claude-haiku-4-5` | anthropic | `haiku`, `claude-haiku` | 200K | $0.80 / $4.00 | 100 tok/s |
|
||||
| `gpt-5.2` | openai | `gpt5` | 1M | $1.80 / $14.00 | 65 tok/s |
|
||||
| `gpt-5-mini` | openai | `gpt5-mini` | 1M | $0.20 / $2.00 | 70 tok/s |
|
||||
| `gpt-5.2-codex` | openai | | 1M | $1.80 / $14.00 | 100 tok/s |
|
||||
| `gpt-5.3-codex` | openai | `codex` | 1M | $1.80 / $14.00 | 100 tok/s |
|
||||
| `gemini-3.1-pro-preview` | gemini | `gemini-pro` | 1M | $2.00 / $12.00 | 85 tok/s |
|
||||
| `gemini-3-flash-preview` | gemini | `gemini-flash` | 1M | $0.50 / $3.00 | 150 tok/s |
|
||||
| `gemini-3.1-flash-lite-preview` | gemini | `gemini-flash-lite` | 1M | $0.20 / $1.50 | 200 tok/s |
|
||||
| `kimi-k2.5` | kimi | `kimi` | 262K | $0.60 / $3.00 | 50 tok/s |
|
||||
| `glm-4.7` | zai | `glm`, `glm4` | 203K | $0.60 / $2.20 | 100 tok/s |
|
||||
| `minimax-m2.5` | minimax | `minimax` | 197K | $0.30 / $1.20 | 45 tok/s |
|
||||
| `mercury-2` | inception | `mercury` | 131K | $0.20 / $0.80 | 1000 tok/s |
|
||||
|
||||
Each provider requires its own API key set via environment variable (e.g. `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`). See the [Quick Start](/getting-started/quick-start) for setup.
|
||||
|
||||
## Using models in workflows
|
||||
|
||||
Assign models to workflow nodes using [model stylesheets](/workflows/stylesheets), which use a CSS-like syntax:
|
||||
|
||||
```dot
|
||||
digraph Example {
|
||||
graph [
|
||||
model_stylesheet="
|
||||
* { llm_model: claude-haiku-4-5; }
|
||||
.coding { llm_model: claude-sonnet-4-5; reasoning_effort: high; }
|
||||
#review { llm_model: gemini-3.1-pro-preview; }
|
||||
"
|
||||
]
|
||||
|
||||
spec [label="Write Spec"]
|
||||
implement [label="Implement", class="coding"]
|
||||
review [label="Review"]
|
||||
}
|
||||
```
|
||||
|
||||
This routes the spec node to Haiku (the default), implementation to Sonnet, and review to Gemini Pro.
|
||||
|
||||
## Overriding the default model
|
||||
|
||||
Model stylesheets set per-node models inside the workflow graph, but you can also override the default model for an entire run. This is useful for quick experimentation or when you want to swap models without editing the DOT file.
|
||||
|
||||
### CLI flags
|
||||
|
||||
Pass `--model` and optionally `--provider` to `arc run start`:
|
||||
|
||||
```bash
|
||||
arc run start demo/01-hello.dot --model claude-opus-4-6
|
||||
arc run start demo/04-pipeline.dot --model gemini-3.1-pro-preview --provider gemini
|
||||
```
|
||||
|
||||
These flags set the default model for all nodes that don't have an explicit model assigned via a stylesheet.
|
||||
|
||||
### Run config TOML
|
||||
|
||||
For repeatable runs, set the model in a run config file:
|
||||
|
||||
```toml
|
||||
version = 1
|
||||
goal = "Implement the feature"
|
||||
graph = "implement.dot"
|
||||
|
||||
[llm]
|
||||
model = "claude-sonnet-4-5"
|
||||
provider = "anthropic"
|
||||
|
||||
[llm.fallbacks]
|
||||
anthropic = ["gemini", "openai"]
|
||||
gemini = ["anthropic", "openai"]
|
||||
```
|
||||
|
||||
Then launch with:
|
||||
|
||||
```bash
|
||||
arc run start run.toml
|
||||
```
|
||||
|
||||
The `[llm.fallbacks]` table is optional. It maps each provider to an ordered list of fallback providers to try when the primary is unavailable.
|
||||
|
||||
<Note>
|
||||
The precedence order is: node-level stylesheet > run config TOML > CLI flags > server defaults. More specific settings always win.
|
||||
</Note>
|
||||
|
||||
## CLI commands
|
||||
|
||||
### List models
|
||||
|
||||
View all available models, or filter by provider:
|
||||
|
||||
```bash
|
||||
arc models list
|
||||
arc models list --provider anthropic
|
||||
arc models list --query codex
|
||||
```
|
||||
|
||||
### Test models
|
||||
|
||||
Verify that your API keys are working by sending a test prompt to each configured provider:
|
||||
|
||||
```bash
|
||||
arc models test
|
||||
arc models test --model claude-sonnet-4-5
|
||||
arc models test --provider openai
|
||||
```
|
||||
|
||||
This is useful for confirming connectivity after setup or when adding a new provider key.
|
||||
|
|
|
|||
|
|
@ -3,3 +3,134 @@ title: "Workflows"
|
|||
description: "Core workflow concepts in Arc"
|
||||
---
|
||||
|
||||
A workflow is a directed graph that defines a repeatable process for AI agents, shell commands, and human decisions. Unlike a DAG (directed acyclic graph), an Arc workflow can and often does include loops — for example, implement-test-fix cycles that repeat until tests pass. You write workflows in [Graphviz DOT](/reference/dot-language), check them into version control, and run them with `arc run start`.
|
||||
|
||||
## Anatomy of a workflow
|
||||
|
||||
Every workflow is a `digraph` with a `goal`, a `start` node, an `exit` node, and one or more processing nodes connected by edges:
|
||||
|
||||
<Frame>
|
||||
<img src="/images/anatomy-workflow.svg" alt="Simple workflow: Start → Scan Files → Analyze → Exit" />
|
||||
</Frame>
|
||||
|
||||
```dot
|
||||
digraph MyWorkflow {
|
||||
graph [goal="Describe the project"]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
scan [label="Scan Files", shape=parallelogram, script="find . -maxdepth 2 -type f | head -30"]
|
||||
analyze [label="Analyze", prompt="Review the file listing. Summarize the project structure.", shape=tab]
|
||||
|
||||
start -> scan -> analyze -> exit
|
||||
}
|
||||
```
|
||||
|
||||
The `goal` attribute describes what the workflow accomplishes. Arc uses it to guide agent behavior and generate retrospectives.
|
||||
|
||||
## Key node types
|
||||
|
||||
Each node's Graphviz **shape** determines how it executes. The three most important types are:
|
||||
|
||||
**Agents** (default `box` shape) run an LLM with access to tools — bash, file editing, sub-agents — looping autonomously until the task is complete:
|
||||
|
||||
```dot
|
||||
implement [label="Implement", prompt="Read plan.md and implement every step."]
|
||||
```
|
||||
|
||||
**Commands** (`parallelogram`) run shell scripts and capture output for downstream nodes:
|
||||
|
||||
```dot
|
||||
validate [label="Run Tests", shape=parallelogram, script="cargo test 2>&1 || true"]
|
||||
```
|
||||
|
||||
**Human gates** (`hexagon`) pause the workflow and wait for a person to choose a path. Edge labels define the options:
|
||||
|
||||
```dot
|
||||
approve [shape=hexagon, label="Approve Plan"]
|
||||
|
||||
approve -> implement [label="[A] Approve"]
|
||||
approve -> plan [label="[R] Revise"]
|
||||
```
|
||||
|
||||
Arc supports additional node types for one-shot prompts, conditional branching, parallel fan-out/fan-in, and more. See [Stages and Nodes](/workflows/stages-and-nodes) for the full reference.
|
||||
|
||||
## Branching and loops
|
||||
|
||||
<Frame>
|
||||
<img src="/images/branch-loop-workflow.svg" alt="Branching and loop workflow" />
|
||||
</Frame>
|
||||
|
||||
Edges can have **conditions** that route execution based on outcomes:
|
||||
|
||||
```dot
|
||||
gate [shape=diamond, label="Tests passing?"]
|
||||
|
||||
gate -> exit [label="Pass", condition="outcome=success"]
|
||||
gate -> implement [label="Fix"]
|
||||
```
|
||||
|
||||
Loops are natural — just point an edge back to an earlier node. Use `max_visits` on a node to prevent infinite loops:
|
||||
|
||||
```dot
|
||||
fix [label="Fix Failures", prompt="Fix the failing tests.", max_visits=3]
|
||||
```
|
||||
|
||||
## Parallel execution
|
||||
|
||||
<Frame>
|
||||
<img src="/images/parallel-workflow.svg" alt="Parallel fan-out and merge workflow" />
|
||||
</Frame>
|
||||
|
||||
Fan out to run branches concurrently, then merge the results:
|
||||
|
||||
```dot
|
||||
fork [label="Fan Out", shape=component]
|
||||
merge [label="Merge", shape=tripleoctagon]
|
||||
|
||||
fork -> security
|
||||
fork -> architecture
|
||||
fork -> quality
|
||||
security -> merge
|
||||
architecture -> merge
|
||||
quality -> merge
|
||||
merge -> report -> exit
|
||||
```
|
||||
|
||||
## Model stylesheets
|
||||
|
||||
Assign models to nodes using CSS-like selectors with increasing specificity:
|
||||
|
||||
```
|
||||
* { llm_model: claude-haiku-4-5; } /* all nodes */
|
||||
.coding { llm_model: claude-sonnet-4-5; } /* nodes with class="coding" */
|
||||
#review { llm_model: gemini-3.1-pro-preview; } /* node with id "review" */
|
||||
```
|
||||
|
||||
Selectors cascade by specificity: `*` (0) < `shape` (1) < `.class` (2) < `#id` (3). Explicit node attributes always override stylesheets. See [Model Stylesheets](/workflows/stylesheets) for details.
|
||||
|
||||
## Goal gates
|
||||
|
||||
Mark critical nodes with `goal_gate=true`. The workflow fails if any goal gate doesn't succeed — even if execution reaches the exit node:
|
||||
|
||||
```dot
|
||||
validate [label="Validate", prompt="Run the test suite and verify all tests pass.", goal_gate=true]
|
||||
```
|
||||
|
||||
## Running a workflow
|
||||
|
||||
From the CLI:
|
||||
|
||||
```bash
|
||||
arc run start workflow.dot
|
||||
```
|
||||
|
||||
Or from a [run config TOML](/execution/run-configuration) for repeatable, parameterized runs:
|
||||
|
||||
```bash
|
||||
arc run start run.toml
|
||||
```
|
||||
|
||||
See the [Quick Start](/getting-started/quick-start) to try it out, or browse the [example workflows](/examples/implement-feature) for real-world patterns.
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
"group": "Defining Workflows",
|
||||
"icon": "diagram-project",
|
||||
"pages": [
|
||||
"workflows/ingestion",
|
||||
"workflows/stages-and-nodes",
|
||||
"workflows/transitions",
|
||||
"workflows/variables",
|
||||
|
|
|
|||
63
docs/images/anatomy-workflow.svg
Normal file
63
docs/images/anatomy-workflow.svg
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 14.1.2 (20260124.0452)
|
||||
-->
|
||||
<!-- Title: MyWorkflow Pages: 1 -->
|
||||
<svg width="413pt" height="44pt"
|
||||
viewBox="0.00 0.00 413.00 44.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 40.25)">
|
||||
<title>MyWorkflow</title>
|
||||
<!-- start -->
|
||||
<g id="node1" class="node">
|
||||
<title>start</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="35.26,-36.12 0,-18.13 35.26,-0.13 70.52,-18.12 35.26,-36.12"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="10.69,-23.58 10.69,-12.67"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="24.57,-5.58 45.95,-5.58"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="59.83,-12.67 59.83,-23.58"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="45.95,-30.67 24.57,-30.67"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="35.26" y="-13.1" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Start</text>
|
||||
</g>
|
||||
<!-- scan -->
|
||||
<g id="node3" class="node">
|
||||
<title>scan</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="237.5,-36.12 133.32,-36.12 106.52,-0.13 210.7,-0.13 237.5,-36.12"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="172.01" y="-13.1" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Scan Files</text>
|
||||
</g>
|
||||
<!-- start->scan -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>start->scan</title>
|
||||
<path fill="none" stroke="#666666" d="M71.31,-18.12C82.54,-18.12 95.33,-18.12 107.92,-18.12"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="107.87,-21.63 117.87,-18.13 107.87,-14.63 107.87,-21.63"/>
|
||||
</g>
|
||||
<!-- exit -->
|
||||
<g id="node2" class="node">
|
||||
<title>exit</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="405.25,-36.25 369,-36.25 369,0 405.25,0 405.25,-36.25"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="381,-36.25 369,-24.25"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="369,-12 381,0"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="393.25,0 405.25,-12"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="405.25,-24.25 393.25,-36.25"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="387.13" y="-13.1" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Exit</text>
|
||||
</g>
|
||||
<!-- analyze -->
|
||||
<g id="node4" class="node">
|
||||
<title>analyze</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="333,-36.12 285.5,-36.12 285.5,-40.12 273.5,-40.12 273.5,-0.12 333,-0.12 333,-36.12"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="273.5,-36.12 285.5,-36.12"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="303.25" y="-13.1" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Analyze</text>
|
||||
</g>
|
||||
<!-- scan->analyze -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>scan->analyze</title>
|
||||
<path fill="none" stroke="#666666" d="M224.46,-18.12C236.92,-18.12 250.06,-18.12 261.93,-18.12"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="261.78,-21.63 271.78,-18.13 261.78,-14.63 261.78,-21.63"/>
|
||||
</g>
|
||||
<!-- analyze->exit -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>analyze->exit</title>
|
||||
<path fill="none" stroke="#666666" d="M333.35,-18.12C341.07,-18.12 349.41,-18.12 357.12,-18.12"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="357.05,-21.63 367.05,-18.13 357.05,-14.63 357.05,-21.63"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
82
docs/images/branch-loop-workflow.svg
Normal file
82
docs/images/branch-loop-workflow.svg
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 14.1.2 (20260124.0452)
|
||||
-->
|
||||
<!-- Title: BranchLoop Pages: 1 -->
|
||||
<svg width="626pt" height="79pt"
|
||||
viewBox="0.00 0.00 626.00 79.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 75.12)">
|
||||
<title>BranchLoop</title>
|
||||
<!-- start -->
|
||||
<g id="node1" class="node">
|
||||
<title>start</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="35.26,-36.12 0,-18.13 35.26,-0.13 70.52,-18.12 35.26,-36.12"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="10.69,-23.58 10.69,-12.67"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="24.57,-5.58 45.95,-5.58"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="59.83,-12.67 59.83,-23.58"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="45.95,-30.67 24.57,-30.67"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="35.26" y="-13.1" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Start</text>
|
||||
</g>
|
||||
<!-- implement -->
|
||||
<g id="node3" class="node">
|
||||
<title>implement</title>
|
||||
<path fill="none" stroke="#357f9e" d="M167.02,-36.12C167.02,-36.12 119.52,-36.12 119.52,-36.12 113.52,-36.12 107.52,-30.12 107.52,-24.12 107.52,-24.12 107.52,-12.12 107.52,-12.12 107.52,-6.12 113.52,-0.12 119.52,-0.12 119.52,-0.12 167.02,-0.12 167.02,-0.12 173.02,-0.12 179.02,-6.12 179.02,-12.12 179.02,-12.12 179.02,-24.13 179.02,-24.13 179.02,-30.12 173.02,-36.12 167.02,-36.12"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="143.27" y="-13.1" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Implement</text>
|
||||
</g>
|
||||
<!-- start->implement -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>start->implement</title>
|
||||
<path fill="none" stroke="#666666" d="M71.56,-18.12C79.34,-18.12 87.69,-18.12 95.84,-18.12"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="95.61,-21.63 105.61,-18.13 95.61,-14.63 95.61,-21.63"/>
|
||||
</g>
|
||||
<!-- exit -->
|
||||
<g id="node2" class="node">
|
||||
<title>exit</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="618.46,-36.25 582.21,-36.25 582.21,0 618.46,0 618.46,-36.25"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="594.21,-36.25 582.21,-24.25"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="582.21,-12 594.21,0"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="606.46,0 618.46,-12"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="618.46,-24.25 606.46,-36.25"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="600.33" y="-13.1" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Exit</text>
|
||||
</g>
|
||||
<!-- validate -->
|
||||
<g id="node4" class="node">
|
||||
<title>validate</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="321.43,-71.12 237.59,-71.12 216.02,-35.13 299.86,-35.12 321.43,-71.12"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="268.73" y="-48.1" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Validate</text>
|
||||
</g>
|
||||
<!-- implement->validate -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>implement->validate</title>
|
||||
<path fill="none" stroke="#666666" d="M179.32,-28.06C187.93,-30.5 197.39,-33.18 206.83,-35.86"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="205.82,-39.21 216.39,-38.57 207.72,-32.48 205.82,-39.21"/>
|
||||
</g>
|
||||
<!-- gate -->
|
||||
<g id="node5" class="node">
|
||||
<title>gate</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="441.07,-36.12 358.43,-18.13 441.07,-0.13 523.71,-18.12 441.07,-36.12"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="441.07" y="-13.1" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Tests passing?</text>
|
||||
</g>
|
||||
<!-- validate->gate -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>validate->gate</title>
|
||||
<path fill="none" stroke="#666666" d="M306.27,-45.62C329.43,-40.86 359.81,-34.62 385.77,-29.28"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="386.39,-32.73 395.48,-27.29 384.98,-25.87 386.39,-32.73"/>
|
||||
</g>
|
||||
<!-- gate->exit -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>gate->exit</title>
|
||||
<path fill="none" stroke="#666666" d="M525.77,-18.12C541.89,-18.12 557.72,-18.12 570.55,-18.12"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="570.32,-21.63 580.32,-18.13 570.32,-14.63 570.32,-21.63"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="552.96" y="-19.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#666666">Pass</text>
|
||||
</g>
|
||||
<!-- gate->implement -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>gate->implement</title>
|
||||
<path fill="none" stroke="#666666" d="M367.41,-15.71C323.57,-14.59 266.58,-13.73 216.02,-14.88 207.79,-15.06 199.04,-15.37 190.58,-15.72"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="190.64,-12.21 180.81,-16.15 190.95,-19.21 190.64,-12.21"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="268.73" y="-16.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#666666">Fix</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
113
docs/images/ensemble-workflow.svg
Normal file
113
docs/images/ensemble-workflow.svg
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 14.1.2 (20260124.0452)
|
||||
-->
|
||||
<!-- Title: Ensemble Pages: 1 -->
|
||||
<svg width="587pt" height="98pt"
|
||||
viewBox="0.00 0.00 587.00 98.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 94)">
|
||||
<title>Ensemble</title>
|
||||
<!-- start -->
|
||||
<g id="node1" class="node">
|
||||
<title>start</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="35.26,-63 0,-45 35.26,-27 70.52,-45 35.26,-63"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="10.69,-50.46 10.69,-39.54"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="24.57,-32.46 45.95,-32.46"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="59.83,-39.54 59.83,-50.46"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="45.95,-57.54 24.57,-57.54"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="35.26" y="-39.98" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Start</text>
|
||||
</g>
|
||||
<!-- fork -->
|
||||
<g id="node3" class="node">
|
||||
<title>fork</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="165.27,-63 106.52,-63 106.52,-59 102.52,-59 102.52,-55 106.52,-55 106.52,-35 102.52,-35 102.52,-31 106.52,-31 106.52,-27 165.27,-27 165.27,-63"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="106.52,-59 110.52,-59 110.52,-55 106.52,-55"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="106.52,-35 110.52,-35 110.52,-31 106.52,-31"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="135.9" y="-39.98" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Fan Out</text>
|
||||
</g>
|
||||
<!-- start->fork -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>start->fork</title>
|
||||
<path fill="none" stroke="#666666" d="M71.59,-45C79.15,-45 87.19,-45 94.92,-45"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="94.78,-48.5 104.78,-45 94.78,-41.5 94.78,-48.5"/>
|
||||
</g>
|
||||
<!-- exit -->
|
||||
<g id="node2" class="node">
|
||||
<title>exit</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="578.67,-63.12 542.42,-63.12 542.42,-26.88 578.67,-26.88 578.67,-63.12"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="554.42,-63.12 542.42,-51.12"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="542.42,-38.88 554.42,-26.88"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="566.67,-26.88 578.67,-38.88"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="578.67,-51.12 566.67,-63.12"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="560.54" y="-39.98" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Exit</text>
|
||||
</g>
|
||||
<!-- opus -->
|
||||
<g id="node4" class="node">
|
||||
<title>opus</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="276.52,-90 214.02,-90 214.02,-94 202.02,-94 202.02,-54 276.52,-54 276.52,-90"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="202.02,-90 214.02,-90"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="239.27" y="-73.35" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Opus</text>
|
||||
<text xml:space="preserve" text-anchor="middle" x="239.27" y="-60.6" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">(Anthropic)</text>
|
||||
</g>
|
||||
<!-- fork->opus -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>fork->opus</title>
|
||||
<path fill="none" stroke="#666666" d="M165.68,-52.66C173.49,-54.75 182.17,-57.06 190.72,-59.34"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="189.79,-62.71 200.35,-61.9 191.59,-55.95 189.79,-62.71"/>
|
||||
</g>
|
||||
<!-- gemini -->
|
||||
<g id="node5" class="node">
|
||||
<title>gemini</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="277.27,-36 213.27,-36 213.27,-40 201.27,-40 201.27,0 277.27,0 277.27,-36"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="201.27,-36 213.27,-36"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="239.27" y="-19.35" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Gemini Pro</text>
|
||||
<text xml:space="preserve" text-anchor="middle" x="239.27" y="-6.6" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">(Google)</text>
|
||||
</g>
|
||||
<!-- fork->gemini -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>fork->gemini</title>
|
||||
<path fill="none" stroke="#666666" d="M165.68,-37.34C173.33,-35.3 181.8,-33.04 190.19,-30.81"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="190.85,-34.25 199.61,-28.3 189.05,-27.49 190.85,-34.25"/>
|
||||
</g>
|
||||
<!-- merge -->
|
||||
<g id="node6" class="node">
|
||||
<title>merge</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="387.17,-37.54 387.17,-52.46 367.87,-63 340.57,-63 321.27,-52.46 321.27,-37.54 340.57,-27 367.87,-27 387.17,-37.54"/>
|
||||
<polygon fill="none" stroke="#357f9e" points="391.17,-35.17 391.17,-54.83 368.89,-67 339.55,-67 317.27,-54.83 317.27,-35.17 339.55,-23 368.89,-23 391.17,-35.17"/>
|
||||
<polygon fill="none" stroke="#357f9e" points="395.17,-32.8 395.17,-57.2 369.91,-71 338.53,-71 313.27,-57.2 313.27,-32.8 338.53,-19 369.91,-19 395.17,-32.8"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="354.22" y="-39.98" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Merge</text>
|
||||
</g>
|
||||
<!-- opus->merge -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>opus->merge</title>
|
||||
<path fill="none" stroke="#666666" d="M276.94,-63.23C284.92,-61.33 293.49,-59.28 301.91,-57.27"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="302.44,-60.74 311.36,-55.01 300.82,-53.93 302.44,-60.74"/>
|
||||
</g>
|
||||
<!-- gemini->merge -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>gemini->merge</title>
|
||||
<path fill="none" stroke="#666666" d="M277.57,-26.92C285.34,-28.77 293.67,-30.76 301.85,-32.72"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="300.84,-36.08 311.38,-35 302.47,-29.27 300.84,-36.08"/>
|
||||
</g>
|
||||
<!-- synth -->
|
||||
<g id="node7" class="node">
|
||||
<title>synth</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="506.42,-63 443.17,-63 443.17,-67 431.17,-67 431.17,-27 506.42,-27 506.42,-63"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="431.17,-63 443.17,-63"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="468.79" y="-39.98" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Synthesize</text>
|
||||
</g>
|
||||
<!-- merge->synth -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>merge->synth</title>
|
||||
<path fill="none" stroke="#666666" d="M395.54,-45C403.26,-45 411.41,-45 419.35,-45"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="419.24,-48.5 429.24,-45 419.24,-41.5 419.24,-48.5"/>
|
||||
</g>
|
||||
<!-- synth->exit -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>synth->exit</title>
|
||||
<path fill="none" stroke="#666666" d="M506.82,-45C514.71,-45 522.93,-45 530.47,-45"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="530.46,-48.5 540.46,-45 530.46,-41.5 530.46,-48.5"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
160
docs/images/how-arc-works.svg
Normal file
160
docs/images/how-arc-works.svg
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 14.1.2 (20260124.0452)
|
||||
-->
|
||||
<!-- Title: HowArcWorks Pages: 1 -->
|
||||
<svg width="684pt" height="424pt"
|
||||
viewBox="0.00 0.00 684.00 424.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 420)">
|
||||
<title>HowArcWorks</title>
|
||||
<g id="clust1" class="cluster">
|
||||
<title>cluster_author</title>
|
||||
<polygon fill="none" stroke="#999999" stroke-dasharray="5,2" points="8,-336 8,-408 304,-408 304,-336 8,-336"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="156" y="-393.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#666666">Author Time</text>
|
||||
</g>
|
||||
<g id="clust2" class="cluster">
|
||||
<title>cluster_engine</title>
|
||||
<polygon fill="none" stroke="#999999" stroke-dasharray="5,2" points="99,-8 99,-317 330,-317 330,-8 99,-8"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="214.5" y="-302.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#666666">Runtime</text>
|
||||
</g>
|
||||
<g id="clust3" class="cluster">
|
||||
<title>cluster_external</title>
|
||||
<polygon fill="none" stroke="#999999" stroke-dasharray="5,2" points="338,-8 338,-80 668,-80 668,-8 338,-8"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="503" y="-65.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#666666">External</text>
|
||||
</g>
|
||||
<!-- dot -->
|
||||
<g id="node1" class="node">
|
||||
<title>dot</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="71.5,-380 16.5,-380 16.5,-344 77.5,-344 77.5,-374 71.5,-380"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="71.5,-380 71.5,-374"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="77.5,-374 71.5,-374"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="47" y="-363.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">Workflow</text>
|
||||
<text xml:space="preserve" text-anchor="middle" x="47" y="-351.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">(.dot)</text>
|
||||
</g>
|
||||
<!-- parse -->
|
||||
<g id="node4" class="node">
|
||||
<title>parse</title>
|
||||
<path fill="none" stroke="#357f9e" d="M182.75,-289C182.75,-289 129.25,-289 129.25,-289 123.25,-289 117.25,-283 117.25,-277 117.25,-277 117.25,-265 117.25,-265 117.25,-259 123.25,-253 129.25,-253 129.25,-253 182.75,-253 182.75,-253 188.75,-253 194.75,-259 194.75,-265 194.75,-265 194.75,-277 194.75,-277 194.75,-283 188.75,-289 182.75,-289"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="156" y="-266.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">Parse Graph</text>
|
||||
</g>
|
||||
<!-- dot->parse -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>dot->parse</title>
|
||||
<path fill="none" stroke="#666666" d="M68.28,-343.63C84.71,-330.21 107.65,-311.48 125.95,-296.53"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="128.07,-299.32 133.61,-290.28 123.65,-293.9 128.07,-299.32"/>
|
||||
</g>
|
||||
<!-- toml -->
|
||||
<g id="node2" class="node">
|
||||
<title>toml</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="185.38,-380 120.62,-380 120.62,-344 191.38,-344 191.38,-374 185.38,-380"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="185.38,-380 185.38,-374"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="191.38,-374 185.38,-374"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="156" y="-363.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">Run Config</text>
|
||||
<text xml:space="preserve" text-anchor="middle" x="156" y="-351.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">(.toml)</text>
|
||||
</g>
|
||||
<!-- toml->parse -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>toml->parse</title>
|
||||
<path fill="none" stroke="#666666" d="M156,-343.84C156,-331.61 156,-314.87 156,-300.63"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="159.5,-300.92 156,-290.92 152.5,-300.92 159.5,-300.92"/>
|
||||
</g>
|
||||
<!-- env -->
|
||||
<g id="node3" class="node">
|
||||
<title>env</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="289.5,-380 234.5,-380 234.5,-344 295.5,-344 295.5,-374 289.5,-380"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="289.5,-380 289.5,-374"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="295.5,-374 289.5,-374"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="265" y="-363.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">API Keys</text>
|
||||
<text xml:space="preserve" text-anchor="middle" x="265" y="-351.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">(.env)</text>
|
||||
</g>
|
||||
<!-- env->parse -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>env->parse</title>
|
||||
<path fill="none" stroke="#666666" d="M243.72,-343.63C227.29,-330.21 204.35,-311.48 186.05,-296.53"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="188.35,-293.9 178.39,-290.28 183.93,-299.32 188.35,-293.9"/>
|
||||
</g>
|
||||
<!-- engine -->
|
||||
<g id="node5" class="node">
|
||||
<title>engine</title>
|
||||
<path fill="none" stroke="#357f9e" stroke-width="2" d="M192.88,-216C192.88,-216 119.12,-216 119.12,-216 113.12,-216 107.12,-210 107.12,-204 107.12,-204 107.12,-192 107.12,-192 107.12,-186 113.12,-180 119.12,-180 119.12,-180 192.88,-180 192.88,-180 198.88,-180 204.88,-186 204.88,-192 204.88,-192 204.88,-204 204.88,-204 204.88,-210 198.88,-216 192.88,-216"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="156" y="-193.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">Workflow Engine</text>
|
||||
</g>
|
||||
<!-- parse->engine -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>parse->engine</title>
|
||||
<path fill="none" stroke="#666666" d="M156,-252.81C156,-245.23 156,-236.1 156,-227.54"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="159.5,-227.54 156,-217.54 152.5,-227.54 159.5,-227.54"/>
|
||||
</g>
|
||||
<!-- handler -->
|
||||
<g id="node6" class="node">
|
||||
<title>handler</title>
|
||||
<path fill="none" stroke="#357f9e" d="M310.38,-143C310.38,-143 245.62,-143 245.62,-143 239.62,-143 233.62,-137 233.62,-131 233.62,-131 233.62,-119 233.62,-119 233.62,-113 239.62,-107 245.62,-107 245.62,-107 310.38,-107 310.38,-107 316.38,-107 322.38,-113 322.38,-119 322.38,-119 322.38,-131 322.38,-131 322.38,-137 316.38,-143 310.38,-143"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="278" y="-120.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">Node Handlers</text>
|
||||
</g>
|
||||
<!-- engine->handler -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>engine->handler</title>
|
||||
<path fill="none" stroke="#666666" d="M185.84,-179.63C201.65,-170.43 221.27,-159.02 238.33,-149.08"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="239.85,-152.25 246.73,-144.2 236.33,-146.2 239.85,-152.25"/>
|
||||
</g>
|
||||
<!-- transition -->
|
||||
<g id="node7" class="node">
|
||||
<title>transition</title>
|
||||
<path fill="none" stroke="#357f9e" d="M247.38,-52C247.38,-52 182.62,-52 182.62,-52 176.62,-52 170.62,-46 170.62,-40 170.62,-40 170.62,-28 170.62,-28 170.62,-22 176.62,-16 182.62,-16 182.62,-16 247.38,-16 247.38,-16 253.38,-16 259.38,-22 259.38,-28 259.38,-28 259.38,-40 259.38,-40 259.38,-46 253.38,-52 247.38,-52"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="215" y="-29.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">Edge Selection</text>
|
||||
</g>
|
||||
<!-- handler->transition -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>handler->transition</title>
|
||||
<path fill="none" stroke="#666666" d="M265.85,-106.84C256.76,-93.99 244.16,-76.19 233.77,-61.52"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="236.83,-59.79 228.2,-53.65 231.12,-63.83 236.83,-59.79"/>
|
||||
</g>
|
||||
<!-- llm -->
|
||||
<g id="node8" class="node">
|
||||
<title>llm</title>
|
||||
<path fill="none" stroke="#357f9e" d="M395.88,-52C395.88,-52 358.12,-52 358.12,-52 352.12,-52 346.12,-46 346.12,-40 346.12,-40 346.12,-28 346.12,-28 346.12,-22 352.12,-16 358.12,-16 358.12,-16 395.88,-16 395.88,-16 401.88,-16 407.88,-22 407.88,-28 407.88,-28 407.88,-40 407.88,-40 407.88,-46 401.88,-52 395.88,-52"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="377" y="-35.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">LLM</text>
|
||||
<text xml:space="preserve" text-anchor="middle" x="377" y="-23.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">Providers</text>
|
||||
</g>
|
||||
<!-- handler->llm -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>handler->llm</title>
|
||||
<path fill="none" stroke="#666666" d="M305.75,-106.63C316.9,-99.07 329.57,-89.72 340,-80 346.21,-74.22 352.32,-67.39 357.73,-60.83"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="360.19,-63.36 363.68,-53.35 354.72,-59 360.19,-63.36"/>
|
||||
</g>
|
||||
<!-- sandbox -->
|
||||
<g id="node9" class="node">
|
||||
<title>sandbox</title>
|
||||
<path fill="none" stroke="#357f9e" d="M550.62,-52C550.62,-52 463.38,-52 463.38,-52 457.38,-52 451.38,-46 451.38,-40 451.38,-40 451.38,-28 451.38,-28 451.38,-22 457.38,-16 463.38,-16 463.38,-16 550.62,-16 550.62,-16 556.62,-16 562.62,-22 562.62,-28 562.62,-28 562.62,-40 562.62,-40 562.62,-46 556.62,-52 550.62,-52"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="507" y="-35.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">Sandbox</text>
|
||||
<text xml:space="preserve" text-anchor="middle" x="507" y="-23.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">(local/Docker/cloud)</text>
|
||||
</g>
|
||||
<!-- handler->sandbox -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>handler->sandbox</title>
|
||||
<path fill="none" stroke="#666666" d="M322.58,-114C353.17,-106.42 394.34,-94.79 429,-80 443.07,-74 457.78,-66.01 470.58,-58.43"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="472.36,-61.44 479.1,-53.27 468.73,-55.46 472.36,-61.44"/>
|
||||
</g>
|
||||
<!-- human -->
|
||||
<g id="node10" class="node">
|
||||
<title>human</title>
|
||||
<path fill="none" stroke="#357f9e" d="M648,-52C648,-52 618,-52 618,-52 612,-52 606,-46 606,-40 606,-40 606,-28 606,-28 606,-22 612,-16 618,-16 618,-16 648,-16 648,-16 654,-16 660,-22 660,-28 660,-28 660,-40 660,-40 660,-46 654,-52 648,-52"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="633" y="-35.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">Human</text>
|
||||
<text xml:space="preserve" text-anchor="middle" x="633" y="-23.55" font-family="Helvetica,sans-Serif" font-size="11.00" fill="#1a1a1a">Input</text>
|
||||
</g>
|
||||
<!-- handler->human -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>handler->human</title>
|
||||
<path fill="none" stroke="#666666" d="M322.82,-120.82C396.28,-115.07 538.66,-101.5 584,-80 593.96,-75.27 603.31,-67.82 611.11,-60.32"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="613.4,-62.98 617.88,-53.38 608.39,-58.1 613.4,-62.98"/>
|
||||
</g>
|
||||
<!-- transition->engine -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>transition->engine</title>
|
||||
<path fill="none" stroke="#666666" d="M201.94,-52.39C192.05,-66.41 178.95,-87.02 171.5,-107 164.13,-126.77 160.23,-150.3 158.19,-168.35"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="154.73,-167.78 157.22,-178.08 161.69,-168.47 154.73,-167.78"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="191.75" y="-121.33" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#666666">next node</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
130
docs/images/parallel-workflow.svg
Normal file
130
docs/images/parallel-workflow.svg
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 14.1.2 (20260124.0452)
|
||||
-->
|
||||
<!-- Title: Parallel Pages: 1 -->
|
||||
<svg width="641pt" height="152pt"
|
||||
viewBox="0.00 0.00 641.00 152.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 148)">
|
||||
<title>Parallel</title>
|
||||
<!-- start -->
|
||||
<g id="node1" class="node">
|
||||
<title>start</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="35.26,-90 0,-72 35.26,-54 70.52,-72 35.26,-90"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="10.69,-77.46 10.69,-66.54"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="24.57,-59.46 45.95,-59.46"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="59.83,-66.54 59.83,-77.46"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="45.95,-84.54 24.57,-84.54"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="35.26" y="-66.97" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Start</text>
|
||||
</g>
|
||||
<!-- fork -->
|
||||
<g id="node3" class="node">
|
||||
<title>fork</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="165.27,-90 106.52,-90 106.52,-86 102.52,-86 102.52,-82 106.52,-82 106.52,-62 102.52,-62 102.52,-58 106.52,-58 106.52,-54 165.27,-54 165.27,-90"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="106.52,-86 110.52,-86 110.52,-82 106.52,-82"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="106.52,-62 110.52,-62 110.52,-58 106.52,-58"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="135.9" y="-66.97" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Fan Out</text>
|
||||
</g>
|
||||
<!-- start->fork -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>start->fork</title>
|
||||
<path fill="none" stroke="#666666" d="M71.59,-72C79.15,-72 87.19,-72 94.92,-72"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="94.78,-75.5 104.78,-72 94.78,-68.5 94.78,-75.5"/>
|
||||
</g>
|
||||
<!-- exit -->
|
||||
<g id="node2" class="node">
|
||||
<title>exit</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="632.67,-90.12 596.42,-90.12 596.42,-53.88 632.67,-53.88 632.67,-90.12"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="608.42,-90.12 596.42,-78.12"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="596.42,-65.88 608.42,-53.88"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="620.67,-53.88 632.67,-65.88"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="632.67,-78.12 620.67,-90.12"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="614.54" y="-66.97" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Exit</text>
|
||||
</g>
|
||||
<!-- security -->
|
||||
<g id="node4" class="node">
|
||||
<title>security</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="307.65,-144 230.15,-144 230.15,-148 218.15,-148 218.15,-108 307.65,-108 307.65,-144"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="218.15,-144 230.15,-144"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="262.9" y="-120.97" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Security Audit</text>
|
||||
</g>
|
||||
<!-- fork->security -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>fork->security</title>
|
||||
<path fill="none" stroke="#666666" d="M165.57,-84.39C178.46,-89.95 194.09,-96.71 208.97,-103.14"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="207.16,-106.17 217.73,-106.92 209.94,-99.74 207.16,-106.17"/>
|
||||
</g>
|
||||
<!-- architecture -->
|
||||
<g id="node5" class="node">
|
||||
<title>architecture</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="324.52,-90 213.27,-90 213.27,-94 201.27,-94 201.27,-54 324.52,-54 324.52,-90"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="201.27,-90 213.27,-90"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="262.9" y="-66.97" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Architecture Review</text>
|
||||
</g>
|
||||
<!-- fork->architecture -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>fork->architecture</title>
|
||||
<path fill="none" stroke="#666666" d="M165.57,-72C172.94,-72 181.21,-72 189.72,-72"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="189.48,-75.5 199.48,-72 189.48,-68.5 189.48,-75.5"/>
|
||||
</g>
|
||||
<!-- quality -->
|
||||
<g id="node6" class="node">
|
||||
<title>quality</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="305.77,-36 232.02,-36 232.02,-40 220.02,-40 220.02,0 305.77,0 305.77,-36"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="220.02,-36 232.02,-36"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="262.9" y="-12.97" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Code Quality</text>
|
||||
</g>
|
||||
<!-- fork->quality -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>fork->quality</title>
|
||||
<path fill="none" stroke="#666666" d="M165.57,-59.61C178.58,-53.99 194.37,-47.17 209.38,-40.69"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="210.42,-44.05 218.21,-36.87 207.64,-37.63 210.42,-44.05"/>
|
||||
</g>
|
||||
<!-- merge -->
|
||||
<g id="node7" class="node">
|
||||
<title>merge</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="434.42,-64.54 434.42,-79.46 415.12,-90 387.82,-90 368.52,-79.46 368.52,-64.54 387.82,-54 415.12,-54 434.42,-64.54"/>
|
||||
<polygon fill="none" stroke="#357f9e" points="438.42,-62.17 438.42,-81.83 416.14,-94 386.8,-94 364.52,-81.83 364.52,-62.17 386.8,-50 416.14,-50 438.42,-62.17"/>
|
||||
<polygon fill="none" stroke="#357f9e" points="442.42,-59.8 442.42,-84.2 417.16,-98 385.78,-98 360.52,-84.2 360.52,-59.8 385.78,-46 417.16,-46 442.42,-59.8"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="401.47" y="-66.97" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Merge</text>
|
||||
</g>
|
||||
<!-- security->merge -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>security->merge</title>
|
||||
<path fill="none" stroke="#666666" d="M307.86,-108.62C322.42,-102.86 338.67,-96.43 353.45,-90.59"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="354.49,-93.95 362.5,-87.01 351.91,-87.44 354.49,-93.95"/>
|
||||
</g>
|
||||
<!-- architecture->merge -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>architecture->merge</title>
|
||||
<path fill="none" stroke="#666666" d="M324.99,-72C332.92,-72 340.97,-72 348.72,-72"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="348.68,-75.5 358.68,-72 348.68,-68.5 348.68,-75.5"/>
|
||||
</g>
|
||||
<!-- quality->merge -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>quality->merge</title>
|
||||
<path fill="none" stroke="#666666" d="M305.99,-34.64C321.02,-40.58 338.04,-47.32 353.46,-53.41"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="351.84,-56.53 362.42,-56.96 354.41,-50.02 351.84,-56.53"/>
|
||||
</g>
|
||||
<!-- report -->
|
||||
<g id="node8" class="node">
|
||||
<title>report</title>
|
||||
<polygon fill="none" stroke="#357f9e" points="560.42,-90 490.42,-90 490.42,-94 478.42,-94 478.42,-54 560.42,-54 560.42,-90"/>
|
||||
<polyline fill="none" stroke="#357f9e" points="478.42,-90 490.42,-90"/>
|
||||
<text xml:space="preserve" text-anchor="middle" x="519.42" y="-66.97" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#1a1a1a">Final Report</text>
|
||||
</g>
|
||||
<!-- merge->report -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>merge->report</title>
|
||||
<path fill="none" stroke="#666666" d="M442.7,-72C450.52,-72 458.82,-72 466.95,-72"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="466.75,-75.5 476.75,-72 466.75,-68.5 466.75,-75.5"/>
|
||||
</g>
|
||||
<!-- report->exit -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>report->exit</title>
|
||||
<path fill="none" stroke="#666666" d="M560.72,-72C568.76,-72 577.04,-72 584.6,-72"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="584.58,-75.5 594.58,-72 584.58,-68.5 584.58,-75.5"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.3 KiB |
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: "Ingestion"
|
||||
description: "How Arc ingests workflow definitions"
|
||||
---
|
||||
|
||||
|
|
@ -1,5 +1,217 @@
|
|||
---
|
||||
title: "Stages & Nodes"
|
||||
description: "Defining stages and nodes in workflows"
|
||||
title: "Nodes & Stages"
|
||||
description: "All node types and how they become stages at runtime"
|
||||
---
|
||||
|
||||
## Nodes vs. stages
|
||||
|
||||
A **node** is a step defined in the DOT file at author time. A **stage** is the runtime execution of a node. In a simple linear workflow, each node runs once and produces one stage. But when a workflow loops — for example, an implement-test-fix cycle — the same node can produce multiple stages within a single run.
|
||||
|
||||
This distinction matters for observability and debugging: the workflow graph shows nodes, but the run timeline shows stages. Each stage records its own inputs, outputs, duration, and token usage.
|
||||
|
||||
## Node types
|
||||
|
||||
Every node's Graphviz `shape` attribute determines its execution behavior. If no shape is specified, the node defaults to an agent.
|
||||
|
||||
### Start
|
||||
|
||||
**Shape:** `Mdiamond`
|
||||
|
||||
The entry point of the workflow. Every workflow must have exactly one start node.
|
||||
|
||||
```dot
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
```
|
||||
|
||||
### Exit
|
||||
|
||||
**Shape:** `Msquare`
|
||||
|
||||
The terminal node. When execution reaches exit, the workflow completes. Every workflow must have exactly one exit node.
|
||||
|
||||
```dot
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
```
|
||||
|
||||
### Agent
|
||||
|
||||
**Shape:** `box` (default)
|
||||
|
||||
Runs an LLM with access to tools — bash, file editing, sub-agents — in an agentic loop. The agent works autonomously, calling tools as needed, until it decides the task is complete.
|
||||
|
||||
```dot
|
||||
implement [label="Implement", prompt="Read plan.md and implement every step."]
|
||||
```
|
||||
|
||||
Key attributes:
|
||||
|
||||
| Attribute | Description |
|
||||
|---|---|
|
||||
| `prompt` | The task instructions for the agent |
|
||||
| `reasoning_effort` | `low`, `medium`, or `high` (default: `high`) |
|
||||
| `max_tokens` | Maximum tokens for LLM responses |
|
||||
| `fidelity` | How much prior context is passed to this node (see table below) |
|
||||
| `thread_id` | Groups nodes into a shared conversation thread (advanced — see below) |
|
||||
| `timeout` | Execution timeout (e.g. `"900s"`) |
|
||||
|
||||
**Fidelity levels:**
|
||||
|
||||
| Value | Behavior |
|
||||
|---|---|
|
||||
| `compact` | Structured summary of prior stages (default) |
|
||||
| `full` | Complete context from all prior stages — no summarization |
|
||||
| `summary:high` | Detailed summary including outputs and key details |
|
||||
| `summary:medium` | Moderate summary with outcomes and notable findings |
|
||||
| `summary:low` | Brief summary with just outcomes per stage |
|
||||
| `truncate` | Minimal — only the goal and run ID |
|
||||
|
||||
Fidelity can also be set at the graph level (`default_fidelity`) or on individual edges to control the transition between stages.
|
||||
|
||||
**Thread ID:**
|
||||
|
||||
Setting `thread_id` on multiple nodes (e.g. `thread_id="impl"`) groups them into a shared conversation thread, preserving context continuity across nodes as if they were part of the same session. This is an advanced feature typically used within subgraph clusters:
|
||||
|
||||
```dot
|
||||
subgraph cluster_impl {
|
||||
node [fidelity="full", thread_id="impl"]
|
||||
plan [label="Plan"]
|
||||
implement [label="Implement"]
|
||||
review [label="Review"]
|
||||
}
|
||||
```
|
||||
|
||||
### Prompt
|
||||
|
||||
**Shape:** `tab`
|
||||
|
||||
Makes a single LLM call with no tool use. Useful for analysis, summarization, generation, and lightweight reasoning where tools aren't needed.
|
||||
|
||||
```dot
|
||||
spec [label="Write Spec", shape=tab, prompt="Write a brief spec for a string utility module."]
|
||||
```
|
||||
|
||||
Prompt nodes accept the same attributes as agent nodes (`prompt`, `reasoning_effort`, `max_tokens`, etc.) but never invoke tools.
|
||||
|
||||
### Command
|
||||
|
||||
**Shape:** `parallelogram`
|
||||
|
||||
Runs a shell script and captures its output. The output is available to downstream nodes as context.
|
||||
|
||||
```dot
|
||||
test [label="Run Tests", shape=parallelogram, script="cargo test 2>&1 || true"]
|
||||
```
|
||||
|
||||
| Attribute | Description |
|
||||
|---|---|
|
||||
| `script` | The shell command to execute |
|
||||
| `language` | `"shell"` (default) or `"python"` |
|
||||
|
||||
### Human
|
||||
|
||||
**Shape:** `hexagon`
|
||||
|
||||
Pauses the workflow and waits for a person to choose a path. The outgoing edge labels define the available options:
|
||||
|
||||
```dot
|
||||
approve [shape=hexagon, label="Approve Plan"]
|
||||
|
||||
approve -> implement [label="[A] Approve"]
|
||||
approve -> plan [label="[R] Revise"]
|
||||
```
|
||||
|
||||
In the web UI, human gates appear as interactive prompts. From the CLI, they appear as a menu.
|
||||
|
||||
### Conditional
|
||||
|
||||
**Shape:** `diamond`
|
||||
|
||||
Routes execution to different edges based on conditions evaluated against the current run context:
|
||||
|
||||
```dot
|
||||
gate [shape=diamond, label="Tests passing?"]
|
||||
|
||||
gate -> exit [label="Pass", condition="outcome=success"]
|
||||
gate -> implement [label="Fix"]
|
||||
```
|
||||
|
||||
Conditions support `=`, `!=`, `&&`, and context variable lookups (e.g. `context.tests_passed=true`). An edge with no condition acts as the default fallback.
|
||||
|
||||
### Parallel (fan-out)
|
||||
|
||||
**Shape:** `component`
|
||||
|
||||
Fans out to execute multiple branches concurrently. Each branch gets its own isolated context.
|
||||
|
||||
```dot
|
||||
fork [label="Fan Out", shape=component, join_policy="wait_all", error_policy="continue"]
|
||||
|
||||
fork -> security
|
||||
fork -> architecture
|
||||
fork -> quality
|
||||
```
|
||||
|
||||
| Attribute | Description |
|
||||
|---|---|
|
||||
| `join_policy` | When the merge can proceed (see table below) |
|
||||
| `error_policy` | How branch failures are handled (see table below) |
|
||||
| `max_parallel` | Maximum concurrent branches (default: 4) |
|
||||
|
||||
**Join policies:**
|
||||
|
||||
| Policy | Behavior |
|
||||
|---|---|
|
||||
| `wait_all` | Wait for every branch to finish (default) |
|
||||
| `first_success` | Proceed as soon as one branch succeeds |
|
||||
| `k_of_n(N)` | Proceed after N branches succeed (e.g. `k_of_n(2)`) |
|
||||
| `quorum(F)` | Proceed after a fraction of branches succeed (e.g. `quorum(0.5)`) |
|
||||
|
||||
**Error policies:**
|
||||
|
||||
| Policy | Behavior |
|
||||
|---|---|
|
||||
| `continue` | Run all branches even if some fail, then evaluate the join policy (default) |
|
||||
| `fail_fast` | Cancel remaining branches as soon as one fails |
|
||||
| `ignore` | Treat all branch failures as successes |
|
||||
|
||||
### Merge (fan-in)
|
||||
|
||||
**Shape:** `tripleoctagon`
|
||||
|
||||
Collects results from parallel branches into a single context. Typically paired with a parallel fan-out node:
|
||||
|
||||
```dot
|
||||
merge [label="Merge Results", shape=tripleoctagon]
|
||||
|
||||
security -> merge
|
||||
architecture -> merge
|
||||
quality -> merge
|
||||
merge -> report
|
||||
```
|
||||
|
||||
The merged results are available to downstream nodes as `parallel_results.json`.
|
||||
|
||||
## Common node attributes
|
||||
|
||||
These attributes can be set on any node type:
|
||||
|
||||
| Attribute | Description |
|
||||
|---|---|
|
||||
| `label` | Display name shown in the graph visualization |
|
||||
| `class` | CSS-like class for [model stylesheet](/workflows/stylesheets) targeting (space-separated for multiple) |
|
||||
| `max_visits` | Maximum times this node can execute in a run (prevents infinite loops) |
|
||||
| `goal_gate` | When `true`, the workflow fails if this node doesn't succeed |
|
||||
| `max_retries` | Override default retry count for this node |
|
||||
| `retry_policy` | Named retry preset (see table below) |
|
||||
|
||||
**Retry policies:**
|
||||
|
||||
| Preset | Attempts | Backoff | Description |
|
||||
|---|---|---|---|
|
||||
| `none` | 1 | — | No retries, fail immediately |
|
||||
| `standard` | 5 | 200ms initial, 2x exponential | Good default for transient failures |
|
||||
| `aggressive` | 5 | 500ms initial, 2x exponential | Longer initial delay for rate limits |
|
||||
| `linear` | 3 | 500ms fixed | Constant delay between attempts |
|
||||
| `patient` | 3 | 2s initial, 3x exponential | Slow ramp for unreliable services |
|
||||
|
||||
If neither `retry_policy` nor `max_retries` is set, nodes default to 3 retries with standard backoff.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,157 @@
|
|||
---
|
||||
title: "Transitions"
|
||||
description: "Defining transitions between stages"
|
||||
description: "How Arc decides which node to execute next"
|
||||
---
|
||||
|
||||
After each node finishes, Arc must decide which edge to follow to the next node. This decision is fully deterministic — given the same outcome and context, Arc always picks the same edge. Understanding the transition logic helps you design workflows that route reliably.
|
||||
|
||||
## How transitions work
|
||||
|
||||
When a node completes, it produces an **outcome** with a status (`success`, `fail`, `partial_success`) and optional signals like a preferred label or suggested next node. Arc evaluates the outgoing edges in a fixed priority order:
|
||||
|
||||
1. **Condition match** — Edges with a `condition` attribute are evaluated first. If one or more conditions match, the edge with the highest `weight` wins (lexical tiebreak on target node ID).
|
||||
2. **Preferred label** — If the node's outcome includes a preferred label (e.g. from a human gate selection), the edge whose `label` matches is chosen.
|
||||
3. **Suggested next** — If the node suggests a specific next node ID, the edge pointing to that node is chosen.
|
||||
4. **Unconditional fallback** — Edges without conditions are considered last, again using `weight` then lexical tiebreak.
|
||||
|
||||
If no edge matches at all, the workflow halts with an error.
|
||||
|
||||
## Edge attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|---|---|
|
||||
| `label` | Display text on the edge; also used for human gate option matching |
|
||||
| `condition` | Boolean expression that must evaluate to true for this edge (see below) |
|
||||
| `weight` | Numeric priority for tiebreaking (higher wins, default: 0) |
|
||||
|
||||
## Conditions
|
||||
|
||||
Edge conditions are boolean expressions evaluated against the stage outcome and run context. Conditions go in the `condition` attribute on an edge:
|
||||
|
||||
```dot
|
||||
gate -> exit [label="Pass", condition="outcome=success"]
|
||||
gate -> implement [label="Fix", condition="outcome=fail"]
|
||||
```
|
||||
|
||||
### Available keys
|
||||
|
||||
| Key | Resolves to |
|
||||
|---|---|
|
||||
| `outcome` | The stage status: `success`, `fail`, or `partial_success` |
|
||||
| `preferred_label` | The label selected by a human gate |
|
||||
| `context.KEY` | A value from the run context (e.g. `context.tests_passed`) |
|
||||
| `KEY` | Shorthand for context lookup (without the `context.` prefix) |
|
||||
|
||||
### Operators
|
||||
|
||||
| Operator | Example | Description |
|
||||
|---|---|---|
|
||||
| `=` | `outcome=success` | Equality |
|
||||
| `!=` | `outcome!=fail` | Inequality |
|
||||
| `>` | `context.score > 80` | Greater than (numeric) |
|
||||
| `<` | `context.count < 5` | Less than (numeric) |
|
||||
| `>=` | `context.score >= 80` | Greater than or equal (numeric) |
|
||||
| `<=` | `context.count <= 10` | Less than or equal (numeric) |
|
||||
| `contains` | `context.message contains error` | Substring match, or array membership |
|
||||
| `matches` | `context.version matches ^v\d+` | Regular expression match |
|
||||
|
||||
A bare key with no operator is a **truthiness check** — it passes if the value is non-empty, not `"false"`, and not `"0"`:
|
||||
|
||||
```dot
|
||||
gate -> next [condition="my_flag"]
|
||||
```
|
||||
|
||||
### Combining conditions
|
||||
|
||||
Use `&&` (AND), `||` (OR), and `!` (NOT) to build compound expressions. `&&` binds tighter than `||`:
|
||||
|
||||
```dot
|
||||
// Both must be true
|
||||
gate -> deploy [condition="outcome=success && context.tests_passed=true"]
|
||||
|
||||
// Either can be true
|
||||
gate -> proceed [condition="outcome=success || outcome=partial_success"]
|
||||
|
||||
// Negation
|
||||
gate -> retry [condition="!outcome=success"]
|
||||
|
||||
// Mixed precedence: (a AND b) OR c
|
||||
gate -> next [condition="outcome=success && context.ready=true || context.override"]
|
||||
```
|
||||
|
||||
## Agent transitions
|
||||
|
||||
Agent and prompt nodes can influence which edge is taken by including a JSON object in their response with routing directives. Arc scans the LLM output for the last JSON object containing any of these fields:
|
||||
|
||||
```json
|
||||
{
|
||||
"preferred_next_label": "fix",
|
||||
"suggested_next_ids": ["implement", "review"],
|
||||
"context_updates": { "tests_passed": true }
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Effect |
|
||||
|---|---|
|
||||
| `preferred_next_label` | Matched against edge labels (same as human gate selection) |
|
||||
| `suggested_next_ids` | Ordered list of preferred target node IDs |
|
||||
| `context_updates` | Key-value pairs merged into the run context for downstream conditions |
|
||||
|
||||
Arc automatically scans LLM output for these JSON objects — no special configuration is needed. However, you do need to instruct the LLM to emit the JSON in your prompt. For example:
|
||||
|
||||
```dot
|
||||
review [
|
||||
label="Review",
|
||||
shape=tab,
|
||||
prompt="Review the implementation for correctness and \
|
||||
code quality. If changes are needed, respond with: \
|
||||
{\"preferred_next_label\": \"fix\"}. If everything \
|
||||
looks good, respond with: \
|
||||
{\"preferred_next_label\": \"approve\"}."
|
||||
]
|
||||
|
||||
review -> fix [label="Fix"]
|
||||
review -> approve [label="Approve"]
|
||||
```
|
||||
|
||||
The LLM's natural language response can contain other text — Arc finds the last JSON object with a recognized routing field and extracts the directives from it.
|
||||
|
||||
## Human gate transitions
|
||||
|
||||
Human gates use edge labels to present options to the user. The selected label becomes the `preferred_label` in the outcome, and Arc matches it to the corresponding edge:
|
||||
|
||||
```dot
|
||||
approve [shape=hexagon, label="Approve Plan"]
|
||||
|
||||
approve -> implement [label="[A] Approve"]
|
||||
approve -> plan [label="[R] Revise"]
|
||||
approve -> skip [label="[S] Skip"]
|
||||
```
|
||||
|
||||
The `[A]`, `[R]`, `[S]` prefixes are keyboard accelerators — Arc strips them when matching, so the user can type just the letter.
|
||||
|
||||
## Unconditional edges
|
||||
|
||||
An edge without a `condition` attribute always matches. When a node has a single outgoing edge, it doesn't need a condition:
|
||||
|
||||
```dot
|
||||
start -> plan -> implement -> exit
|
||||
```
|
||||
|
||||
When mixing conditional and unconditional edges, conditional matches take priority. An unconditional edge acts as the default fallback:
|
||||
|
||||
```dot
|
||||
gate -> fast_path [condition="outcome=success"]
|
||||
gate -> slow_path
|
||||
```
|
||||
|
||||
## Weight tiebreaking
|
||||
|
||||
When multiple edges match (e.g. two unconditional edges), `weight` determines the winner. Higher weight wins:
|
||||
|
||||
```dot
|
||||
node -> preferred [weight=10]
|
||||
node -> fallback [weight=1]
|
||||
```
|
||||
|
||||
If weights are equal, the edge with the lexicographically first target node ID is chosen. This makes the behavior fully deterministic.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue