Skip to content
Beskid The Beskid Book

Beskid

Jump to a Beskid service

Beskid

Jump to a Beskid service

03.6 Bsol — structured config without YAML trauma

The meta-language behind .bproj manifests, schema profiles, and why it feels like HCL until the compiler gets honest.

Bsol — structured config without YAML trauma

Every toolchain eventually invents a config dialect. Beskid’s is Bsol (Beskid Structured Object Language). If you have touched Terraform, you already know the shape: blocks, labels, key = value, bracket lists. If you have touched YAML, you already know why we did not use it for manifests.

This page is informative. Exact grammar and profile rules live in the Bsol platform spec.

Bsol is not Beskid program syntax. Your .bd files still go through the normal surface parser, semantic rules, HIR, codegen—the full analysis stack.

Bsol is the meta-language for files the compiler reads before it touches your source tree:

FileProfileBecomes
MyApp.bprojproject.v1ProjectManifest + resolver graph
workspace.bws / workspace.projworkspace.v1WorkspaceManifest
runtime_manifest.bsolruntime.v1ABI tables and dispatch registries

Same surface grammar. Different schema profile. Same pipeline shape.

HashiCorp Configuration Language (HCL) popularized a useful pattern:

resource "aws_instance" "web" {
ami = "ami-123"
instance_type = "t3.micro"
}

Bsol uses the same mental model—block kind, optional label, body of assignments—without pretending to be Terraform:

MyApp {
name = "MyApp"
version = "0.1.0"
}
target "App" {
kind = App
entry = "Main.bd"
}

The similarity is intentional. The divergence is where validation lives.

StageHCL-ish tools (typical)Beskid Bsol stack
Lex / parseCustom parser per productOne bsol.pest grammar → BsolDocument
StructureSchema baked into parserSchema profiles (project.v1, …)
SemanticsProvider / app logicbeskid_analysis::projects lowering + E18xx contract band
IDEOften string heuristicsLSP walks span-backed AST from parse_bsol_document

HCL separates syntax from provider semantics across many tools. Beskid separates syntax from manifest semantics across one crate (beskid_bsol) and downstream lowering—the same split you see between parse and semantic analysis for .bd, just on a smaller document.

flowchart LR
  subgraph bsol [beskid_bsol]
    pest[bsol.pest]
    ast[BsolDocument]
    prof[Schema profile]
    val[validate]
    pest --> ast --> val
    prof --> val
  end
  subgraph analysis [beskid_analysis projects stack]
    lower[parser.rs lowering]
    model[ProjectManifest]
    graph[Resolver / lockfile]
    val --> lower --> model --> graph
  end
  subgraph bd [Beskid .bd stack — same spine idea]
    parse[Parse Program]
    sem[Semantic rules]
    ir[HIR / codegen]
    parse --> sem --> ir
  end

Both paths share the platform rule: one spine, no shadow parsers. Manifest files are not special-cased with ad hoc regex in the LSP; they go through Bsol first, then contract validation—mirroring how .bd goes through parse, then semantic rules.

Older manifest parsers hard-coded block kinds in the grammar (target, dependency, …). Bsol widened the grammar to any ident { ... } block and moved legality into profiles:

  • Grammar answers: is this text structurally a Bsol document?
  • Profile answers: which blocks and fields are legal for this file type?
  • Lowering answers: what does it mean for builds and locks?

That three-layer split matches how the rest of the compiler treats syntax vs semantics—Bsol is the config-side version of “parse succeeds, semantic pass may still fail.”

@schemaless — when you need a raw { ... } pocket

Section titled “@schemaless — when you need a raw { ... } pocket”

Most blocks are structured. Occasionally a profile needs an opaque body—content the parser does not interpret as assignments (embedded snippets, foreign syntax, migration shims).

Mark the block with @schemaless before {:

patch @schemaless {
# anything between the braces is captured verbatim
keep = "this { nested } text"
not parsed as bsol
}

The profile rule must opt in with schemaless = true. Parser stores the inner text in schemaless_body; validation skips field rules; downstream code decides what to do with the raw string.

Structured blocks and schemaless blocks can coexist in one document—same as mixing strict types and extern escape hatches in the main language, but for config.

TopicLink
Writing your first manifestProject manifest
Workspace filesWorkspace manifest
Normative grammar + ASTBsol design model
Runtime ABI manifestRuntime manifest profile
Full analysis pipelineFrom source to something that runs

Tree and resolution

04. Where does this file even go?