1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
//! A scheduled, dependency-ordered orchestrator of asset graphs.
//!
//! swale runs on the taquba durable execution crates. Every task instance
//! runs as a single workflow run, and the record of its outcome and the event
//! for the scheduler commit in one transaction.
//!
//! # Definition file
//!
//! One TOML file per graph. An asset node declares the asset it produces and
//! the assets it consumes, and a task node declares its upstream nodes with
//! `after`.
//!
//! ```toml
//! [graph]
//! name = "orders_daily"
//! schedule = "0 2 * * *"
//! partition = "daily"
//!
//! [[node]]
//! name = "extract"
//! produces = "orders_raw"
//! operator = "shell"
//! [node.params]
//! command = "dbt run --select orders_raw >&2 && printf '{\"table\": \"orders_raw\"}'"
//!
//! [[node]]
//! name = "load"
//! produces = "orders_warehouse"
//! consumes = ["orders_raw"]
//! operator = "http"
//! [node.params]
//! method = "POST"
//! url = "https://warehouse.example/load"
//! body = '{"table": "{{ upstream.extract.table }}"}'
//! ```
//!
//! The [`definition`] module documents every field, and the loader reports
//! every fault of a definition at once. From Rust, [`load_path`] returns the
//! checked graph:
//!
//! ```
//! use std::path::Path;
//! use swale::OperatorSet;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let graph = swale::load_path(
//! Path::new("examples/orders_daily.toml"),
//! &OperatorSet::builtin(),
//! )?;
//! println!("{}: {} nodes", graph.name(), graph.nodes().len());
//! # Ok(()) }
//! ```
//!
//! # Operators
//!
//! An operator runs a node, and its parameters are the `params` table of the
//! node. A parameter string refers to `{{ partition }}`, `{{ run.<field> }}`
//! (`id` or `summary`), `{{ upstream.<node>.<path> }}` and `{{ env.<NAME> }}`.
//! The upstream reference is a path into the JSON output of an upstream node,
//! and the env reference is an environment variable of the daemon.
//!
//! - **`subprocess`** runs `argv` with a JSON document on stdin (the identity,
//! the parameters and the upstream outputs) and reads the output from stdout.
//! - **`shell`** runs `command` with `sh -c`, with the identity in `SWALE_*`
//! variables, the upstream outputs in `SWALE_INPUTS` and the `env` table in
//! the environment, and reads the output from stdout.
//! - **`http`** sends `method`, `url`, `headers` and `body` within `timeout`
//! and outputs `{"status": <code>, "body": <value>}`, with a JSON body
//! parsed.
//! - **`object_exists`** waits until an object exists at `url`, a store URL,
//! with a poll every `interval` and a failure after `timeout`. No worker
//! is held between polls, and the output is the URL, the size and the
//! last-modified time of the object.
//!
//! Exit code 0 and a 2xx status are success. Exit code 75, a 5xx status, a 429
//! status, a connection failure and a timeout are transient errors, retried up
//! to `retries` times. Any other exit code or status is a permanent error,
//! which dead-letters the task instance. A program or a request must be
//! idempotent per attempt.
//!
//! # Schedule
//!
//! The daemon fires the `schedule` of a graph, a cron expression with five
//! fields in UTC. The partition of a firing is the start of the schedule
//! interval that ends at the firing time: a daily schedule at 02:00 that
//! fires on 2026-09-16 runs the partition `20260915`. A graph with a schedule
//! declares `partition` as `daily` or `hourly`.
//!
//! The first adoption of a graph runs the partitions of the firings within
//! its `catchup` window. After downtime the daemon replays the missed firings
//! within the same window.
//!
//! # Command
//!
//! The `swale` binary is enabled by the default `cli` feature. A program that
//! embeds the library can set `default-features = false`.
//!
//! `swale validate` loads a definition and prints each fault, one per line.
//!
//! `swale run` runs a graph for one partition on a store, prints each node's
//! record as it is written and waits for the run to settle. A second `run`
//! for the same partition resumes the existing graph run, and a process
//! interrupted mid-run resumes without repeating a completed node.
//!
//! `swale publish` writes a definition to the store as the current definition
//! of its graph. `swale daemon` runs the published graphs until it is
//! interrupted. It adopts each published definition within one sync interval,
//! fires each schedule and runs the task instances. A graph run keeps the
//! definition it started from, so an edit applies from the next graph run.
//! The `default` pool always exists, and `--pool name=steps` adds a pool.
//!
//! The daemon keeps the records of a settled graph run and the request
//! records for `--retention`, ninety days by default. A start of a partition
//! whose records were removed runs the graph again.
//!
//! Every command that opens a store takes `--store`: a directory or an object
//! store URL (`s3://bucket/prefix`, `gs://bucket/prefix`,
//! `az://container/prefix`). A cloud scheme needs the matching cargo feature
//! (`aws`, `gcp` or `azure`) and reads the provider's environment variables
//! for its credentials. The default store is `~/.swale/store`.
//!
//! `swale run` and `swale daemon` open the store as its only writer. A
//! `swale run` on the store of a running daemon opens a second writer, and
//! the store then refuses the writes of the daemon.
//!
//! `swale status` lists the graphs of a store with the count of their graph
//! runs in each state. `swale status <graph>` lists the latest graph runs of
//! the graph, and `swale status <graph> <partition>` lists the nodes of one
//! graph run. A node without a record is `ready`, `waiting` or `blocked`. A
//! blocked node does not run until a rerun changes the record of an upstream.
//!
//! `swale queues` lists the job counts of every queue, and `swale queues
//! <queue>` lists the dead jobs of one queue. Both commands only read from the
//! store, so they can run alongside a daemon.
//!
//! `swale start <graph> <partition>...` starts the graph run of each
//! partition, `swale rerun <graph> <partition> <node>` runs a node again, and
//! `swale cancel <graph> <partition>` cancels an active graph run. Each
//! command writes a request to the store and does not open the queue, and
//! the daemon applies the request at its next sync pass. With `--wait` the
//! command waits for the outcome and prints it.
//!
//! A rerun of a failed or cancelled node runs the node again, and its
//! downstream nodes follow as their trigger rules allow. A rerun of a
//! succeeded node runs the node again and, after it, every node downstream
//! of it through an asset edge or an all-succeeded edge, each with the new
//! outputs. A task node with the all-done or one-failed rule keeps its
//! record. Until such a node runs again, the status view shows it as ready,
//! waiting or blocked with its last record.
//!
//! ```console
//! $ swale validate examples/orders_daily.toml
//! orders_daily: 5 nodes, 3 edges
//! $ swale run examples/local.toml --store ./swale-store
//! local/none: started, 1 root node(s) submitted
//! first: succeeded (local-none-first-r0)
//! second: succeeded (local-none-second-r0)
//! local/none: complete
//! $ swale status local none --store ./swale-store
//! local/none: complete, requested 2026-09-17T13:48:19Z, definition 9450f82715de
//! NODE POOL STATE RUN TERMINATED
//! first default succeeded local-none-first-r0 2026-09-17T13:48:19Z
//! second default succeeded local-none-second-r0 2026-09-17T13:48:20Z
//! $ swale publish examples/orders_daily.toml --store s3://bucket/swale
//! orders_daily: published 36e831ff15e026ad45115374cb98edec6b617dffb0d4ef40f9fd351ea36bca9a
//! $ swale daemon --store s3://bucket/swale --pool warehouse=2
//! $ swale rerun orders_daily 20260915 transform --store s3://bucket/swale --wait
//! request 01K5ARRE8ZW9K8XTJTQ6PVYJK7: submitted orders_daily-20260915-transform-r1
//! ```
//!
//! A command exits with status 0, 1 or 2:
//!
//! - **0.** The command succeeded. An interrupt ends `swale daemon` with this
//! status.
//! - **1.** A definition has a fault, a graph run failed, a request was
//! refused or another error occurred.
//! - **2.** The arguments are not valid.
pub use ;
pub use ;
pub use ;
pub use Error;
pub use ;
pub use ;
pub use ;
pub use Partition;
pub use Pools;
pub use NodeState;
pub use ;
pub use ;
pub use ;
pub use ;
pub use TaskIdentity;
pub use Template;