Architecture
How the dippin toolchain is organized — packages, data flow, and design decisions.
Compiler Pipeline
Dippin is a multi-stage compiler pipeline. All downstream consumers program against the canonical IR — a set of Go structs defined in the ir package.
(.dip or .dot)
parserirFrom the canonical IR, multiple output stages fan out:
Package Map
dippin-lang/
├── ir/ # Canonical intermediate representation (types only)
│ ├── ir.go # Workflow, Node, NodeConfig, RetryConfig, NodeIO
│ ├── edge.go # Edge, Condition, ConditionExpr
│ ├── source.go # SourceLocation, SourceMap
│ └── lookup.go # Helper methods (Node, EdgesFrom, EdgesTo, NodeIDs)
│
├── parser/ # Lexer + recursive descent parser
│ ├── lexer.go # Indentation-aware tokenizer
│ ├── parser.go # Produces ir.Workflow from tokens
│ ├── parse_defaults.go # Defaults block parsing
│ ├── parse_edges.go # Edge and condition parsing
│ ├── parse_nodes.go # Node declaration parsing
│ ├── parse_stylesheet.go # Stylesheet section parsing
│ └── parse_helpers.go # Shared utilities
│
├── validator/ # Graph validation + semantic linting
│ ├── validate.go # 10 structural checks (DIP001-DIP010)
│ ├── lint.go # Lint orchestration (DIP101-DIP162)
│ └── diagnostic.go # Diagnostic type, Result, Severity
│
├── formatter/ # Canonical .dip source formatter
├── export/ # DOT graph exporter
├── migrate/ # DOT ↔ Dippin migration + parity checker
├── simulate/ # Reference graph executor (JSONL events)
├── cost/ # Cost estimation engine + pricing tables
├── coverage/ # Edge coverage analysis
├── doctor/ # Health report card (grade A-F)
├── optimize/ # Model optimization suggestions
├── diff/ # Semantic workflow comparison
├── feedback/ # Cost calibration from telemetry
├── unused/ # Dead-branch detection
├── graph/ # ASCII DAG rendering
├── testrunner/ # Scenario test runner
├── lsp/ # Language Server Protocol server
├── dipx/ # .dipx bundle format (loader tier)
├── scaffold/ # Template scaffolding for dippin new
└── cmd/dippin/ # CLI entry point + command handlersKey Design Decisions
IR as the universal interface
Everything flows through ir.Workflow. Packages import ir but not each other (except analysis packages that compose). This decouples parsing from all downstream consumers.
Sealed interfaces
Both NodeConfig and ConditionExpr use Go's sealed interface pattern with unexported methods. Only types within the ir package can implement them, preventing invalid configurations.
No short-circuiting validation
All 10 structural checks and all 62 semantic checks run unconditionally. A single call reports every issue, not just the first. This enables batch fixing.
Zero external dependencies
Core packages depend only on the Go standard library. The ir package imports only time. Only the lsp package uses external libraries (go.lsp.dev for JSON-RPC 2.0).
Idempotent formatter
The formatter is the authority on canonical form. Format(Parse(Format(Parse(source)))) always equals Format(Parse(source)). The fmt --check command uses this property.
Testable CLI
The Run function accepts args []string and io.Writer, making it fully testable without touching os.Args or os.Stdout. All commands are exercised via this interface.
Loader-tier exemption
The dipx package is a bounded exception to the IR-only rule: it may import parser and simulate to materialize a parsed workflow tree from a .dipx bundle, but MUST NOT import validator, cost, formatter, or any analysis package. Pack-time structural validation runs at the CLI layer.
Dependency Graph
The ir package is a leaf dependency. Most packages import only ir. Analysis packages compose each other.