Manifold
Manifold is a world-modeling and mathematical optimization engine under development at Ramverk. It represents operational state, relationships, resources, permitted changes, constraints, and objectives explicitly so software can evaluate bounded paths toward a goal.
Manifold keeps confirmed facts separate from interpretations and proposed results. Plans remain derived proposals until a person or an observed result confirms a consequential change.
Development status
Manifold is under development and is not generally available. These docs describe the current checkout. The documented DSL syntax works with the parser and resolver in this repository, but it is not yet a stable public contract.
Where to begin
- Follow Getting started to check a DSL source file from this repository.
- Read the Manifold DSL guide for the complete implemented language surface.
- Read Model boundaries for the distinctions shared by every Manifold developer surface.
- Open the API reference when a generated Manifold OpenAPI contract is available.
Getting started
Manifold does not yet have a published installation or hosted onboarding flow. You can check DSL source with the current repository checkout.
Create model.dsl at the repository root:
entity "vehicle-1" {
description {
name = "Service vehicle"
}
capacities {
payload_mass = 800 kg
}
properties {
payload_mass = 0 kg
located_at = location(59.3293, 18.0686)
}
traits [vehicle]
}
task "keep-vehicle-at-base" {
desired {
@"vehicle-1".properties.located_at = location(59.3293, 18.0686)
}
}
Check it from the repository root:
cargo run -p manifold-dsl -- check model.dsl
The command exits successfully without output when the source parses and resolves. It writes a source diagnostic to standard error and exits with a failure status when it finds an error.
This command checks the parsed and resolved source model. It does not materialize the source into the engine or produce a plan. Continue with the DSL overview, or read the CLI guide for standard input and base context.
The developer surfaces have distinct roles:
| Surface | Role | Current status |
|---|---|---|
| Manifold DSL | Declarative model source | Parsing, resolution, validation, diagnostics, and a check command are implemented in this repository. |
| Manifold SDK | Public name for developer libraries | No supported public package is published from this repository yet. |
| Manifold API | Authenticated customer-facing data plane | The contract is under development. |
Model boundaries
Manifold models the part of an operation relevant to a bounded decision. It does not need an exhaustive representation of the world.
Confirmed state
The current digital twin contains operational facts accepted by the system. Stable identities remain distinct from changing state, and retained provenance records where information came from.
Desired state
Work describes what must become true, together with its constraints and objectives. It does not prescribe the sequence of changes used to reach that outcome.
Permitted change
A mutation declares a reusable change Manifold may consider. It defines roles, requirements, temporary resource uses, and persistent transformations without binding concrete entities or granting execution approval.
Proposed plan
Planning binds resources, evaluates alternatives, and schedules mutations. A plan contains predicted state and remains separate from confirmed operational truth.
Observed result
An observation records what happened. It can update confirmed state through a new traceable change; selecting a plan does not silently make its predictions true.
Manifold DSL
The Manifold DSL is the declarative source language for a Manifold model. A source file can declare condition vocabularies, entities, permitted mutations, and tasks that describe desired state.
The current pipeline has four visible stages:
- The lexer recognizes tokens and retains source spans.
- The parser builds a syntax tree and expression arena.
- The resolver decodes identities, resolves references and roles, and builds a syntax-independent model.
- Validation rejects duplicate identities, invalid component paths, unsupported state values, incompatible capacities, and undeclared mutation role values.
The manifold-dsl check command runs these stages and renders source
diagnostics. Engine materialization and planning are not implemented by this
pipeline yet.
Declarations
A source file accepts four top-level declarations:
| Declaration | Purpose | Identity form |
|---|---|---|
condition | Declares a named set of condition variants. | Identifier |
entity | Declares an identity and its current components. | Quoted string |
mutation | Declares roles, requirements, resource uses, and changes. | Quoted string |
task | Declares predicates for a desired state. | Quoted string |
The resolver collects declarations before it resolves their bodies. A local entity can therefore refer to an entity declared later in the same file.
Read Language structure for lexical rules and block syntax. The complete example is the same representative source checked by the DSL test suite and the documentation recipe.
Language structure
Manifold DSL source is a sequence of top-level declarations. Whitespace separates entries. Blocks do not use semicolons, and lists do not use commas. Function arguments are the exception: commas separate arguments inside parentheses.
condition readiness [not_ready ready]
entity "van-110" {
traits [vehicle van]
}
The current lexer does not support comments. A comment marker such as # or
// produces an unknown-token diagnostic.
Identifiers and identities
An identifier starts with an ASCII letter or underscore. Later characters can also be digits.
vehicle
payload_mass
ready_2
Conditions and mutation roles use identifiers. Entities, mutations, and tasks use quoted string identities.
condition readiness [ready]
entity "van-110" {}
mutation "transport-payload" {}
task "deliver-cargo-42" {}
Quoted strings support \", \\, \n, \r, and \t. Other escape
sequences fail during resolution.
Numbers and quantities
Numbers contain digits and can have a decimal fraction. A leading sign is a unary operator rather than part of the number token.
0
59.3293
-18.0686
A quantity is a number, whitespace, and a unit. A compound unit can contain slash-separated identifier segments without spaces around the slash.
800 kg
0.08 l/km
70 km/h
The resolver currently preserves the number and unit text. It does not convert units or check dimensional compatibility.
Blocks and lists
Curly braces contain named sections or expressions. Square brackets contain identifiers or reference paths, depending on the section.
entity "cargo-42" {
properties {
mass = 120 kg
}
traits [cargo]
}
Whitespace is sufficient between entries. Formatting is not yet canonical, and no formatter is provided.
Declaration order
The resolver first collects all top-level identities, then resolves declaration bodies. Forward entity references therefore work within one source file:
entity "cargo" {
properties {
located_at = @"depot".properties.located_at
}
}
entity "depot" {
properties {
located_at = location(59.3293, 18.0686)
}
}
Every condition, entity, mutation, and task identity must be unique within the file. It must also be absent from any base context supplied to the resolver.
Conditions
A condition declaration defines a named vocabulary of states. The condition name and each variant are identifiers.
condition readiness [
not_ready
ready
]
condition cleanliness [clean dirty contaminated]
An entity records condition state in its conditions section:
entity "van-110" {
conditions {
readiness = ready
cleanliness = clean
}
}
Condition entries are expressions. They can be read through a concrete component path:
@"van-110".conditions.readiness
@vehicle.conditions.readiness
The first path refers to a known entity. The second refers to a mutation role and is valid only inside a mutation.
The current resolver stores condition declarations and entity condition expressions, but it does not yet prove that an assigned symbol is one of the declared variants. Treat the declarations as model intent rather than complete enum type-checking.
Entities and state
An entity has a stable quoted identity and a set of components. The current DSL
supports description, capacities, properties, traits, and conditions.
entity "van-110" {
description {
name = "White VW van"
plate = "ABC-123"
}
capacities {
payload_mass = 800 kg
}
properties {
payload_mass = 0 kg
speed = 70 km/h
located_at = location(59.3293, 18.0686)
}
traits [vehicle van diesel]
conditions {
readiness = ready
}
}
Description
description contains named string values. It holds human-readable metadata,
not changing operational state.
description {
name = "White VW van"
plate = "ABC-123"
}
Properties
properties contains current state values. The resolver accepts three value
forms:
- a quantity such as
120 kg; - a location such as
location(59.3293, 18.0686); or - a reference to one component value on an entity or mutation role.
properties {
mass = 120 kg
located_at = location(59.3293, 18.0686)
depot = @"hq".properties.located_at
}
Plain numbers, strings, symbols, arithmetic expressions, and arbitrary function
calls are not valid property initializers. location takes exactly two signed
or unsigned numbers. The resolver does not currently check geographic ranges.
Capacities
A capacity is a limit for a property on the same entity. Every capacity must have a property with the same name.
capacities {
payload_mass = 800 kg
}
properties {
payload_mass = 0 kg
}
When both values are concrete, they must use the same broad value form: quantity with quantity, or location with location. The current check does not compare quantity units or evaluate bounds. A reference value bypasses this shallow compatibility check because its concrete type is not resolved yet.
Traits
Traits are identifier labels that state a capability or classification.
traits [vehicle van diesel]
A trait path names one specific trait:
@"van-110".traits.vehicle
Conditions
conditions contains named state expressions. See Conditions
for declarations and current validation limits.
Component names
A component entry name must be unique within its component kind, including across repeated sections. A reference to a known entity must name an entry that the entity declares.
References and expressions
Expressions appear in condition state, mutation requirements and changes, and task predicates. The parser preserves their structure and precedence. The resolver resolves entity and role component paths and keeps other symbols and calls for later stages.
References
An entity reference starts with @ and a quoted identity:
@"cargo-42".properties.mass
A mutation role reference starts with @ and a role identifier:
@payload.properties.mass
Role references are valid only inside a mutation that declares the role.
Except for whole-entity resource uses, a reference must identify exactly one component value:
@"van-110".description.plate
@"van-110".capacities.payload_mass
@"van-110".conditions.readiness
@"van-110".properties.fuel_volume
@"van-110".traits.vehicle
References cannot stop at an entity or component, and they cannot continue past the value name. Reference chains are not supported.
Evaluation values
An evaluation value starts with $:
$distance
$duration
The parser and resolver preserve evaluation paths as symbolic inputs. The current DSL pipeline does not compute them. A later routing or planning stage is expected to supply their values.
Values and calls
General expressions accept:
- quoted strings;
- numbers and quantities;
- symbols and paths;
- function calls;
- parenthesized groups;
- unary
+and-; and - binary arithmetic and comparison operators.
@van.properties.fuel_volume > 0 l
$distance * @van.properties.fuel_per_distance
score(@vehicle.properties.speed, $duration)
Calls are parsed generically. Only location(latitude, longitude) has special
meaning when it initializes a property or capacity.
Operators and precedence
Binary operators bind in this order, from strongest to weakest:
| Precedence | Operators |
|---|---|
| 1 | unary +, unary - |
| 2 | *, / |
| 3 | +, - |
| 4 | =, !=, <, <=, >, >= |
Operators with the same precedence associate from left to right. Parentheses override precedence.
a + b * c
(a + b) * c
a - b - c
The resolver does not yet type-check general expressions, compare units, or require task and requirement expressions to produce Boolean values.
Mutations
A mutation declares a reusable permitted change. It defines abstract roles, requirements for binding those roles, temporary resource uses, and persistent transformations. Declaring a mutation does not bind entities or approve its execution.
mutation "transport-payload" {
roles [van payload destination]
requires {
@van.traits.vehicle
@payload.traits.cargo
@destination.traits.location
@van.properties.located_at = @payload.properties.located_at
@destination.properties.located_at
@van.capacities.payload_mass
@payload.properties.mass
}
uses {
reserve [@van @payload]
observe [@destination.properties.located_at]
occupy {
@van.capacities.payload_mass += @payload.properties.mass
}
}
transforms {
@van.properties.located_at -> @destination.properties.located_at
@payload.properties.located_at -> @destination.properties.located_at
}
}
Roles
roles lists the abstract entities a mutation needs. Role names must be unique
within the mutation.
roles [van payload destination]
Use @role to refer to a role. An undeclared role produces a resolver error.
Requirements
requires contains expressions that describe acceptable role bindings and
required component values.
requires {
@van.traits.vehicle
@van.conditions.readiness = ready
@van.properties.fuel_volume > 0 l
}
Every role component value used by observe, share, reserve, occupy, or
transforms must appear somewhere in requires. The mention can be nested in
a larger expression. This rule makes the mutation’s data needs explicit.
Whole-role uses such as reserve [@van] are exempt because they reserve the
entity rather than one component value. References to concrete entities are
also exempt from the role requirement rule.
Resource uses
uses describes temporary access while a mutation is active.
| Section | Current representation |
|---|---|
observe | Read an entity or one component value. |
share | Share an entity or one component value. |
reserve | Reserve an entity or one component value. |
occupy | Apply a temporary change to a component value. |
The first three sections contain path lists:
uses {
observe [@destination.properties.located_at]
share [@vehicle.properties.telemetry]
reserve [@vehicle @payload]
}
occupy contains changes:
uses {
occupy {
@vehicle.capacities.payload_mass += @payload.properties.mass
}
}
The DSL records these use modes, but scheduling and contention behavior are not implemented by the DSL resolver.
Transformations
transforms declares persistent changes. A change target must be a component
value on an entity or role reference.
| Operator | Parsed change |
|---|---|
= | Assign |
+= | Add and assign |
-= | Subtract and assign |
*= | Multiply and assign |
/= | Divide and assign |
-> | Become |
transforms {
@van.properties.fuel_volume -=
$distance * @van.properties.fuel_per_distance
@payload.properties.located_at ->
@destination.properties.located_at
}
The resolver preserves each operator. It does not apply the changes or prove that their values and units are compatible.
Tasks and desired state
A task states what should become true. It does not prescribe a mutation or a sequence of steps.
task "deliver-cargo-42" {
desired {
@"cargo-42".properties.located_at =
@"workshop".properties.located_at
}
}
A task identity is a quoted string. Its desired section contains one or more
expressions. Concrete entity references can target entities declared in the
same source or supplied through a base context.
The parser and resolver preserve desired expressions. They do not yet require a Boolean result, compile the task into solver input, select mutations, or produce a plan.
Keep desired state separate from mutation mechanics. The task above says where the cargo should be. The transport mutation describes one permitted way to change locations. A later planner will decide whether and how to bind and use that mutation.
Check source files
The manifold-dsl binary checks one source file. Run it through Cargo from the
repository root:
cargo run -p manifold-dsl -- check path/to/model.dsl
A valid file produces no output and exits successfully. A lexer, parser, or resolver error produces a source diagnostic on standard error and exits with a failure status.
Standard input
Pass - to read the source from standard input:
printf 'entity "vehicle-1" {}' | cargo run -p manifold-dsl -- check -
Base context
Use --base to resolve a source file against declarations from another DSL
file:
cargo run -p manifold-dsl -- check task.dsl --base current-state.dsl
The command parses and resolves the base file first. References in task.dsl
can then use entities declared by current-state.dsl. Base declarations do not
become part of the result for the checked file. A checked file cannot redeclare
an identity that exists in the base context.
Standard input cannot be both the checked source and the base source.
Color
Use the global --color option with auto, always, or never:
cargo run -p manifold-dsl -- --color never check model.dsl
Diagnostic families
Diagnostic codes identify the stage that rejected the source:
| Prefix | Stage |
|---|---|
MDSL-L | Lexer |
MDSL-P | Parser |
MDSL-R | Resolver and semantic validation |
Diagnostics include the source path, one or more labeled spans, and help text when the resolver can suggest a concrete correction.
Complete example
This example defines condition vocabularies, four entities, one transport
mutation, and a delivery task. The DSL parser and resolver test suite checks the
same source file. The developer documentation test also runs it through the
manifold-dsl check command.
condition readiness [
not_ready
ready
]
condition cleanliness [
clean
dirty
contaminated
]
entity "van-110" {
description {
name = "White VW van"
plate = "ABC-123"
}
capacities {
payload_mass = 800 kg
fuel_volume = 60 l
}
properties {
payload_mass = 0 kg
curb_mass = 1800 kg
fuel_volume = 50 l
fuel_per_distance = 0.08 l/km
speed = 70 km/h
located_at = @"hq".properties.located_at
}
traits [
vehicle
van
diesel
]
conditions {
readiness = ready
cleanliness = clean
}
}
entity "cargo-42" {
properties {
mass = 120 kg
located_at = @"hq".properties.located_at
}
traits [
cargo
]
}
entity "hq" {
traits [
location
]
properties {
located_at = location(59.3293, 18.0686)
}
}
entity "workshop" {
traits [
location
]
properties {
located_at = location(59.3498, 18.0707)
}
}
mutation "transport-payload" {
roles [
van
payload
destination
]
requires {
@van.traits.vehicle
@van.conditions.readiness = ready
@payload.traits.cargo
@destination.traits.location
@van.properties.located_at = @payload.properties.located_at
@destination.properties.located_at
@van.capacities.payload_mass
@payload.properties.mass
@van.properties.fuel_volume
@van.properties.fuel_per_distance
}
uses {
observe [
@destination.properties.located_at
]
reserve [
@van
@payload
]
occupy {
@van.capacities.payload_mass += @payload.properties.mass
}
}
transforms {
@van.properties.fuel_volume -=
$distance * @van.properties.fuel_per_distance
@van.properties.located_at -> @destination.properties.located_at
@payload.properties.located_at -> @destination.properties.located_at
}
}
task "deliver-cargo-42" {
desired {
@"cargo-42".properties.located_at = @"workshop".properties.located_at
}
}
The example is a language fixture. Checking it proves that the current parser and resolver accept it. It does not run the transport mutation or produce a delivery plan.
Current limitations
The current DSL implementation can lex, parse, resolve, validate, and diagnose the documented source language. The following boundaries remain:
- The syntax is under development and has no stability guarantee.
- No public package or standalone installer is available.
- No formatter or canonical formatting rule is implemented.
- Source comments are not supported.
- Property and capacity initializers accept only quantities, locations, and component-value references.
- Unit strings are preserved but not converted or checked for dimensional compatibility.
- Location coordinates must be numbers, but geographic ranges are not checked.
- General expressions are not type-checked.
- Condition values are not checked against declared condition variants.
- Evaluation values such as
$distanceremain symbolic. - Resource use modes are recorded but not scheduled.
- Transformations are resolved but not applied.
- DSL source is not yet materialized into the Manifold engine.
- Tasks are not compiled into solver input, and the DSL does not produce plans.
- Base context can supply declarations for resolution, but commit, merge, and overwrite behavior belongs to a later application layer.
These docs describe implemented syntax and validation, not a generally available or production-stable language contract.
Manifold SDK
Manifold SDK is the public umbrella name for developer libraries that interact with Manifold. Individual packages will keep concrete, role-based names.
No supported public SDK package is published from this repository yet. Package installation, language-specific examples, and compatibility guarantees will be added only after those artifacts exist.
Manifold API
The Manifold API is the future authenticated customer-facing data plane. It is separate from the dashboard control-plane API and from Manifold’s unauthenticated local development server.
The endpoint and authentication contracts are still under development. This section will document them from the generated Manifold OpenAPI schema once that contract exists.
Do not use the repository’s current root OpenAPI document here: that schema is generated by Shift API and describes a different product boundary.
API reference
The reference below is generated from a Manifold OpenAPI document when one is provided to the documentation build.
The generated Manifold API contract is not available in this build. The API remains under development.