diff --git a/docs/agents/outputs.mdx b/docs/agents/outputs.mdx index 2942524a8..f5b24f435 100644 --- a/docs/agents/outputs.mdx +++ b/docs/agents/outputs.mdx @@ -21,7 +21,7 @@ Every agent and prompt node sets three context keys from its response: These keys are available to downstream nodes via the [context](/execution/context). The `last_response` key provides a quick preview, while `response.{node_id}` preserves the complete output for nodes that need it. -```graphviz +```dot plan -> implement -> review -> exit // In the review node's prompt, you can reference prior outputs: @@ -64,7 +64,7 @@ JSON objects without recognized fields are ignored. If no routing directive is f Arc does not automatically instruct agents to emit routing JSON. You must include instructions in your prompt: -```graphviz +```dot review [ label="Review", shape=tab, diff --git a/docs/agents/prompts.mdx b/docs/agents/prompts.mdx index 734930b25..872c0747b 100644 --- a/docs/agents/prompts.mdx +++ b/docs/agents/prompts.mdx @@ -13,13 +13,13 @@ The `prompt` attribute on a node defines the task instructions for that stage. I Short prompts can be written directly in the DOT file: -```graphviz +```dot plan [label="Plan", prompt="Analyze the codebase and write a step-by-step plan."] ``` Use `\` for multi-line strings: -```graphviz +```dot review [ label="Review", shape=tab, @@ -35,7 +35,7 @@ review [ For longer prompts, use the `@` prefix to load from a Markdown file relative to the DOT file: -```graphviz +```dot plan [label="Plan Implementation", prompt="@prompts/implement/plan.md"] implement [label="Implement", prompt="@prompts/implement/implement.md"] review [label="Review", prompt="@prompts/implement/review.md"] @@ -47,7 +47,7 @@ The `@` prefix tells the engine to read the file contents and use them as the pr Prompts support `$variable` placeholders that expand at runtime. Currently the only built-in variable is `$goal`, which resolves to the graph-level `goal` attribute: -```graphviz title="pipeline.dot" +```dot title="pipeline.dot" digraph Pipeline { graph [goal="Add a /health endpoint to the API server"] @@ -67,7 +67,7 @@ A `$` not followed by an identifier character (e.g. `$5`) is left as-is. An unde If a node has neither a `prompt` attribute nor an empty one, Arc uses the `label` as the prompt: -```graphviz +```dot // "Do work" is both the display label and the prompt work [label="Do work"] ``` diff --git a/docs/changelog/2026-02-27.mdx b/docs/changelog/2026-02-27.mdx index fbed943eb..2414bffc9 100644 --- a/docs/changelog/2026-02-27.mdx +++ b/docs/changelog/2026-02-27.mdx @@ -15,7 +15,7 @@ Two new built-in tools bring real-time information into workflow decisions. `web Individual workflow nodes can now delegate work to external AI coding assistants. Set the backend to `claude-code`, `codex`, or `gemini-cli` and the node will use that CLI tool instead of the built-in agent loop. -```graphviz +```dot implement [handler=codergen, cli_backend=codex] review [handler=codergen, cli_backend=claude-code] ``` diff --git a/docs/changelog/2026-03-05.mdx b/docs/changelog/2026-03-05.mdx index 42ff717f1..864726ae4 100644 --- a/docs/changelog/2026-03-05.mdx +++ b/docs/changelog/2026-03-05.mdx @@ -27,7 +27,7 @@ Transition conditions in DOT workflows now support `||` (or), `!` (not), numeric Previously, conditions were limited to `&&`-joined equality checks. Now you can write expressive guards like: -```graphviz +```dot stage_a -> stage_b [condition="score > 80 || result contains 'approved'"]; ``` @@ -98,7 +98,7 @@ verbose = true Handler types have been renamed for clarity: `agent_loop` is now `agent`, and `one_shot` is now `prompt`. The old names still work as aliases, so existing workflows won't break. -```graphviz +```dot stage_a [type="agent"]; stage_b [type="prompt"]; ``` diff --git a/docs/core-concepts/agents.mdx b/docs/core-concepts/agents.mdx index 0aebca67d..c3148f33c 100644 --- a/docs/core-concepts/agents.mdx +++ b/docs/core-concepts/agents.mdx @@ -43,7 +43,7 @@ The CLI is selected automatically based on the node's provider: Set the CLI backend on a node with `backend="cli"` or via a [model stylesheet](/workflows/stylesheets): -```graphviz +```dot implement [label="Implement", backend="cli", llm_provider="anthropic"] ``` @@ -91,7 +91,7 @@ See [Tools](/agents/tools) for the full reference. The agent's behavior is shaped by its prompt — the task instructions set in the `prompt` attribute of the workflow node. Prompts can be inline strings or references to external Markdown files: -```graphviz +```dot // Inline prompt plan [label="Plan", prompt="Analyze the codebase and write a step-by-step plan."] diff --git a/docs/core-concepts/models.mdx b/docs/core-concepts/models.mdx index 96056995d..41641e7a1 100644 --- a/docs/core-concepts/models.mdx +++ b/docs/core-concepts/models.mdx @@ -48,7 +48,7 @@ When no model is specified, the `arc agent` command uses a default model based o Assign models to workflow nodes using [model stylesheets](/workflows/stylesheets), which use a CSS-like syntax: -```graphviz title="example.dot" +```dot title="example.dot" digraph Example { graph [ model_stylesheet=" diff --git a/docs/core-concepts/workflows.mdx b/docs/core-concepts/workflows.mdx index badb8feef..f105f47d4 100644 --- a/docs/core-concepts/workflows.mdx +++ b/docs/core-concepts/workflows.mdx @@ -13,7 +13,7 @@ Every workflow is a `digraph` with a `goal`, a `start` node, an `exit` node, and Simple workflow: Start → Scan Files → Analyze → Exit -```graphviz title="my-workflow.dot" +```dot title="my-workflow.dot" digraph MyWorkflow { graph [goal="Describe the project"] rankdir=LR @@ -36,19 +36,19 @@ Each node's Graphviz **shape** determines how it executes. The three most import **Agents** (default `box` shape) run an LLM with access to tools — bash, file editing, sub-agents — looping autonomously until the task is complete: -```graphviz +```dot implement [label="Implement", prompt="Read plan.md and implement every step."] ``` **Commands** (`parallelogram`) run shell scripts and capture output for downstream nodes: -```graphviz +```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: -```graphviz +```dot approve [shape=hexagon, label="Approve Plan"] approve -> implement [label="[A] Approve"] @@ -65,7 +65,7 @@ Arc supports additional node types for one-shot prompts, conditional branching, Edges can have **conditions** that route execution based on outcomes: -```graphviz +```dot gate [shape=diamond, label="Tests passing?"] gate -> exit [label="Pass", condition="outcome=success"] @@ -74,7 +74,7 @@ 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: -```graphviz +```dot fix [label="Fix Failures", prompt="Fix the failing tests.", max_visits=3] ``` @@ -86,7 +86,7 @@ fix [label="Fix Failures", prompt="Fix the failing tests.", max_visits=3] Fan out to run branches concurrently, then merge the results: -```graphviz +```dot fork [label="Fan Out", shape=component] merge [label="Merge", shape=tripleoctagon] @@ -103,7 +103,7 @@ merge -> report -> exit Mark critical nodes with `goal_gate=true`. The workflow fails if any goal gate doesn't succeed — even if execution reaches the exit node: -```graphviz +```dot validate [label="Validate", prompt="Run the test suite and verify all tests pass.", goal_gate=true] ``` diff --git a/docs/docs.json b/docs/docs.json index 310618f9b..4a5bca544 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -286,6 +286,13 @@ "vscode" ] }, + "styling": { + "codeblocks": { + "languages": { + "custom": ["/languages/dot.json"] + } + } + }, "footer": { "socials": { "x": "https://x.com/mintlify", diff --git a/docs/execution/context.mdx b/docs/execution/context.mdx index 45c5c3a6d..62882adda 100644 --- a/docs/execution/context.mdx +++ b/docs/execution/context.mdx @@ -80,7 +80,7 @@ The engine sets several keys automatically. These are prefixed with `internal.` Edge [conditions](/workflows/transitions#conditions) can read context values to route execution: -```graphviz +```dot gate -> deploy [condition="outcome=success && context.tests_passed=true"] gate -> fix [condition="outcome=fail"] ``` @@ -105,17 +105,17 @@ When a new agent or prompt node starts, Arc assembles a **preamble** — a summa Fidelity can be set at three levels. The first match wins: 1. **Edge attribute** — Set `fidelity` on an edge to control the transition into a specific node: - ```graphviz + ```dot plan -> implement [fidelity="full"] ``` 2. **Node attribute** — Set `fidelity` on a node to control all transitions into it: - ```graphviz + ```dot implement [fidelity="full"] ``` 3. **Graph default** — Set `default_fidelity` on the graph for a run-wide default: - ```graphviz + ```dot digraph Example { graph [default_fidelity="summary:medium"] } @@ -127,7 +127,7 @@ If none of these are set, fidelity defaults to `compact`. `full` fidelity is typically used with `thread_id` to create a shared conversation across multiple nodes. Nodes with the same `thread_id` share a single LLM session, preserving full context continuity: -```graphviz +```dot subgraph cluster_impl { node [fidelity="full", thread_id="impl"] plan [label="Plan"] diff --git a/docs/execution/failures.mdx b/docs/execution/failures.mdx index ab24d2acb..f0d790b3e 100644 --- a/docs/execution/failures.mdx +++ b/docs/execution/failures.mdx @@ -20,7 +20,7 @@ When a node fails, Arc classifies the failure into one of six categories. These Classification happens automatically. Arc inspects SDK error types, HTTP status codes, and error message patterns to assign the right class. The `failure_class` is written to [context](/execution/context) after each stage, so you can route on it in edge conditions: -```graphviz +```dot implement -> fix [condition="failure_class=transient_infra"] implement -> escalate [condition="failure_class=deterministic"] ``` @@ -53,7 +53,7 @@ When a node handler fails (after LLM retries are exhausted), the engine can retr Set a retry policy on a node with the `retry_policy` attribute: -```graphviz +```dot implement [retry_policy="standard"] ``` @@ -71,7 +71,7 @@ All policies apply random jitter (0.5x–1.5x) and cap individual delays at 60 s You can also set just the retry count using `max_retries`: -```graphviz +```dot implement [max_retries="5"] ``` @@ -132,7 +132,7 @@ Arc has two independent mechanisms for detecting stuck loops: **node visit limit The `max_node_visits` graph attribute sets the maximum number of times any single node can execute before the run is terminated: -```graphviz title="example.dot" +```dot title="example.dot" digraph Example { graph [max_node_visits="20"] // ... @@ -203,7 +203,7 @@ Loop restart edges also have their own separate circuit breaker (`restart_failur Goal gates are quality checkpoints that are enforced when the workflow reaches an exit node. A node marked with `goal_gate=true` must have completed with `success` or `partial_success` — otherwise the run cannot finish. -```graphviz +```dot verify [shape=box, goal_gate="true"] ``` @@ -214,7 +214,7 @@ When a goal gate is unsatisfied at the exit node, Arc looks for a **retry target 3. Graph-level `retry_target` attribute 4. Graph-level `fallback_retry_target` attribute -```graphviz title="example.dot" +```dot title="example.dot" digraph Example { graph [retry_target="plan"] verify [shape=box, goal_gate="true", retry_target="implement"] @@ -238,7 +238,7 @@ Arc runs a background watchdog that monitors event activity. If no events are em | `stall_timeout` | 600 seconds (10 minutes) | | Set to `0` | Disables the watchdog | -```graphviz title="example.dot" +```dot title="example.dot" digraph Example { graph [stall_timeout="300"] // 5 minutes } diff --git a/docs/execution/interviews.mdx b/docs/execution/interviews.mdx index 9b537e9b7..f81f6e3b4 100644 --- a/docs/execution/interviews.mdx +++ b/docs/execution/interviews.mdx @@ -110,7 +110,7 @@ Questions can have a `timeout_seconds` field. When set, Arc wraps the interviewe The human handler then checks the node's `human.default_choice` attribute. If set, execution continues to the default target. Otherwise, the stage retries. -```graphviz +```dot approve [shape=hexagon, label="Approve?", human.default_choice="deploy"] ``` diff --git a/docs/execution/run-configuration.mdx b/docs/execution/run-configuration.mdx index 0745ba2dc..5733dbc18 100644 --- a/docs/execution/run-configuration.mdx +++ b/docs/execution/run-configuration.mdx @@ -181,7 +181,7 @@ language = "rust" Variables can be used anywhere in the DOT file with `$name` syntax: -```graphviz title="c-i.dot" +```dot title="c-i.dot" digraph CI { graph [goal="Run tests for $repo_name"] clone [shape=parallelogram, script="git clone $repo_url repo"] diff --git a/docs/getting-started/why-arc.mdx b/docs/getting-started/why-arc.mdx index 51b005acb..166e78015 100644 --- a/docs/getting-started/why-arc.mdx +++ b/docs/getting-started/why-arc.mdx @@ -48,7 +48,7 @@ Workflows are defined in Graphviz DOT, a simple graph description language. Here Plan-Implement workflow graph -```graphviz title="plan-implement.dot" +```dot title="plan-implement.dot" digraph PlanImplement { graph [goal="Plan, approve, implement, and simplify a change"] diff --git a/docs/languages/dot.json b/docs/languages/dot.json new file mode 100644 index 000000000..18d9081c4 --- /dev/null +++ b/docs/languages/dot.json @@ -0,0 +1,100 @@ +{ + "name": "dot", + "scopeName": "source.dot", + "fileTypes": ["dot", "DOT", "gv"], + "firstLineMatch": "digraph.*", + "patterns": [ + { + "match": " ?(digraph)[ \\t]+([A-Za-z0-9]+) ?(\\{)", + "captures": { + "1": { "name": "storage.type.dot" }, + "2": { "name": "variable.other.dot" }, + "3": { "name": "punctuation.section.dot" } + } + }, + { + "match": "(<|-)(>|-)", + "name": "keyword.operator.dot" + }, + { + "match": "\\b(node|edge|graph|digraph|subgraph|strict)\\b", + "name": "storage.type.dot" + }, + { + "match": "\\b(bottomlabel|color|comment|distortion|fillcolor|fixedsize|fontcolor|fontname|fontsize|group|height|label|layer|orientation|peripheries|regular|shape|shapefile|sides|skew|style|toplabel|URL|width|z)\\b", + "name": "support.constant.attribute.node.dot" + }, + { + "match": "\\b(arrowhead|arrowsize|arrowtail|color|comment|constraint|decorate|dir|fontcolor|fontname|fontsize|headlabel|headport|headURL|label|labelangle|labeldistance|labelfloat|labelcolor|labelfontname|labelfontsize|layer|lhead|ltail|minlen|samehead|sametail|splines|style|taillabel|tailport|tailURL|weight)\\b", + "name": "support.constant.attribute.edge.dot" + }, + { + "match": "\\b(bgcolor|center|clusterrank|color|comment|compound|concentrate|fillcolor|fontname|fontpath|fontsize|label|labeljust|labelloc|layers|margin|mclimit|nodesep|nslimit|nslimit1|ordering|orientation|page|pagedir|quantum|rank|rankdir|ranksep|ratio|remincross|rotate|samplepoints|searchsize|size|style|URL)\\b", + "name": "support.constant.attribute.graph.dot" + }, + { + "match": "\\b(box|polygon|ellipse|circle|point|egg|triangle|plaintext|diamond|trapezium|parallelogram|house|pentagon|hexagon|septagon|octagon|doublecircle|doubleoctagon|tripleoctagon|invtriangle|invtrapezium|invhouse|Mdiamond|Msquare|Mcircle|rect|rectangle|none|note|tab|folder|box3d|component|max|min|same)\\b", + "name": "variable.other.dot" + }, + { + "begin": "\"", + "beginCaptures": { + "0": { "name": "punctuation.definition.string.begin.dot" } + }, + "end": "\"", + "endCaptures": { + "0": { "name": "punctuation.definition.string.end.dot" } + }, + "name": "string.quoted.double.dot", + "patterns": [ + { + "match": "\\\\.", + "name": "constant.character.escape.dot" + } + ] + }, + { + "begin": "(^[ \\t]+)?(?=//)", + "beginCaptures": { + "1": { "name": "punctuation.whitespace.comment.leading.dot" } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "//", + "beginCaptures": { + "0": { "name": "punctuation.definition.comment.dot" } + }, + "end": "\\n", + "name": "comment.line.double-slash.dot" + } + ] + }, + { + "begin": "(^[ \\t]+)?(?=#)", + "beginCaptures": { + "1": { "name": "punctuation.whitespace.comment.leading.dot" } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "#", + "beginCaptures": { + "0": { "name": "punctuation.definition.comment.dot" } + }, + "end": "\\n", + "name": "comment.line.number-sign.dot" + } + ] + }, + { + "begin": "/\\*", + "captures": { + "0": { "name": "punctuation.definition.comment.dot" } + }, + "end": "\\*/", + "name": "comment.block.dot" + } + ], + "repository": {} +} diff --git a/docs/reference/dot-language.mdx b/docs/reference/dot-language.mdx index 1131c4e91..dccfbd6f6 100644 --- a/docs/reference/dot-language.mdx +++ b/docs/reference/dot-language.mdx @@ -9,7 +9,7 @@ Arc workflows are written in a subset of the [Graphviz DOT language](https://gra Every workflow is a `digraph` (directed graph) with a name and a body of statements: -```graphviz title="my-workflow.dot" +```dot title="my-workflow.dot" digraph MyWorkflow { graph [goal="Describe the project"] rankdir=LR @@ -28,7 +28,7 @@ Only `digraph` is supported — `graph` (undirected) and `strict` are not. The g ## Comments -```graphviz +```dot // Line comment — everything to end of line /* Block comment @@ -63,7 +63,7 @@ The body of a digraph can contain these statement types: Set workflow-level configuration: -```graphviz +```dot // Block syntax graph [goal="Build a feature", model_stylesheet="* { llm_model: claude-haiku-4-5; }"] @@ -88,7 +88,7 @@ rankdir=LR Apply default attributes to all subsequently declared nodes: -```graphviz +```dot node [shape=box, timeout="900s"] ``` @@ -98,7 +98,7 @@ Defaults are scoped to their enclosing subgraph. Explicit attributes on individu Apply default attributes to all subsequently declared edges: -```graphviz +```dot edge [weight=5] ``` @@ -106,7 +106,7 @@ edge [weight=5] Declare a node with optional attributes: -```graphviz +```dot plan [label="Plan", prompt="Create an implementation plan."] ``` @@ -118,7 +118,7 @@ Nodes referenced in edges are auto-created if not explicitly declared. Connect nodes with directed edges: -```graphviz +```dot start -> plan -> implement -> exit ``` @@ -126,7 +126,7 @@ Chained edges like `A -> B -> C` expand to individual edges `A -> B` and `B -> C Edges can have attributes: -```graphviz +```dot gate -> exit [label="Pass", condition="outcome=success"] gate -> implement [label="Fix"] ``` @@ -135,7 +135,7 @@ gate -> implement [label="Fix"] Group nodes visually and apply scoped defaults: -```graphviz +```dot subgraph cluster_impl { label = "Implementation" node [thread_id="impl", fidelity="full"] @@ -280,7 +280,7 @@ A bare key with no operator is a **truthiness check** — it passes if the value ### Examples -```graphviz +```dot // Simple outcome check gate -> exit [condition="outcome=success"] @@ -310,7 +310,7 @@ gate -> slow_path Instead of inlining long prompts, reference an external file: -```graphviz +```dot simplify [label="Simplify", prompt="@docs-internal/prompts/simplify.md"] ``` @@ -334,7 +334,7 @@ Arc validates workflows at parse time and reports diagnostics. Key rules: ## Complete example -```graphviz title="implement-feature.dot" +```dot title="implement-feature.dot" digraph ImplementFeature { graph [ goal="Implement a feature with tests and code review", diff --git a/docs/workflows/human-in-the-loop.mdx b/docs/workflows/human-in-the-loop.mdx index c34202a46..4f9df92db 100644 --- a/docs/workflows/human-in-the-loop.mdx +++ b/docs/workflows/human-in-the-loop.mdx @@ -9,7 +9,7 @@ Not every decision should be made by an LLM. Arc provides several mechanisms for A human gate is a node with shape `hexagon` that pauses the workflow and presents the user with a choice. The options are derived from the outgoing edge labels: -```graphviz +```dot approve [shape=hexagon, label="Approve Plan"] approve -> implement [label="[A] Approve"] @@ -35,7 +35,7 @@ When matching the user's selection to an edge, Arc strips the accelerator prefix In addition to fixed choices, a human gate can accept freeform text input. Add an edge with `freeform=true`: -```graphviz +```dot review [shape=hexagon, label="Review Changes"] review -> implement [label="[A] Approve"] @@ -49,7 +49,7 @@ If the user types something that doesn't match any fixed option, their input rou If a human gate has a timeout configured, you can specify a default choice using the `human.default_choice` attribute: -```graphviz +```dot approve [shape=hexagon, label="Approve?", human.default_choice="approve"] ``` diff --git a/docs/workflows/stages-and-nodes.mdx b/docs/workflows/stages-and-nodes.mdx index fdcc4f3a3..135fe7598 100644 --- a/docs/workflows/stages-and-nodes.mdx +++ b/docs/workflows/stages-and-nodes.mdx @@ -19,7 +19,7 @@ Every node's Graphviz `shape` attribute determines its execution behavior. If no The entry point of the workflow. Every workflow must have exactly one start node. -```graphviz +```dot start [shape=Mdiamond, label="Start"] ``` @@ -29,7 +29,7 @@ start [shape=Mdiamond, label="Start"] The terminal node. When execution reaches exit, the workflow completes. Every workflow must have exactly one exit node. -```graphviz +```dot exit [shape=Msquare, label="Exit"] ``` @@ -39,7 +39,7 @@ exit [shape=Msquare, label="Exit"] 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. -```graphviz +```dot implement [label="Implement", prompt="Read plan.md and implement every step."] ``` @@ -71,7 +71,7 @@ Fidelity can also be set at the graph level (`default_fidelity`) or on individua 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: -```graphviz +```dot subgraph cluster_impl { node [fidelity="full", thread_id="impl"] plan [label="Plan"] @@ -86,7 +86,7 @@ subgraph cluster_impl { Makes a single LLM call with no tool use. Useful for analysis, summarization, generation, and lightweight reasoning where tools aren't needed. -```graphviz +```dot spec [label="Write Spec", shape=tab, prompt="Write a brief spec for a string utility module."] ``` @@ -98,7 +98,7 @@ Prompt nodes accept the same attributes as agent nodes (`prompt`, `reasoning_eff Runs a shell script and captures its output. The output is available to downstream nodes as context. -```graphviz +```dot test [label="Run Tests", shape=parallelogram, script="cargo test 2>&1 || true"] ``` @@ -113,7 +113,7 @@ test [label="Run Tests", shape=parallelogram, script="cargo test 2>&1 || true"] Pauses the workflow and waits for a person to choose a path. The outgoing edge labels define the available options: -```graphviz +```dot approve [shape=hexagon, label="Approve Plan"] approve -> implement [label="[A] Approve"] @@ -128,7 +128,7 @@ In the web UI, human gates appear as interactive prompts. From the CLI, they app Pauses the workflow for a configured duration before proceeding. Useful for rate limiting between API calls or waiting for external processes to complete. -```graphviz +```dot cooldown [label="Wait 30s", shape=insulator, duration="30s"] ``` @@ -142,7 +142,7 @@ cooldown [label="Wait 30s", shape=insulator, duration="30s"] Routes execution to different edges based on conditions evaluated against the current run context: -```graphviz +```dot gate [shape=diamond, label="Tests passing?"] gate -> exit [label="Pass", condition="outcome=success"] @@ -157,7 +157,7 @@ Conditions support `=`, `!=`, `&&`, and context variable lookups (e.g. `context. Fans out to execute multiple branches concurrently. Each branch gets its own isolated context. -```graphviz +```dot fork [label="Fan Out", shape=component, join_policy="wait_all", error_policy="continue"] fork -> security @@ -194,7 +194,7 @@ fork -> quality Collects results from parallel branches into a single context. Typically paired with a parallel fan-out node: -```graphviz +```dot merge [label="Merge Results", shape=tripleoctagon] security -> merge diff --git a/docs/workflows/stylesheets.mdx b/docs/workflows/stylesheets.mdx index 7da1f32c3..0d65f8212 100644 --- a/docs/workflows/stylesheets.mdx +++ b/docs/workflows/stylesheets.mdx @@ -9,7 +9,7 @@ Model stylesheets let you assign LLM models, providers, and settings to workflow Stylesheets are set in the `model_stylesheet` graph attribute: -```graphviz title="example.dot" +```dot title="example.dot" digraph Example { graph [ goal="Build and review a utility function", @@ -52,7 +52,7 @@ Each rule starts with a selector that determines which nodes it applies to: Set the `class` attribute on a node to target it with class selectors. Multiple classes are space-separated: -```graphviz +```dot implement [label="Implement", class="coding critical"] ``` @@ -95,7 +95,7 @@ If two rules have the same specificity, the **last one** in the stylesheet wins. A model set directly on a node attribute always takes precedence over stylesheets, regardless of specificity: -```graphviz +```dot implement [label="Implement", class="coding", llm_model="claude-opus-4-6"] ``` diff --git a/docs/workflows/transitions.mdx b/docs/workflows/transitions.mdx index d0cda404e..642a5d7c3 100644 --- a/docs/workflows/transitions.mdx +++ b/docs/workflows/transitions.mdx @@ -28,7 +28,7 @@ If no edge matches at all, the workflow halts with an error. Edge conditions are boolean expressions evaluated against the stage outcome and run context. Conditions go in the `condition` attribute on an edge: -```graphviz +```dot gate -> exit [label="Pass", condition="outcome=success"] gate -> implement [label="Fix", condition="outcome=fail"] ``` @@ -57,7 +57,7 @@ gate -> implement [label="Fix", condition="outcome=fail"] A bare key with no operator is a **truthiness check** — it passes if the value is non-empty, not `"false"`, and not `"0"`: -```graphviz +```dot gate -> next [condition="my_flag"] ``` @@ -65,7 +65,7 @@ gate -> next [condition="my_flag"] Use `&&` (AND), `||` (OR), and `!` (NOT) to build compound expressions. `&&` binds tighter than `||`: -```graphviz +```dot // Both must be true gate -> deploy [condition="outcome=success && context.tests_passed=true"] @@ -99,7 +99,7 @@ Agent and prompt nodes can influence which edge is taken by including a JSON obj 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: -```graphviz +```dot review [ label="Review", shape=tab, @@ -120,7 +120,7 @@ The LLM's natural language response can contain other text — Arc finds the las 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: -```graphviz +```dot approve [shape=hexagon, label="Approve Plan"] approve -> implement [label="[A] Approve"] @@ -134,13 +134,13 @@ The `[A]`, `[R]`, `[S]` prefixes are keyboard accelerators — Arc strips them w An edge without a `condition` attribute always matches. When a node has a single outgoing edge, it doesn't need a condition: -```graphviz +```dot start -> plan -> implement -> exit ``` When mixing conditional and unconditional edges, conditional matches take priority. An unconditional edge acts as the default fallback: -```graphviz +```dot gate -> fast_path [condition="outcome=success"] gate -> slow_path ``` @@ -149,7 +149,7 @@ gate -> slow_path When multiple edges match (e.g. two unconditional edges), `weight` determines the winner. Higher weight wins: -```graphviz +```dot node -> preferred [weight=10] node -> fallback [weight=1] ``` diff --git a/docs/workflows/variables.mdx b/docs/workflows/variables.mdx index 80757e463..cf5a2a020 100644 --- a/docs/workflows/variables.mdx +++ b/docs/workflows/variables.mdx @@ -22,7 +22,7 @@ language = "rust" These variables are expanded into the DOT source **before** the graph is parsed. You can use `$variable` anywhere in the DOT file — goals, prompts, labels, scripts, or any other attribute: -```graphviz title="check.dot" +```dot title="check.dot" digraph Check { graph [goal="Run tests for $repo_name"] @@ -48,7 +48,7 @@ A bare `$` not followed by an identifier character (e.g. `costs $5`) is left as- Inside agent and prompt node prompts, Arc automatically expands `$goal` to the workflow's `goal` attribute. This happens at runtime, after graph parsing: -```graphviz title="example.dot" +```dot title="example.dot" digraph Example { graph [goal="Implement the login feature"]