Getting Started with Dippin

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.

1 Install the Toolchain

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.

2 Write Your First Workflow

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.

3 Validate the Workflow

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

4 Lint for Best Practices

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.

5 Format for Consistency

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

6 Visualize with DOT Export

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 │
  └───────┘   └───────────┘   └───────────┘   └──────┘

7 Add a Tool Node

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.

8 Add Conditional Routing

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

9 Run the Full Check Suite

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": []
}

10 Explore the Examples

The repository ships with real-world examples in the examples/ directory. A few worth studying:

FileWhat 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
...

Quick Reference: Essential Commands

CommandWhat it does
dippin validate file.dipStructural correctness (DIP001-DIP009)
dippin lint file.dipSemantic warnings (DIP101-DIP125)
dippin check file.dipValidate + lint combined
dippin fmt file.dipCanonical formatting to stdout
dippin fmt --write file.dipFormat in place
dippin export-dot file.dipConvert to Graphviz DOT
dippin graph file.dipASCII topology in terminal
dippin test file.dipRun scenario tests
dippin cost file.dipEstimate per-run cost
dippin doctor file.dipHealth report with letter grade
dippin lspStart LSP server for editor integration
dippin explain DIPxxxExplain a diagnostic code

What's Next?

You've got a working toolchain and your first workflow. Pick whichever fits where you're headed:

Notes

  1. DOT requires prompts to be a single quoted string with \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.
  2. Exhaustive condition detection also handles contains/not-contains complementary pairs, not just success/fail. The implementation lives in validator/lint.go.