Dippin is a domain-specific language for authoring AI pipeline workflows. It replaces Graphviz DOT as the format for defining multi-step LLM pipelines, with first-class support for multi-line prompts, conditional routing, parallel execution, and a full validation toolchain. You'll go from zero to a validated, linted, and visualized workflow in under 10 minutes.
Dippin is a single Go binary. Install it with go install:
$ go install github.com/2389-research/dippin-lang/cmd/dippin@latest
Or via Homebrew (macOS and Linux):
$ brew install 2389-research/tap/dippin
Verify it works:
$ dippin --version dippin v0.10.0
One binary, everything included: parser, validator, linter, formatter, simulator, cost estimator, LSP server, and DOT exporter. No plugins or runtime dependencies.
Create a file called pipeline.dip. A Dippin workflow has four parts:
a header with metadata, optional defaults, node definitions, and edges connecting them.
workflow MyFirstPipeline goal: "Summarize a document and then translate the summary to Spanish" start: Start exit: Exit defaults provider: anthropic model: claude-sonnet-4-6 agent Start label: Start agent Exit label: Exit agent Summarize label: "Summarize Document" prompt: Read the provided document carefully. Produce a concise summary that captures the key points, main arguments, and conclusions. Keep the summary under 200 words. agent Translate label: "Translate to Spanish" prompt: Translate the summary from the previous step into Spanish. Preserve the meaning and tone. Use formal register. edges Start -> Summarize Summarize -> Translate Translate -> Exit
A few things to notice. Prompts are multi-line blocks introduced by prompt:
with indented content below -- no quoting, no escaping, no \n sequences.
That's the main reason Dippin exists.1 Node types (agent,
tool, human) declare what kind of step each node is.
And edges live in a dedicated edges block at the bottom, separate from
the node definitions. You can try this yourself in the
playground.
Run dippin validate to check structural correctness:
$ dippin validate pipeline.dip PASS pipeline.dip
Validation catches structural errors: missing start/exit nodes, references to undefined nodes in edges, duplicate node names, unreachable nodes, and cycles. These are the DIP001-DIP009 error codes. If any fire, the file is invalid.
Try breaking it -- rename Exit to Done in the header
but not in the node list:
$ dippin validate pipeline.dip FAIL pipeline.dip DIP002: exit node "Done" is not defined
Validation checks structure. Linting checks semantics -- missing timeouts, unknown models, unreachable branches, and 22 other potential problems:
$ dippin lint pipeline.dip PASS pipeline.dip (0 errors, 0 warnings)
Clean. If you'd used a nonexistent model name, you'd see:
$ dippin lint pipeline.dip WARN pipeline.dip DIP108: node "Summarize": unknown model "claude-5-opus" for provider "anthropic"
34 diagnostic codes in total: 9 structural errors (DIP001-DIP009) and
25 semantic warnings (DIP101-DIP125). Run dippin explain DIP108
to see what any code means.
The formatter produces canonical output with deterministic field ordering. It's idempotent: formatting already-formatted code produces identical output.
$ dippin fmt pipeline.dip
Prints the formatted version to stdout. Use --write to format
in place, or --check to verify formatting without changing the file
(handy for CI):
$ dippin fmt --check pipeline.dip OK pipeline.dip
Export to Graphviz DOT format and render a diagram:
$ dippin export-dot pipeline.dip | dot -Tpng -o pipeline.png
For left-to-right layout (better for wide pipelines):
$ dippin export-dot --rankdir=LR pipeline.dip | dot -Tpng -o pipeline.png
Or view the topology right in your terminal:
$ dippin graph pipeline.dip ┌───────┐ ┌───────────┐ ┌───────────┐ ┌──────┐ │ Start │──▶│ Summarize │──▶│ Translate │──▶│ Exit │ └───────┘ └───────────┘ └───────────┘ └──────┘
Dippin supports three node kinds: agent (LLM call),
tool (shell command), and human (user input).
Here's a tool node that prepares the workspace:
tool SetupWorkspace label: "Setup Workspace" timeout: 30s command: set -eu mkdir -p .ai/output printf 'workspace-ready'
Tool nodes run shell commands directly. The timeout field matters --
without it, dippin lint emits a DIP111 warning.
The command: block works like prompt:: indent
your script and write any shell syntax you need. See the
language reference for the full field list.
Edges can carry conditions that control which path is taken at runtime:
edges Start -> SetupWorkspace SetupWorkspace -> Summarize when ctx.outcome = success SetupWorkspace -> Exit when ctx.outcome = fail Summarize -> Translate Translate -> Exit
The when keyword introduces a condition expression. Conditions
check context variables set at runtime. When a node's outgoing edges have
complementary conditions (like success/fail), Dippin
recognizes them as exhaustive and suppresses the DIP101 "unconditional fallback
missing" warning.2
dippin check runs validate + lint together and can output JSON for
programmatic consumption:
$ dippin check pipeline.dip PASS pipeline.dip valid=true errors=0 warnings=0
$ dippin --format json check pipeline.dip { "file": "pipeline.dip", "valid": true, "errors": 0, "warnings": 0, "diagnostics": [] }
The repository ships with real-world examples in the
examples/
directory. A few worth studying:
| File | What it demonstrates |
|---|---|
ask_and_execute.dip |
Human input, parallel implementation across 3 providers, cross-review |
code_quality_sweep.dip |
3-provider parallel analysis, fan-out/fan-in, goal gates, retry loops |
consensus_task.dip |
Multi-model consensus with postmortem and bounded restarts |
complexity_cleanup.dip |
Tool nodes with shell scripts, conditional routing, iterative refinement |
human_gate_showcase.dip |
Human choice and freeform gates with preferred_label for testing |
Validate them all at once:
$ for f in examples/*.dip; do dippin validate "$f"; done PASS examples/ask_and_execute.dip PASS examples/code_quality_sweep.dip PASS examples/complexity_cleanup.dip PASS examples/consensus_task.dip PASS examples/human_gate_showcase.dip ...
| Command | What it does |
|---|---|
dippin validate file.dip | Structural correctness (DIP001-DIP009) |
dippin lint file.dip | Semantic warnings (DIP101-DIP125) |
dippin check file.dip | Validate + lint combined |
dippin fmt file.dip | Canonical formatting to stdout |
dippin fmt --write file.dip | Format in place |
dippin export-dot file.dip | Convert to Graphviz DOT |
dippin graph file.dip | ASCII topology in terminal |
dippin test file.dip | Run scenario tests |
dippin cost file.dip | Estimate per-run cost |
dippin doctor file.dip | Health report with letter grade |
dippin lsp | Start LSP server for editor integration |
dippin explain DIPxxx | Explain a diagnostic code |
You've got a working toolchain and your first workflow. Pick whichever fits where you're headed:
\n for newlines and \" for inner quotes. For a 20-line system prompt, that's unreadable. Dippin's indentation-based blocks were the original motivation for building the language. See Migrating from DOT for a side-by-side comparison.contains/not-contains complementary pairs, not just success/fail. The implementation lives in validator/lint.go.