Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,11 @@ is retained as evidence; it is not counted as a successful model run.

## What is not included

- **BPMN.** Weave does not import or export BPMN files. Subprocesses, loops,
compensation, and error boundary events are not part of the workflow language;
- **BPMN.** Weave does not import or export BPMN files. Compensation and error
boundary events are not part of the workflow language. The language defines
**Loop over items** and **Call a workflow** (see [Steps](contracts.md#steps)),
but this version does not compile or run them yet: the compiler reports
`WV-COMP-UNSUPPORTED_FEATURE`.
[Coming from BPM/BPMN](concepts.md#coming-from-bpmbpmn) lists the alternatives.
- **Named enterprise adapters.** SAP and Oracle are not offered as executable
named adapters. Reaching a system through a generic connector does not certify
Expand Down
4 changes: 2 additions & 2 deletions docs/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,8 @@ Use this table to translate what you know:
| Error end event, terminate end event | **Fail** (`fail`) | Ends the whole run as failed with your code and message, including any other parallel branches |
| Error boundary event | Not in the language | A failed Action retries when that is safe; otherwise the run is suspended with an incident for an operator. To branch on a business outcome, return it in the Action's output and test it with a Decision |
| Message throw or end event | **Call an action**, or an integration event subscription | A subscription notifies another system when a run's status changes |
| Call activity, subprocess | Not in the language | Keep the part inside the same workflow, or make it a separate workflow that your product starts |
| Loop, multi-instance activity | Not in the language | Use a Parallel with a fixed set of branches, or start one run per item |
| Call activity, subprocess | **Call a workflow** (`callWorkflow`) | Defined in the [workflow language](contracts.md#steps), but this version does not compile or run it: the compiler reports `WV-COMP-UNSUPPORTED_FEATURE`. Until then, keep the part inside the same workflow, or make it a separate workflow that your product starts |
| Loop, multi-instance activity | **Loop over items** (`forEach`) | Defined in the [workflow language](contracts.md#steps), but this version does not compile or run it: the compiler reports `WV-COMP-UNSUPPORTED_FEATURE`. Until then, use a Parallel with a fixed set of branches, or start one run per item |
| Compensation | Not in the language | Model compensating Actions as ordinary steps; Weave never undoes an external effect |
| Instance migration | Not available | A running run keeps its version; new runs use the new activation |
| Process monitoring, cockpit | **Runs**, history, and incidents in Studio and the CLI; logs, metrics, and traces | Studio draws a run's graph and marks its current step **Now**; see [follow and manage runs](guides/studio.md#save-publish-activate-and-run), [execution management](guides/execution-management.md), and [observability](operations/observability.md) |
Expand Down
79 changes: 72 additions & 7 deletions docs/contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,11 @@ snake_case keys in a document are rejected. Serialize Python models with
`model_dump(by_alias=True)` or `model_dump_json(by_alias=True)`.

**Some fields may be omitted but never set to null.** These are the workflow's
`timeoutSeconds`, an action's `connection` and `routing`, and an action step's
`connection`. When present they must have their declared type; an explicit `null`
is rejected. Both serializers preserve the omission, and the Python model shows
an omitted field as `None`.
`timeoutSeconds` and `callable` (and its `allowedCallers`), an action's
`connection` and `routing`, an action step's `connection`, and a call step's
`onFailure` and `businessKey`. When present they must have their declared type;
an explicit `null` is rejected. Both serializers preserve the omission, and the
Python model shows an omitted field as `None`.

`load_definition` checks shape only. It does not parse source text, validate the
embedded JSON Schemas, resolve dependencies, compile, or authorize anything. The
Expand All @@ -170,7 +171,10 @@ object with exactly one of these keys:
| `op` | An operator with expression arguments: `{op: {name, args}}` | `{op: {name: eq, args: [{ref: /input/urgent}, {literal: true}]}}` |

Operators are `eq`, `ne`, `lt`, `lte`, `gt`, `gte`, `and`, `or`, `not`, `exists`,
`coalesce`, `contains`, `notContains`, `in`, `notIn`, `startsWith`, and `endsWith`.
`coalesce`, `contains`, `notContains`, `in`, `notIn`, `startsWith`, `endsWith`,
`concat`, and `join`. `concat` joins one or more strings, numbers, or Booleans
into one string; `join` takes a list of such values and a separator string. Numbers
are written as JavaScript writes them (`2.0` becomes `2`, `1e21` stays `1e+21`).
There are no function calls, scripts, environment variables, or
file access. The compiler checks arity, types, and scope; the
[compiler reference](reference/compiler.md#cli-and-published-catalog-contract)
Expand All @@ -194,16 +198,29 @@ helps if you know process modeling from another tool:
| `kind` | Studio name | Closest BPMN idea | Other fields |
| --- | --- | --- | --- |
| `action` | **Call an action** | Service task | Required `uses` (exact action reference) and `with` (input expression); optional `connection` slot name |
| `llm` | **AI task** | Service task | Required `uses` (exact AI action reference), `profile` (an `llmProfiles` entry), `prompt` and `context` expressions, and `connection` slot name |
| `transform` | **Transform** | Script or business rule task (expressions only) | Required `value` expression |
| `decisionTable` | **Decision table** | Business rule task | Required `uses` (exact decision table reference) and `with` (input expression) |
| `switch` | **Decision** | Exclusive gateway | Nonempty `cases: [{when, steps, output}]` and required `default: {steps, output}` (the **Otherwise** path in Studio); the first true case wins |
| `parallel` | **Parallel** | Parallel gateway (split and join) | Nonempty `branches: {name: {steps, output}}` and a positive integer `concurrency`; every branch completes before the step continues |
| `wait` | **Wait for time** | Timer intermediate event | Required positive integer `durationSeconds` |
| `signal` | **Wait for signal** | Message intermediate event | Required `name`, positive integer `timeoutSeconds`, and a `payloadSchema` object |
| `humanTask` | **Human task** | User task | Required `assignment` (the name of an assignment bound at activation), `title` and `context` expressions, and `formSchema`; `decisions` defaults to `approve`, `reject` (1 to 32 unique names); optional positive `dueSeconds` and `expirySeconds` |
| `fail` | **Fail** | Error end event | Required business-error `code` (a name such as `customer-not-found`) and a nonempty `message` |
| `forEach` | **Loop over items** | Multi-instance subprocess | Required `items` (an expression that gives a list) and `body: {steps, output}`; optional `concurrency` (default 1), `maxItems` (default 1000), and `collect` (`all`, the default, or `nonNull`). The defaults are written into the stored document |
| `callWorkflow` | **Call a workflow** | Call activity | Required `uses` (exact workflow reference) and `with` (input expression); optional `mode` (`wait`, the default, or `detach`), `onFailure` (`stop` or `continue`, only with `wait`), and `businessKey` expression |

Weave is not a BPMN engine and does not import BPMN files. Subprocesses (call
activities), loops, and compensation are not part of the language.
Weave is not a BPMN engine and does not import BPMN files. Loops and calls to
other workflows are part of the language; compensation is not.

**New language constructs.** `forEach`, `callWorkflow`, `concat`, and `join`
each need a language feature: `flow.forEach`, `flow.callWorkflow`, `text.concat`,
and `text.join`. Their document shape is final, so `load_definition` accepts
them, but this version of the compiler reports `WV-COMP-UNSUPPORTED_FEATURE` at
each use instead of compiling it. A platform runs a construct only when its
[language manifest](#language-manifest) lists the feature. Step IDs can never
contain `[`, `#`, or `~`, which keeps
[instance keys](reference/compiler.md#instance-keys) unambiguous.

Branches may contain zero steps, but each must declare its `output`. The compiler,
not the shape check, enforces unique step IDs, unique signal names, branch scope,
Expand Down Expand Up @@ -231,6 +248,34 @@ definition; they are not legal on a workflow step.
| `output` | Yes | Expression that computes the run output |
| `timeoutSeconds` | No | Positive whole-run timeout; omit it for no workflow-wide timeout |
| `connections` | No (default `{}`) | **Connection slots**: named requirements `{connector: <exact ref>, required: <bool>}`; `required` defaults to `true`. Each slot is bound to an integration connection at activation |
| `callable` | No | Lets other workflows call this exact version with `callWorkflow`: `{}` allows any workflow in the project, and `{allowedCallers: [order-intake]}` allows only the named workflows (1 to 100 unique names). Studio will write it from a **Called by a workflow** trigger; the manifest marks the field `pending` until then |

A callable workflow, and a loop over a list that builds text for each item:

```yaml
# notify-customer@1.0.0 accepts calls from order-intake only.
spec:
callable:
allowedCallers: [order-intake]
---
# One reminder per invoice, four at a time, collected in invoice order.
- id: notify
kind: forEach
items: {ref: /input/invoices}
concurrency: 4
body:
steps:
- id: subject
kind: transform
value:
op:
name: concat
args: [{literal: "Invoice "}, {ref: /item/number}, {literal: " is overdue"}]
output: {ref: /steps/subject/output}
```

The full examples are in
[examples/language](../examples/language/).

## Actions

Expand Down Expand Up @@ -272,6 +317,24 @@ Manifests contain no Python source or import paths. To build one, see
[Author a connector](connectors/authoring.md); to call a REST API without
writing one, see [Call a REST API without code](connectors/http-without-code.md).

## Language manifest

The **language manifest** lists every step kind, operator, and workflow field the
language defines, the features each one needs, the features the platform runs,
and the language limits. Studio will read it to decide what to offer. Read it with
`weave remote language` or `GET /api/v1/tenants/{tenant}/projects/{project}/language`
(`language.read`, capability `catalog.read`); Studio's local host serves the same
document at `/studio/contracts/language`, and `weave schema export` writes its
schema as `language-manifest.schema.json`.

| Field | Meaning |
| --- | --- |
| `version`, `language_version` | `weave/language-manifest-v1` and `weave/v1alpha1` |
| `ir_versions` | The executable IR versions the platform accepts |
| `features` | The language features the platform runs; empty in this version |
| `limits` | `max_loop_items`, `default_loop_max_items`, `max_loop_depth`, `max_concurrency`, `max_run_iterations`, `max_call_depth` |
| `step_kinds`, `operators`, `workflow_fields` | One entry each, with the `feature` it needs (if any) and `studio`: `ready` when Studio edits it, `pending` until then |

## Values and budgets

Definitions and payloads use plain JSON values: null, Boolean, integer, float,
Expand Down Expand Up @@ -370,5 +433,7 @@ backend is absent. The `integration` and `e2e` pytest markers are registered.
| A field is rejected although it looks right | Field names are camelCase and case-sensitive; snake_case keys are rejected | Use the published name, such as `timeoutSeconds` |
| `null` is rejected for an optional field | Optional fields may be omitted but not set to null | Remove the field |
| A step's `retry` or `timeoutSeconds` is rejected | Retry and per-attempt timeout belong to the action definition | Move them to the action; use `spec.timeoutSeconds` for a workflow-wide timeout |
| `WV-COMP-UNSUPPORTED_FEATURE` | The document uses `forEach`, `callWorkflow`, `concat`, or `join`, which this version of the compiler does not compile yet | Keep the document for a later version, or replace the construct with the steps the compiler supports |
| `onFailure` is rejected on a call step | `onFailure` applies only when the call waits for its result | Remove `onFailure`, or set `mode: wait` |
| Partial validation passes, but there is no artifact | Partial validation never produces one | Compile with an explicit catalog |
| Compilation passes, but the run fails to start | Compilation proves no worker, connection, or permission | Check the activation's bindings and your grants |
7 changes: 5 additions & 2 deletions docs/contributing/source-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,11 @@ Choose the kind that matches the file:
Most inventory entries are `commentless`: strict JSON, the Python, npm, and
Cargo lockfiles, the desktop icons and installer background, and `py.typed`. Two
YAML files are `immutable-fixture` entries because parser and CLI tests assert
their source positions. One entry is `generated`: Studio's schema test corpus, produced by
[`studio_schema_fixtures.py`](../../scripts/studio_schema_fixtures.py). No vendored
their source positions. `generated` entries name their generator in `source`. Examples are
Studio's schema test corpus, produced by
[`studio_schema_fixtures.py`](../../scripts/studio_schema_fixtures.py), the shared language
fixtures, produced by [`language_fixtures.py`](../../scripts/language_fixtures.py), and the
worker lockfiles, produced from the `pyproject.toml` beside each. No vendored
third-party source is declared. Third-party dependencies keep their own
distribution metadata and license terms; the inventory does not certify
redistribution compliance.
Expand Down
27 changes: 27 additions & 0 deletions docs/contributing/source-inventory.toml
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,33 @@ copyright = "Copyright 2026 Firefly Software Foundation."
author = "Firefly Software Foundation"
license = "Apache-2.0"

[[exceptions]]
path = "studio/tests/fixtures/language/instance-keys.json"
kind = "generated"
source = "scripts/language_fixtures.py"
reason = "Strict JSON instance-key parse and format cases shared by the Python and Studio suites; regenerate with the generator, which also checks freshness."
copyright = "Copyright 2026 Firefly Software Foundation."
author = "Firefly Software Foundation"
license = "Apache-2.0"

[[exceptions]]
path = "studio/tests/fixtures/language/manifest.json"
kind = "generated"
source = "scripts/language_fixtures.py"
reason = "Strict JSON snapshot of the language manifest shared by the Python and Studio suites; regenerate with the generator, which also checks freshness."
copyright = "Copyright 2026 Firefly Software Foundation."
author = "Firefly Software Foundation"
license = "Apache-2.0"

[[exceptions]]
path = "studio/tests/fixtures/language/text-conversion.json"
kind = "generated"
source = "scripts/language_fixtures.py"
reason = "Strict JSON concat and join text conversion cases shared by the Python and Studio suites; regenerate with the generator, which also checks freshness."
copyright = "Copyright 2026 Firefly Software Foundation."
author = "Firefly Software Foundation"
license = "Apache-2.0"

[[exceptions]]
path = "studio/tests/fixtures/shipped-schemas.json"
kind = "generated"
Expand Down
1 change: 1 addition & 0 deletions docs/reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ operation in the [full API reference](api-explorer.md); to generate a client,
| `compiler.evaluate_decision` | `POST /api/v1/tenants/{tenant}/projects/{project}/compiler/evaluate-decision` | compile |
| `catalog.read` | `GET /api/v1/tenants/{tenant}/projects/{project}/catalog` | catalog.read |
| `capabilities.read` | `GET /api/v1/tenants/{tenant}/projects/{project}/capabilities` | catalog.read |
| `language.read` | `GET /api/v1/tenants/{tenant}/projects/{project}/language` | catalog.read |
| `schemas.read` | `GET /api/v1/tenants/{tenant}/projects/{project}/schemas` | catalog.read |
| `connector_descriptors.list` | `GET /api/v1/tenants/{tenant}/projects/{project}/connector-descriptors` | catalog.read |
| `connector_descriptors.read` | `GET /api/v1/tenants/{tenant}/projects/{project}/connector-descriptors/{adapter}` | catalog.read |
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ workspace, and you need each operation's grant. Find the body schemas in the
```sh
# Read the project catalog.
weave remote catalog --output json
# Read the language manifest: step kinds, operators, features, and limits.
weave remote language --output json
# Compile a request file through the platform.
weave remote compile --request compiler-request.json --output json
# Save a new draft, then a change to revision 1 of it.
Expand Down
Loading
Loading