@hasna/workflows 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,36 +1,90 @@
1
1
  # @hasna/workflows
2
2
 
3
- Universal graph workflow app — 0.1.0 scaffold. This release ships the app
4
- shell: identity, configuration resolution, health and readiness on all four
5
- surfaces (CLI, MCP, serve, SDK).
6
-
7
- The graph language (with `while` nodes), three-table store, session WAL with
8
- torn-run repair, memoization, secrets write-gate, claims/leases daemon, and
9
- four lane adapters (claude, codex, cursor, grok) are **roadmap slices — not
10
- shipped in 0.1.0**. Nothing in this package reads or writes a workflow
11
- database yet.
3
+ Universal graph workflow app: a graph language (with `while` nodes), a
4
+ three-table store, session WAL with torn-run repair, memoization, a secrets
5
+ write-gate, a claims/leases daemon, and four lane adapters (claude, codex,
6
+ cursor, grok) — one domain implementation, four interface surfaces.
12
7
 
13
8
  ## Surfaces
14
9
 
15
10
  | surface | bin / export | what it is |
16
11
  |---|---|---|
17
- | CLI | `workflows` | command-line surface (`version`, `health`, `info` today; the full command set lands with the CLI slice) |
18
- | MCP | `workflows-mcp` | stdio MCP server for coding agents (`workflows_version`, `workflows_health`, `workflows_ready`) |
19
- | Serve | `workflows-serve` | HTTP server (`/health`, `/ready`, `/version`, `/openapi.json`); binds `127.0.0.1` by default, no auth |
12
+ | CLI | `workflows` | init, validate, graph (render), run (--context/--input/--idempotency-key), runs list/show/cancel/resume/events, nodes list/show, sessions list/pull, machines list/status, lanes list/probe, daemon start/status/stop, memos list/clear, resume (interrupted-run restore), serve, repair (+ version, health, info) |
13
+ | MCP | `workflows-mcp` | stdio MCP server for coding agents (7 tools incl. workflows_validate, workflows_run, workflows_runs_list, workflows_lanes_list) |
14
+ | Serve | `workflows-serve` (or `workflows serve`) | HTTP server (`/health`, `/ready`, `/version`, authenticated `/trigger`, `/openapi.json`); binds `127.0.0.1` by default; `/trigger` requires `WORKFLOWS_API_KEY` + Bearer token |
20
15
  | SDK | `./sdk` (`@hasna/workflows/sdk`) | importable module surface (exports `WorkflowsService`, `createWorkflowsService`, `createRequestHandler`, `workflowsTools`, `callWorkflowTool`) |
21
16
 
22
17
  All three bins answer `--version` / `--help` before binding or serving.
23
18
 
24
- The SDK is hand-authored to the OpenAPI document served at
25
- `/openapi.json` — there is no code-generated client and no API-key auth in
26
- 0.1.0. (`hasna.contract.json` carries the fleet-mandated `generatedFrom`
27
- pointer naming that API document for service-class SDK surfaces.)
19
+ ## The graph language (v1)
20
+
21
+ A workflow is a JSON graph with five node types — `start`, `step`, `decision`,
22
+ `while`, `end` — one `start`, at least one `end`, explicit edges only
23
+ (`next`/`then`/`else`), and no explicit cycles: repetition lives in the `while`
24
+ node's condition, which is REQUIRED to carry a finite `maxIterations` bound.
25
+ `validate` reports every rule violation with a dotted path. Conditions are a
26
+ bounded expression language (comparisons, `and`/`or`/`not`, parens, dotted
27
+ paths like `steps.build.exitCode`, and the loop counter `i`).
28
+
29
+ ```json
30
+ {
31
+ "name": "retry-until-green",
32
+ "version": "1.0.0",
33
+ "nodes": [
34
+ { "id": "start", "type": "start", "next": "w" },
35
+ { "id": "w", "type": "while", "condition": "steps.check.ok != true",
36
+ "body": ["work", "check"], "maxIterations": 5, "next": "done" },
37
+ { "id": "work", "type": "step", "lane": "claude", "prompt": "fix it" },
38
+ { "id": "check", "type": "step", "command": "bun test" },
39
+ { "id": "done", "type": "end" }
40
+ ]
41
+ }
42
+ ```
43
+
44
+ ## Execution model
45
+
46
+ - **Store**: exactly three SQLite tables — `runs`, `run_nodes`, `memos`
47
+ (input-hash memoization across runs).
48
+ - **Session WAL**: append-only JSONL journal with per-entry sha256 checksums;
49
+ torn tails are truncated and reported on replay.
50
+ - **Torn-run repair**: a run left `running` with no live claim is marked
51
+ `interrupted` (attempts + 1, up to a bound) or failed; `repair` exposes it.
52
+ An interrupted run continues from its durable cursor either via the daemon
53
+ (which dispatches interrupted runs) or via top-level `resume <run-id>`,
54
+ which restores it and reuses memoized node outputs.
55
+ - **Daemon**: fencing-tokened, expiring, WAL-recorded claims; heartbeat and
56
+ release are fencing-checked; the reaper expires stale leases, repairs torn
57
+ runs, dispatches pending + interrupted runs, and advances each run ONE step
58
+ per bounded cycle (maxDispatchPerCycle / maxStepsPerCycle / maxCycles /
59
+ maxIterations — every invocation carries a finite budget).
60
+ - **Secrets write-gate**: no node output, run result, or context containing a
61
+ credential-shaped value is ever persisted; the write is refused with the
62
+ path and detector named.
63
+ - **Lanes**: exactly four adapters — claude (@anthropic-ai/claude-agent-sdk),
64
+ codex (@openai/codex-sdk), cursor (@cursor/sdk, local mode), grok (no xAI
65
+ Grok SDK exists on npm — measured; local grok CLI). Each falls back to its
66
+ local CLI and reports LANE_DEPENDENCY_MISSING (exit 127) when neither
67
+ substrate exists.
28
68
 
29
69
  ## Usage
30
70
 
31
71
  ```bash
32
72
  workflows --version
33
- workflows health --json
73
+ workflows init # creates workflows/ + sessions/ + workflows.db and scaffolds a sample graph
74
+ workflows validate graph.json
75
+ workflows graph graph.json # render (text | --format dot | --format json)
76
+ workflows run graph.json --context '{"repo":"x"}' --input go=yes --idempotency-key k1
77
+ workflows runs list
78
+ workflows runs show <run-id>
79
+ workflows runs events <run-id> # the run's WAL event stream
80
+ workflows nodes show <run-id> <node-id>
81
+ workflows sessions pull # session WAL state (entries, torn, live claims)
82
+ workflows machines status # this machine's store/WAL/daemon status
83
+ workflows lanes probe claude # wired-vs-not-ready-with-reason maturity check
84
+ workflows resume <run-id> # restore an INTERRUPTED run from its durable cursor
85
+ workflows daemon start --once # or a continuous reap loop
86
+ workflows memos clear --yes
87
+ workflows serve # HTTP server (same as workflows-serve)
34
88
  workflows-mcp # stdio MCP server
35
89
  workflows-serve # HTTP server, port from HASNA_WORKFLOWS_PORT (default 8790)
36
90
  ```
@@ -48,7 +102,10 @@ console.log(svc.health());
48
102
  |---|---|---|
49
103
  | `HASNA_WORKFLOWS_PORT` / `WORKFLOWS_PORT` | serve port | 8790 |
50
104
  | `HASNA_WORKFLOWS_HOST` / `WORKFLOWS_HOST` | serve bind host | 127.0.0.1 |
51
- | `HASNA_WORKFLOWS_DATA_DIR` / `WORKFLOWS_DATA_DIR` | data directory (reserved; no store in 0.1.0) | `~/.hasna/workflows` |
105
+ | `HASNA_WORKFLOWS_DATA_DIR` / `WORKFLOWS_DATA_DIR` | data directory | `~/.hasna/workflows` |
106
+
107
+ The server data backend is sqlite (default) or postgresql when
108
+ `HASNA_WORKFLOWS_DATABASE_URL` is set.
52
109
 
53
110
  ## License
54
111