mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-10 03:30:59 +00:00
Add custom TextMate grammar for DOT syntax highlighting in docs
Revert the graphviz language identifier back to dot (Shiki doesn't bundle either) and register a custom TextMate grammar via Mintlify's styling.codeblocks.languages.custom config. The grammar (extracted from apps/arc-web/app/data/dot-grammar.ts) highlights keywords, shape names, attributes, strings, comments, and operators. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6a98dcc246
commit
4605f821e8
20 changed files with 182 additions and 75 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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"];
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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."]
|
||||
|
||||
|
|
|
|||
|
|
@ -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="
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ Every workflow is a `digraph` with a `goal`, a `start` node, an `exit` node, and
|
|||
<img src="/images/anatomy-workflow.svg" alt="Simple workflow: Start → Scan Files → Analyze → Exit" />
|
||||
</Frame>
|
||||
|
||||
```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]
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -286,6 +286,13 @@
|
|||
"vscode"
|
||||
]
|
||||
},
|
||||
"styling": {
|
||||
"codeblocks": {
|
||||
"languages": {
|
||||
"custom": ["/languages/dot.json"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"footer": {
|
||||
"socials": {
|
||||
"x": "https://x.com/mintlify",
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ Workflows are defined in Graphviz DOT, a simple graph description language. Here
|
|||
<img src="/images/plan-implement-workflow.svg" alt="Plan-Implement workflow graph" />
|
||||
</Frame>
|
||||
|
||||
```graphviz title="plan-implement.dot"
|
||||
```dot title="plan-implement.dot"
|
||||
digraph PlanImplement {
|
||||
graph [goal="Plan, approve, implement, and simplify a change"]
|
||||
|
||||
|
|
|
|||
100
docs/languages/dot.json
Normal file
100
docs/languages/dot.json
Normal file
|
|
@ -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": {}
|
||||
}
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue