Skip to content

DSL Overview

The BLOGE DSL is an external language for defining orchestration graphs in .bloge files. It is designed for teams that want workflow definitions to be readable, reviewable, lintable, and editable outside the Java build without inventing a different runtime model.

What the DSL describes

A .bloge file can express:

  • graphs and executable nodes
  • input bindings from context and upstream outputs
  • explicit or inferred dependencies
  • branch routing
  • resilience configuration
  • transform blocks for pure data shaping
  • schemas, iteration constructs, and session extensions
  • streaming, wait, and await constructs in the extended language surface

A minimal graph

bloge
graph orderProcess {
  node fetchUser : FetchUserOperator {
    input {
      userId = ctx.userId
    }
    timeout = 3s
    retry = { attempts: 2, backoff: 200ms, strategy: exponential }
  }

  node fetchProducts : FetchProductsOperator {
    input {
      productIds = ctx.productIds
    }
    timeout = 5s
  }

  node calcPrice : CalcPriceOperator {
    depends_on = [fetchUser, fetchProducts]
    input {
      user     = fetchUser.output
      products = fetchProducts.output
    }
  }

  branch on calcPrice.output.total > 100 {
    true      -> routeVip
    otherwise -> routeStandard
  }
}

Key ideas

ctx is the request boundary

ctx.<field> reads from GraphContext, which contains the caller-provided entry data or request metadata.

nodeId.output is the data boundary

fetchUser.output.id or calcPrice.output.total refers to upstream outputs. The compiler uses these references to infer dependencies automatically when possible.

transform is for pure shaping, not side effects

bloge
transform orderSummary {
  customerName = fetchUser.output.name
  total        = calcPrice.output.total
  tier         = when {
    calcPrice.output.total > 1000 -> "vip"
    otherwise                     -> "standard"
  }
}

Use transform when you need reusable, pure projections. Use a real operator when the step owns business logic, side effects, or its own SLA.

Resilience is part of the language

bloge
node checkCredit : CreditCheckOperator {
  input {
    userId = fetchUser.output.id
    amount = calcPrice.output.total
  }
  timeout = 2s
  retry = { attempts: 3, backoff: 100ms, strategy: jitter }
  fallback = { approved: false, reason: "service unavailable" }
}

That makes operational behavior visible in the source artifact instead of scattering it through helper libraries or annotations.

Beyond basic DAGs

The DSL surface goes beyond plain nodes and branches. The full language also supports:

  • foreach and loop for iterative orchestration
  • stream constructs for item-by-item forwarding
  • wait and await for suspend/resume patterns
  • session, phase, and round for multi-turn conversational flows
  • schemas and expression type inference for richer tooling and validation

These are all compiled back into BLOGE runtime models rather than introducing a separate engine.

Tooling workflow

BLOGE's language tooling stack is built around the same DSL contract:

  • bloge-lsp: completion, hover, formatting, go-to-definition, diagnostics
  • bloge-vscode: editor integration for .bloge files
  • bloge-lint: CLI and Maven-based static analysis
  • bloge-studio: visual authoring surface that imports and exports .bloge

When to use Java API vs DSL

Prefer Java API when...Prefer DSL when...
operators and graph definitions live in the same codebaseworkflow definitions should be reviewed or edited independently
compile-time type safety is the top priorityproduct, ops, or tooling teams need a standalone artifact
you want direct integration with application codeyou want linting, generation, or visual tooling around the graph

The two styles remain equivalent at runtime, so teams can mix them strategically.

Next steps