@hasna/workflows 0.1.4 → 0.2.1
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 +180 -98
- package/dist/agent-tools.js +554 -1418
- package/dist/cli/index.js +4120 -2474
- package/dist/handlers.js +3339 -55
- package/dist/index.js +2372 -1253
- package/dist/mcp/index.js +1738 -1744
- package/dist/sdk.js +1620 -0
- package/dist/serve/admin.js +4291 -0
- package/dist/serve/index.js +3392 -1381
- package/dist/service.js +2134 -1165
- package/hasna.contract.json +17 -17
- package/package.json +16 -13
- package/types/agent-tools.d.ts +3 -17
- package/types/client-error.d.ts +4 -0
- package/types/client-tools.d.ts +4 -0
- package/types/client.d.ts +60 -0
- package/types/daemon.d.ts +15 -9
- package/types/db/postgres-store.d.ts +54 -0
- package/types/graph.d.ts +6 -0
- package/types/handlers.d.ts +2 -1
- package/types/identity.d.ts +7 -0
- package/types/lanes/codex.d.ts +0 -6
- package/types/lanes/types.d.ts +16 -3
- package/types/openapi.d.ts +7 -0
- package/types/paths.d.ts +10 -1
- package/types/sdk/generated-api.d.ts +161 -0
- package/types/sdk.d.ts +6 -0
- package/types/serve/admin.d.ts +2 -0
- package/types/service.d.ts +75 -4
- package/types/session.d.ts +7 -8
- package/types/setup.d.ts +71 -0
- package/types/store.d.ts +30 -0
- package/types/tool-definitions.d.ts +18 -0
- package/types/types.d.ts +8 -0
- package/types/version.d.ts +1 -0
- package/types/wal.d.ts +9 -1
package/README.md
CHANGED
|
@@ -1,112 +1,194 @@
|
|
|
1
1
|
# @hasna/workflows
|
|
2
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
|
-
"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
|
-
}
|
|
3
|
+
Workflows executes bounded graphs and records their runs, nodes and results. The CLI,
|
|
4
|
+
stdio MCP server and `@hasna/workflows/sdk` use the hosted HTTP API. Their default
|
|
5
|
+
authority is `https://api.hasna.com/workflows/v1`. A missing credential or an
|
|
6
|
+
unreachable service fails visibly; clients never create a local application database.
|
|
7
|
+
|
|
8
|
+
## Set up with your agent
|
|
9
|
+
|
|
10
|
+
Copy this prompt to your agent:
|
|
11
|
+
|
|
12
|
+
> Install the published `@hasna/workflows` package. Connect its `workflows-mcp`
|
|
13
|
+
> stdio server using this harness's supported MCP configuration. Target
|
|
14
|
+
> `https://api.hasna.com/workflows/v1` and use this station's own supported
|
|
15
|
+
> credential resolver. Run `workflows setup` with your credential owner's environment
|
|
16
|
+
> projection, then verify `workflows whoami`, `workflows ready --json` and
|
|
17
|
+
> `workflows runs list --json`, then call `workflows_ready` through the harness.
|
|
18
|
+
> Finish only when those real consumers work. Never copy a credential from another
|
|
19
|
+
> station or fall back to a local database.
|
|
20
|
+
|
|
21
|
+
Raw setup is also available:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm install --prefix <retained-version-runtime> @hasna/workflows
|
|
25
|
+
workflows --help
|
|
26
|
+
workflows setup
|
|
27
|
+
workflows whoami
|
|
28
|
+
workflows ready --json
|
|
29
|
+
workflows runs list --json
|
|
42
30
|
```
|
|
43
31
|
|
|
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
|
-
workflows
|
|
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)
|
|
88
|
-
workflows-mcp # stdio MCP server
|
|
89
|
-
workflows-serve # HTTP server, port from HASNA_WORKFLOWS_PORT (default 8790)
|
|
32
|
+
The shared `@hasna/contracts` resolver owns credentials. It supports the canonical
|
|
33
|
+
`HASNA_WORKFLOWS_API_KEY` / `HASNA_WORKFLOWS_API_URL` environment names and the
|
|
34
|
+
`WORKFLOWS_` aliases, its owner-only disk tier at
|
|
35
|
+
`~/.hasna/workflows/config/credentials`, documented Hasna home/profile overrides,
|
|
36
|
+
and its supported macOS Keychain tier. Keep API keys out of commands, logs and MCP
|
|
37
|
+
configuration. A credential bound to one authority is refused at another authority.
|
|
38
|
+
Legacy unbound internal credentials stay bound to the Hasna gateway.
|
|
39
|
+
|
|
40
|
+
`workflows setup` reads a key projected into `HASNA_WORKFLOWS_API_KEY`, verifies
|
|
41
|
+
one authenticated API read, writes owner-only credentials atomically, and verifies
|
|
42
|
+
another read through the disk tier. It refuses a selected override, pointer or
|
|
43
|
+
profile. Replacing different credentials requires `--replace`; the exact original
|
|
44
|
+
is preserved and read back before replacement. `workflows whoami` works offline and
|
|
45
|
+
reports the authority, credential source and calling agent without printing a key.
|
|
46
|
+
|
|
47
|
+
For personal sign-in, `workflows login` verifies and stores a key projected by
|
|
48
|
+
your credential owner into `HASNA_WORKFLOWS_API_KEY`. A supplied key can also be
|
|
49
|
+
piped into `workflows login --with-api-key`; never put a key in arguments.
|
|
50
|
+
This API-key-only server does not offer a browser or device sign-in flow.
|
|
51
|
+
`workflows logout` removes only the active credential that login stored,
|
|
52
|
+
preserves its readable original and keeps the API URL. It leaves setup-owned,
|
|
53
|
+
environment, pointer and other-profile credentials with their owners. Environment
|
|
54
|
+
credentials still set produce a non-zero result and name their source.
|
|
55
|
+
A supplied key remains valid on the server until its credential owner revokes it;
|
|
56
|
+
`--revoke` signs out locally and reports that individual-key revocation is unavailable.
|
|
57
|
+
|
|
58
|
+
An explicit URL can include or omit `/v1`; the client adds it exactly once:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
workflows --api-url https://api.hasna.com/workflows/v1 runs list --json
|
|
90
62
|
```
|
|
91
63
|
|
|
64
|
+
For self-hosting, supply your own HTTPS URL and its paired credential using the
|
|
65
|
+
resolver. Loopback HTTP is permitted for isolated development. Remote HTTP and
|
|
66
|
+
redirects carrying credentials are refused.
|
|
67
|
+
|
|
68
|
+
## HTTP SDK
|
|
69
|
+
|
|
70
|
+
The SDK works in Node and Bun:
|
|
71
|
+
|
|
92
72
|
```ts
|
|
93
|
-
import {
|
|
73
|
+
import { createWorkflowsClient } from "@hasna/workflows/sdk";
|
|
94
74
|
|
|
95
|
-
const
|
|
96
|
-
|
|
75
|
+
const workflows = createWorkflowsClient();
|
|
76
|
+
const readiness = await workflows.ready();
|
|
77
|
+
const runs = await workflows.listRuns({ limit: 100 });
|
|
97
78
|
```
|
|
98
79
|
|
|
99
|
-
|
|
80
|
+
Its typed operations are generated from the server's OpenAPI document using
|
|
81
|
+
`@hasna/contracts`, with the same credential-bound transport as the CLI and MCP.
|
|
82
|
+
`bun run check:sdk` refuses stale generated code; `bun run generate:sdk` updates it.
|
|
100
83
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
84
|
+
`createWorkflowsClient({ apiUrl })` provides an explicit authority override. Its
|
|
85
|
+
run API includes `triggerRun`, `getRun`, `listNodes`, `events`, `cancelRun` and
|
|
86
|
+
`resumeRun`. Trigger idempotency keys cover the entire stored history and bind to
|
|
87
|
+
the graph, context and cycle budget. Reusing a key for a different request returns
|
|
88
|
+
HTTP 409. Run context cannot contain the reserved `__wf` or `steps` fields.
|
|
89
|
+
|
|
90
|
+
A step's optional `cwd` names its working directory on the server executing the
|
|
91
|
+
workflow. It applies to shell commands and model lanes; prefer an absolute path.
|
|
92
|
+
Codex prompts keep their native repository, sandbox and approval defaults. Supply
|
|
93
|
+
`cwd` for work in an existing trusted repository. For a prompt that needs no file
|
|
94
|
+
changes and may run outside a repository, explicitly set `codexMode: "read-only"`:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { createWorkflowsClient, type WorkflowGraph } from "@hasna/workflows/sdk";
|
|
98
|
+
|
|
99
|
+
const workflows = createWorkflowsClient();
|
|
100
|
+
const graph: WorkflowGraph = {
|
|
101
|
+
name: "read-only-answer", version: "1",
|
|
102
|
+
nodes: [
|
|
103
|
+
{ id: "start", type: "start", next: "answer" },
|
|
104
|
+
{ id: "answer", type: "step", lane: "codex", codexMode: "read-only",
|
|
105
|
+
prompt: "Return the requested answer without changing files.", next: "end" },
|
|
106
|
+
{ id: "end", type: "end" },
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
await workflows.triggerRun(graph, {}, { idempotencyKey: "read-only-answer-1" });
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This explicit mode uses Codex's read-only sandbox, permits a nonrepository
|
|
113
|
+
directory and refuses approval escalation. It applies only to Codex prompt steps;
|
|
114
|
+
shell commands cannot select it. An empty Codex response fails the step even when
|
|
115
|
+
the native process exits successfully. Memoization distinguishes the working
|
|
116
|
+
directory, lane and execution mode.
|
|
117
|
+
|
|
118
|
+
## MCP
|
|
119
|
+
|
|
120
|
+
Register `workflows-mcp` as a stdio command in Codex, Claude Code, OpenCode, Sumi,
|
|
121
|
+
Cursor or another MCP harness. Use the harness's supported configuration writer;
|
|
122
|
+
keep existing servers and machine-owned credentials intact. Initialization,
|
|
123
|
+
`tools/list`, graph validation and version inspection require no credential.
|
|
124
|
+
Hosted tools resolve this station's credential when invoked. No token belongs in
|
|
125
|
+
the harness configuration.
|
|
126
|
+
`--stdio` is accepted. Run tools require a stable `idempotencyKey`. Each tool accepts
|
|
127
|
+
an optional `agent`; otherwise identity comes from the native harness context or
|
|
128
|
+
the station. CLI and SDK callers may also set their agent explicitly.
|
|
129
|
+
|
|
130
|
+
## Server and migration
|
|
131
|
+
|
|
132
|
+
`workflows-serve` owns execution and persistence. `HASNA_WORKFLOWS_HOST`,
|
|
133
|
+
`HASNA_WORKFLOWS_PORT`, `HASNA_WORKFLOWS_DATA_DIR` and
|
|
134
|
+
`HASNA_WORKFLOWS_API_KEY` configure the server. Set
|
|
135
|
+
`HASNA_WORKFLOWS_DATABASE_URL` to its PostgreSQL database and optionally
|
|
136
|
+
`HASNA_WORKFLOWS_DATABASE_SCHEMA` (default `workflows`). Alias names remain supported;
|
|
137
|
+
database URL aliases must agree. Storage and mode environment selectors never
|
|
138
|
+
enable local fallback. Run `workflows-serve init-db` explicitly to create a fresh
|
|
139
|
+
schema; normal startup and readiness never migrate storage.
|
|
140
|
+
Use durable storage for the data directory and one deployed executor; ephemeral
|
|
141
|
+
container storage is unsuitable. Model lanes require the selected harness's
|
|
142
|
+
native subscription on the executor. They do not inherit paid model API keys.
|
|
143
|
+
|
|
144
|
+
When the server sits behind an authenticated gateway, set
|
|
145
|
+
`HASNA_WORKFLOWS_ORIGIN_AUTH` to the gateway's scoped origin identity. It must be
|
|
146
|
+
32 to 256 ASCII letters, digits, underscores or hyphens. All API routes, including
|
|
147
|
+
legacy aliases, then require `x-hasna-origin-auth`; only unversioned `/health` and
|
|
148
|
+
`/ready` remain public. The origin identity never replaces caller Bearer authentication.
|
|
149
|
+
|
|
150
|
+
The versioned API serves health, readiness, version, graph validation, triggers,
|
|
151
|
+
run details, nodes, events, cancellation, resume and inspection routes under `/v1`.
|
|
152
|
+
Legacy unversioned server routes remain aliases. Readiness returns HTTP 503 unless
|
|
153
|
+
authentication and the actual storage schema are available. Cancellation fences
|
|
154
|
+
late results. Resume executes the pinned graph from the saved cursor. A timeout
|
|
155
|
+
whose cancellation is unconfirmed cannot automatically retry or resume.
|
|
156
|
+
PostgreSQL advisory ownership is shared between executors. A lost connection
|
|
157
|
+
leaves a durable execution hold for operator reconciliation; it never silently
|
|
158
|
+
restarts a potentially active command. Deploy one executor with its preserved
|
|
159
|
+
journal so that all event reads use the same authoritative history.
|
|
160
|
+
|
|
161
|
+
The server stores runs, node history and memo results in three PostgreSQL tables,
|
|
162
|
+
with an append-only session journal in its durable data directory. Journal writers
|
|
163
|
+
serialize through a SQLite mutex that contains no application tables. Before torn-tail
|
|
164
|
+
repair, the exact original is copied and read back at
|
|
165
|
+
`session.wal.preserved-<sha256>`. The required `bun run test:pg` gate uses a fresh
|
|
166
|
+
`WORKFLOWS_TEST_DATABASE_URL` and proves actual storage and HTTP execution. It fails
|
|
167
|
+
when the database is not configured. The ordinary test suite reports these cases
|
|
168
|
+
as skipped when no test database is supplied.
|
|
169
|
+
|
|
170
|
+
Existing embedded applications import `createWorkflowsService` from
|
|
171
|
+
`@hasna/workflows` and require Bun. The `./sdk` export now denotes the HTTP client.
|
|
172
|
+
Server-only maintenance commands use `workflows-serve admin ...`; operator
|
|
173
|
+
maintenance never selects the client's hosted credentials or changes its target.
|
|
174
|
+
|
|
175
|
+
An embedded server example:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { createWorkflowsService } from "@hasna/workflows";
|
|
179
|
+
const service = createWorkflowsService({ storageBackend: "sqlite", dataDir: "/srv/workflows", apiKey: process.env.HASNA_WORKFLOWS_API_KEY });
|
|
180
|
+
console.log(service.health());
|
|
181
|
+
```
|
|
106
182
|
|
|
107
|
-
|
|
108
|
-
`
|
|
183
|
+
A workflow graph contains one start node, steps or decisions, optional bounded
|
|
184
|
+
while loops, and an end node. `workflows init workflow.json` writes a sample graph
|
|
185
|
+
without creating application state. `workflows validate workflow.json` and
|
|
186
|
+
`workflows graph workflow.json` work offline. `workflows run workflow.json`
|
|
187
|
+
executes on the configured server, and `workflows runs events <run-id>` reads its
|
|
188
|
+
durable execution history.
|
|
109
189
|
|
|
110
|
-
|
|
190
|
+
Lanes support Claude, Codex, Cursor in local mode, and a Grok CLI when installed.
|
|
191
|
+
A wired substrate is distinct from verified sign-in and usable model capacity;
|
|
192
|
+
missing substrate or authentication fails visibly.
|
|
111
193
|
|
|
112
|
-
|
|
194
|
+
A [Hasna](https://hasna.com) product.
|