Fragments and the DSL
A fragment is one .sbx file with one fragment declaration.
# What this fragment is for — plain comments are dropped.fragment "ripgrep" { selects_on = { commands = ["rg"] } requires = ["toolchains/rust"]
fs { allow_read ["$WORKDIR"] # the project being searched allow_read ["~/.ripgreprc"] # user config }}Fragment-level fields
Section titled “Fragment-level fields”schema_version = 1 | the DSL version the fragment is written for. A fragment stating a version this wardcell does not read is refused before anything is applied; one that states none is read as the current version |
selects_on = { ... } | when this fragment applies automatically |
offer_on = ... | whether this fragment is a choice in the workspace setup picker, and which markers pre-check it |
requires = [...] | other fragments to pull in, by root-relative path without .sbx |
selects_on
Section titled “selects_on”selects_on = { commands = ["git", "gitk"], app_bundles = ["com.example.app"] }commands matches the basename of the command being run, so git matches
/usr/bin/git. app_bundles is an exact match, macOS only.
A fragment with no selects_on applies only when something names it —
--profile, or another fragment’s requires.
offer_on
Section titled “offer_on”offer_on = { group = "Toolchains", files = ["Cargo.toml", "rust-toolchain.toml"] } # offered under "Toolchains", pre-checked on these markersoffer_on = { group = "Tools" } # offered under "Tools", never pre-checkedoffer_on makes a fragment a choice in the workspace
setup picker. The required
group is the heading it sits under — stated in the fragment, not inferred
from the directory, so gh, curl and docker share a “Tools” heading without
sharing a folder. The optional files pre-check the fragment when a checkout
holds one near the root; they are basename patterns with * as the only wildcard
("*.xcodeproj"), matching a file or directory entry. Omit files for a tool
with no repository footprint (gh, ssh): still offered under the picker’s
show all, never pre-checked.
Headings show in a curated order — Toolchains, Tools, Integrations — then any
other group alphabetically. offer_on is metadata only: read by the picker
when you set a workspace up, never when a command runs, and kept strictly apart
from selects_on, which decides what a run selects. offer_on = true/false
and an object with no group are refused; omit offer_on to keep a fragment
out of the picker.
OS tags
Section titled “OS tags”Prefix a block with [linux] or [macos] and it applies only there. An
untagged block applies to both.
[linux]fs { allow_read_ancestors ["~/.ssh"] }
[macos]fs { allow_read_metadata_ancestors ["~/.ssh"] }Comments
Section titled “Comments”# runs to end of line. A comment on the same line as a list entry or a
block becomes that rule’s description and shows up in policy explain:
allow_read [ "~/.gitconfig", # User gitconfig read by the git CLI.]
allow_http "api.example.com" { # the orders API allow_requests ["GET /v1/**"]}A comment on its own line is documentation and is discarded. Use same-line comments for anything a reviewer will want when the rule is questioned.
Path variables
Section titled “Path variables”$NAME tokens in fs paths and env values are expanded by the backend at
render time, so the IR keeps exactly what you wrote. The ones you reach for most:
~, $HOME | the user’s home directory |
$WORKDIR | the directory wardcell run was invoked from |
$TMPDIR | the per-run temporary directory |
The DSL reference has the complete table —
every context, git, macOS, proxy and plugin variable, and which ones an env
value points a tool at.
Values
Section titled “Values”field = "string" # stringfield = true # boolfield = 65536 # integerfield ["a", "b"] # list — note: no `=`block "label" { ... } # nested block with a labelLists take no =. That is the one piece of the grammar that catches people
out.
Full grammar
Section titled “Full grammar”See the DSL Reference.