---
title: "Two Months of Dippin: Edges Own Everything Now"
description: "Eight Dippin releases in two months: dip 2 makes edges own all routing, else -\u003e collapses fallback boilerplate, prompt cascades stop drift, and the toolchain got stricter everywhere it spends your …"
canonical_url: "https://2389.ai/research/writing/dippin-edges-own-everything/"
last_updated: "2026-09-03T10:32:15-05:00"
doc_version: "1.0"
author: "Clint Ecker"
date: 2026-09-03
tags: ["dippin-lang", "dsl", "pipeline", "agents", "multi-agent"]
---

# Two Months of Dippin: Edges Own Everything Now

> Eight Dippin releases in two months: dip 2 makes edges own all routing, else -> collapses fallback boilerplate, prompt cascades stop drift, and the toolchain got stricter everywhere it spends your money.


Quick refresher if you missed the [original announcement](https://2389.ai/research/products/dippin-lang/): Dippin is our [domain-specific language](https://martinfowler.com/bliki/DomainSpecificLanguage.html) (DSL) for writing AI pipeline workflows. It replaced [Graphviz DOT](https://graphviz.org/doc/info/lang.html) for us. A multi-agent pipeline is a graph, but its nodes are programs, and DOT makes you cram prompts and shell scripts into escaped string attributes. Dippin gives those things real syntax, plus a validator with a diagnostic catalog, a formatter, a [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) (LSP) server, and a simulator.

In the two months since, we've shipped eight releases, v0.43 through v0.50, most of them chasing one big project we've been calling the routing cleanup. The language got smaller in the ways that matter and stricter in the ways that matter more.

## dip 2: all routing lives in one place

The headline is **`dip 2`**, an opt-in version header with a single organizing principle: edges own destinations. All of them.

Dippin v1 inherited a couple of node-level routing knobs (`retry_target:` and `fallback_target:`) that let a node declare where it goes on failure, as a field on the node. Convenient, but not great: it meant a graph's structure lived in two places, and reading the `edges` block didn't tell you where control could flow. Under `dip 2`, those fields are rejected. A failure destination is an `on fail` edge, a retry is a `loop` edge, and the edges block is the complete truth about the graph.

Nobody has to rewrite anything by hand. `dippin fmt --migrate` converts v1 files for you. It's conservative: when it can translate a case one-to-one, it does. When it can't, it leaves the original untouched, flags it with an inline `# MIGRATION:` comment, and exits with a distinct code[^exit], so your continuous-integration (CI) checks know a human needs to look.

The same principle killed another duplication. A `parallel Fan -> A, B` node declares its fan-out inline, but workflows were routinely re-declaring those same edges in the edges block and keeping the two in sync by hand. We audited every part of the toolchain that used that information, confirmed the inline list was already the source of truth, and made it official: the formatter now strips the redundant copies, a new lint flags them, and `dip 2` rejects them outright. Our own example workflows lost 216 redundant edge declarations in one sweep.

## Every fallback is now one line

Real workflows have a shape: a dozen or so nodes, each with a couple of guarded edges, and every one of them needing a fallback edge you add yourself (pointing to the same cleanup node) for when none of the guards match. Those repeated fallbacks added more lines to our production pipelines than anything else.

It's one line now:

```dippin
  edges
    Analyze -> Fix when ctx.outcome == "fail"
    Analyze -> Ship when ctx.outcome == "success"
    else -> Cleanup
```

A section-level `else ->` is the graph's default destination for any node whose guards all miss. The validator treats it as reachable, the linter stands down on nodes it covers, and the simulator routes through it exactly like the engine does. Deliberately, it's success-side only. A node *failure* still routes through the failure cascade, because "no guard matched" and "the tool crashed" are different events, and blurring the two is how failures slip through unnoticed.

## Prompts stopped drifting

The other big cleanup targeted duplication of a different kind. We found the same control-protocol boilerplate, the "your final line MUST be exactly STATUS: ..." contract, hand-pasted **65 times across 11 files** in one of our pipeline repos, each copy drifting a little.

Now the `defaults` block takes a **prompt cascade**: declare `prompt_prefix` / `prompt_suffix` once, inline or loaded from a shared fragment file, and it applies to every agent in the workflow (with the suffix guaranteed to be the final content) so last-line contracts hold. Individual agents can opt-out or append their own fragment. Fragment files get the same security envelope as everything else Dippin loads.[^env]

Related: `dippin pack --no-inline` can now ship a workflow's sibling assets (helper scripts, shared fragments) inside the `.dipx` bundle[^dipx] as real files, so a packed run resolves relative paths byte-for-byte identically to a source-tree run.

## And the trust work

The least glamorous release might be the most important one. Double-quoted edge conditions with escaped characters inside them were being quietly corrupted during parsing: `when ctx.msg = "hello \"world\""` could get mangled into something that failed validation, or worse, meant something else. v0.49 made the quoted path escape-aware end to end, and made the lexer *reject* an unterminated string at its opening quote instead of helpfully fabricating a closing one.

That's the pattern across all eight releases. The diagnostic catalog grew from 61 to 64 codes, and every new one is conservative by design: documented to have no false positives, with a test suite guard proving our own examples stay clean. The migration tool exits loud when it's unsure. The pack command refuses rather than guessing. For a language whose programs spend real money when they run, we think boring strictness is the feature.

Everything above is in `dippin` v0.50: `brew install 2389-research/tap/dippin-lang`, or `go install github.com/2389-research/dippin-lang/cmd/dippin@latest`. The [full changelog](https://github.com/2389-research/dippin-lang/blob/main/CHANGELOG.md) has the details, at our customary excessive length.

[^exit]: Exit `3` (`ExitMigrateReview`), distinct from the exit `1` you get for ordinary formatting drift, so a completed-migration check can tell the two apart.
[^env]: The same checks every file load gets: path containment (the file has to stay inside the project directory), rejection of symlinks, and a size cap.
[^dipx]: A `.dipx` is a single, content-addressed bundle of a workflow plus everything it references: the deployable artifact you ship, verified by hash, instead of a loose directory of `.dip` files.


## Sitemap

Parent: [Writing](https://2389.ai/research/writing/index.md)

Related pages in this section:

- [MermaidKit: We Got Tired of Shipping a Browser to Draw a Flowchart](https://2389.ai/research/writing/mermaidkit/index.md)
- [Postique: AI Marketing Employee](https://2389.ai/research/writing/postique/index.md)
- [The team you lose when you open Claude Code](https://2389.ai/research/writing/review-squad/index.md)
- [Horton Hears a Whisper](https://2389.ai/research/writing/horton-hears-a-whisper/index.md)
- [Why We Built a Language for AI Pipelines](https://2389.ai/research/writing/why-we-built-a-language-for-ai-pipelines/index.md)
- [Word Compiler, A Context Compiler for Long-Form Fiction](https://2389.ai/research/writing/word-compiler/index.md)
- [We Turned a 3D Printer Into an AI Portrait Artist](https://2389.ai/research/writing/we-turned-a-3d-printer-into-an-ai-portrait-artist/index.md)
- [Simmer: A Self Honing Skill](https://2389.ai/research/writing/simmer-skill/index.md)
- [Cookoff: Same Spec, Different Code](https://2389.ai/research/writing/cookoff-same-spec-different-code/index.md)
- [Omakase: Show Me](https://2389.ai/research/writing/omakase-show-me/index.md)


Site index: [llms.txt](https://2389.ai/llms.txt) · [sitemap.md](https://2389.ai/sitemap.md) · [HTML](https://2389.ai/research/writing/dippin-edges-own-everything/)
