@decidio/sdk 0.1.6 → 0.1.8
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 +72 -22
- package/dist/cli.js +512 -110
- package/dist/guard.d.ts +2 -0
- package/dist/guard.js +5 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +20 -0
- package/dist/resume.js +38 -8
- package/openapi.yaml +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -11,22 +11,29 @@ npx @decidio/sdk quickstart
|
|
|
11
11
|
One command, guided: it registers a fresh agent (key generated locally), gates a demo action
|
|
12
12
|
with the same one line you'll use on your real function, routes it to a human — **you** — lets
|
|
13
13
|
you approve right there (or from your Decidio app), executes on approval, then downloads the
|
|
14
|
-
sealed Authority Receipt and verifies it offline in front of you
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
sealed Authority Receipt and verifies it offline in front of you, pinned to your workspace's
|
|
15
|
+
issuer. It mints a **7-day** tour token (`init` mints 90-day tokens — different jobs, different
|
|
16
|
+
lifetimes) and ends by offering to clean itself up (`quickstart cleanup` works later too).
|
|
17
|
+
Sign in when prompted. No config: with no `DECIDIO_API_URL` set it targets the hosted synthetic
|
|
18
|
+
sandbox. Headless, the tour **stops at the routed decision** — approving is a human act, so it
|
|
19
|
+
prints the approve command and exits rather than approve its own request (CI can pass
|
|
20
|
+
`--auto-approve-demo`, which labels that authority as automated).
|
|
17
21
|
|
|
18
22
|
## Quickstart — seven steps to your first sealed receipt
|
|
19
23
|
|
|
20
24
|
Under 30 minutes, no help needed. You'll need Node 20.6+, a terminal, and a Decidio workspace
|
|
21
25
|
(request one at [decidioai.com](https://decidioai.com/#early-access) — the hosted sandbox is
|
|
22
|
-
synthetic data, safe to experiment in).
|
|
26
|
+
synthetic data, safe to experiment in). Lab workspaces have a **governed-action allowance**
|
|
27
|
+
(currently 30 actions/hour); hitting it raises a typed `DecidioRateLimitError` naming the limit
|
|
28
|
+
and reset time — nothing is routed or executed — and `tokens list` shows your remaining
|
|
29
|
+
allowance any time.
|
|
23
30
|
|
|
24
31
|
**PowerShell users** — the equivalents for every Bash idiom used below:
|
|
25
32
|
|
|
26
33
|
```powershell
|
|
27
34
|
mkdir decidio-quickstart; cd decidio-quickstart # instead of mkdir ... && cd ...
|
|
28
35
|
$env:DECIDIO_API_URL = "https://decidio-api.onrender.com" # instead of export NAME=value
|
|
29
|
-
$env:
|
|
36
|
+
$env:DECIDIO_AGENT_ID = "my-agent"; npx @decidio/sdk init
|
|
30
37
|
# instead of VAR=value npx ... (inline env)
|
|
31
38
|
```
|
|
32
39
|
|
|
@@ -37,13 +44,15 @@ mkdir decidio-quickstart && cd decidio-quickstart
|
|
|
37
44
|
npm install @decidio/sdk
|
|
38
45
|
```
|
|
39
46
|
|
|
40
|
-
**2.
|
|
47
|
+
**2. Register your agent**
|
|
41
48
|
|
|
42
49
|
```bash
|
|
43
|
-
export DECIDIO_API_URL=https://decidio-api.onrender.com # the hosted sandbox
|
|
44
50
|
npx @decidio/sdk init --unique my-agent # --unique appends a random suffix: collision-proof
|
|
45
51
|
```
|
|
46
52
|
|
|
53
|
+
Every CLI command talks to the hosted sandbox by default and announces its target host on
|
|
54
|
+
stderr each run — set `DECIDIO_API_URL` (env or `.env`) to point at another Decidio instead.
|
|
55
|
+
|
|
47
56
|
`init` signs you into your workspace (email + password, or paste the sign-in link from your
|
|
48
57
|
workspace email), generates the agent's Ed25519 keypair **locally** (only the public `did:key`
|
|
49
58
|
is sent), registers the agent, mints its **floor-limited API token** (limited to the agent runtime — request authorization, poll status, report signed confirmation; it cannot administer the workspace or approve anything — and your workspace session never touches the agent's disk), and writes `.env`.
|
|
@@ -51,7 +60,8 @@ Every later command reads `.env` from this directory automatically.
|
|
|
51
60
|
|
|
52
61
|
What `.env` contains after a successful init: `DECIDIO_API_URL`, `DECIDIO_AGENT_ID`,
|
|
53
62
|
`DECIDIO_AGENT_DID` + `DECIDIO_AGENT_KEY` (the local keypair — the key is what earns
|
|
54
|
-
`application_confirmed` evidence later), `DECIDIO_API_TOKEN` (the floor-limited agent token
|
|
63
|
+
`application_confirmed` evidence later), `DECIDIO_API_TOKEN` (the floor-limited agent token —
|
|
64
|
+
90 days by default, `--expires-days N` to change),
|
|
55
65
|
`DECIDIO_WORKSPACE_ID`, and `DECIDIO_WEBHOOK_SECRET` (operator deployments only). Pick any
|
|
56
66
|
agent name — if it's already taken in your workspace, `init` stops cleanly and suggests a
|
|
57
67
|
fresh one (or pass `--unique` to auto-append a random suffix — collision-proof for shared
|
|
@@ -88,11 +98,9 @@ node --env-file=.env quickstart.mjs
|
|
|
88
98
|
A brand-new agent matches **no** auto-approve rule, so Decidio **routes every request to a
|
|
89
99
|
human by default** — that is the point: nothing executes without either a named policy rule or
|
|
90
100
|
a person. (Routing-by-default is distinct from a policy **block**, which refuses the action
|
|
91
|
-
outright — no human can approve a blocked request.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
named rule auto-approves amounts under $1M when the request carries the agent's signed
|
|
95
|
-
identity proof, so even this $86k example would proceed there.)
|
|
101
|
+
outright — no human can approve a blocked request. Policy `proceed` rules — named auto-approve
|
|
102
|
+
for requests carrying the agent's signed identity proof — are configured per workspace by its
|
|
103
|
+
owner.) The script prints the decision id and waits.
|
|
96
104
|
|
|
97
105
|
**5. Approve it** — in a second terminal (same directory; replace `<decisionId>` with the id
|
|
98
106
|
step 4 printed — angle brackets are placeholders, never typed literally). Approvals are a
|
|
@@ -122,8 +130,13 @@ implementation as the standalone `@decidio/verify`). The receipt is a W3C Verifi
|
|
|
122
130
|
Credential: signature and content binding verify with no Decidio account and no network — the
|
|
123
131
|
evidence is yours, not ours. To also prove *who* issued it, pin your workspace's issuer:
|
|
124
132
|
`npx @decidio/sdk verify --issuer <did:key:...> receipt.json` (the DID is shown in your app's
|
|
125
|
-
record verify panel
|
|
126
|
-
you
|
|
133
|
+
record verify panel — or simply read it off the `receipt` command's output, which prints your
|
|
134
|
+
workspace's issuer DID from the authenticated response so you never have to hunt for it).
|
|
135
|
+
|
|
136
|
+
One receipt proves itself. Pass several files and their **ordering** is verified too: the first
|
|
137
|
+
file is the anchor and each subsequent receipt must follow it, so verifying any consecutive
|
|
138
|
+
*segment* works — you are told whether the segment starts at your workspace's genesis or
|
|
139
|
+
mid-history, and a set spanning two different issuers is refused outright.
|
|
127
140
|
|
|
128
141
|
What the credential contains, honestly: the sealed **authority decision** — who decided, what
|
|
129
142
|
was authorized, when, under which policy. It seals at decision time and is immutable — which is
|
|
@@ -136,6 +149,10 @@ The server caps the evidence at the weaker `agent_asserted`, and the SDK warns a
|
|
|
136
149
|
time.) Immutable seal + accruing evidence is the design, not an omission — corrections and
|
|
137
150
|
later facts supersede, they never rewrite.
|
|
138
151
|
|
|
152
|
+
One sharing note: a receipt is **not a secret, but it is not metadata-free** — it names the
|
|
153
|
+
action, amount limits, policy, agent and issuer identifiers, and the decision reason. Share it
|
|
154
|
+
with auditors and counterparties deliberately, the way you would any business record.
|
|
155
|
+
|
|
139
156
|
**7. Prove a replay is rejected:**
|
|
140
157
|
|
|
141
158
|
```bash
|
|
@@ -168,15 +185,36 @@ waiting: it parks its call arguments agent-side (`.decidio-pending/` by default
|
|
|
168
185
|
stores none of your downstream payload) and throws `DecidioSuspendedError`. The process may
|
|
169
186
|
exit. Two ways the parked action resumes when a human decides:
|
|
170
187
|
|
|
171
|
-
**The worker (self-serve — start here).**
|
|
188
|
+
**The worker (self-serve — start here).** No inbound URL, no shared secrets, and it resumes work
|
|
189
|
+
the current process never started. Here is a complete `agent.mjs` you can run:
|
|
172
190
|
|
|
173
191
|
```js
|
|
174
192
|
import { guard } from "@decidio/sdk";
|
|
175
|
-
|
|
193
|
+
|
|
194
|
+
const payInvoiceRaw = async (invoice) => ({ paid: true, id: invoice.id });
|
|
195
|
+
|
|
196
|
+
// Declare the action name so the wrapper registers at LOAD time, not on first call —
|
|
197
|
+
// that is what lets a restarted process resume actions approved while it was down.
|
|
198
|
+
const payInvoice = guard.protect(
|
|
199
|
+
payInvoiceRaw,
|
|
200
|
+
(invoice) => ({ action: "payInvoice", amount: invoice.amount, scope: "Invoice" }),
|
|
201
|
+
{ action: "payInvoice" },
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
guard.worker(); // polls Decidio, re-executes parked actions on approval, one execution each
|
|
205
|
+
|
|
206
|
+
// New work suspends immediately; approvals land later, through the same worker.
|
|
207
|
+
try { await payInvoice({ id: "INV-1", amount: 86_000 }); }
|
|
208
|
+
catch (e) { console.log(e.name); } // DecidioSuspendedError — expected, not a failure
|
|
176
209
|
```
|
|
177
210
|
|
|
178
|
-
|
|
179
|
-
|
|
211
|
+
Run it with `node --env-file=.env agent.mjs`, approve from another terminal, and the running
|
|
212
|
+
worker executes it. Kill the process, restart it, then approve: it still executes, because the
|
|
213
|
+
action was registered at load. **If you can't declare the name at wrap time** (a dynamic
|
|
214
|
+
`describe`), register the raw function explicitly at startup instead —
|
|
215
|
+
`guard.register("payInvoice", payInvoiceRaw)` — before calling `guard.worker()`. Without one of
|
|
216
|
+
those two, a cold worker has an empty registry and reports `no_handler` (the parked action is
|
|
217
|
+
kept, not lost, and the message names the exact fix).
|
|
180
218
|
|
|
181
219
|
**The signed webhook (operator deployments).** Decidio POSTs a signed verdict to your agent's
|
|
182
220
|
`resumeUrl`; the handler verifies the HMAC signature fail-closed, then re-runs your function:
|
|
@@ -198,6 +236,12 @@ your action succeeds but the process dies *before* the entry is cleared, the cla
|
|
|
198
236
|
(robust crash-recovery of stale claims is on the roadmap), so make your downstream action
|
|
199
237
|
idempotent if you need exactly-once under crashes.
|
|
200
238
|
|
|
239
|
+
**Parked arguments must be JSON-serializable.** A suspended action is signed and then written to
|
|
240
|
+
disk as JSON, so values that don't survive `JSON.stringify` round-tripping — `Date`, `Map`,
|
|
241
|
+
`undefined`, `NaN`, class instances with custom `toJSON` — come back changed and fail the
|
|
242
|
+
integrity check on resume (a refusal, never a wrong execution). Pass plain data; rehydrate
|
|
243
|
+
inside your function.
|
|
244
|
+
|
|
201
245
|
**Payload integrity.** When a routed action is parked, the SDK signs its arguments (bound to the
|
|
202
246
|
decision id) with your agent key; on resume it **refuses to execute** if the parked payload was
|
|
203
247
|
modified, its signature stripped, or the file swapped into another decision's slot. That defends
|
|
@@ -227,13 +271,19 @@ imports none of them. Each adapter's shipped `.d.ts` header documents its wiring
|
|
|
227
271
|
`npx @decidio/sdk <cmd>`:
|
|
228
272
|
|
|
229
273
|
- `quickstart` — the guided two-minute tour (gate → approve → execute → proof)
|
|
230
|
-
- `init [agentId] [--unique]` — sign in, register, mint the agent token, write `.env` (+ `.gitignore` entries)
|
|
274
|
+
- `init [agentId] [--unique] [--force] [--expires-days N]` — sign in, register, mint the agent token, write `.env` (+ `.gitignore` entries). Refuses to overwrite a *different* agent's key in this directory; `--force` backs the old `.env` up first.
|
|
231
275
|
- `doctor` — config, connectivity, and what your current token can do
|
|
232
|
-
- `approvals` / `approvals approve|reject <id> [reason]` — the human side, from your terminal
|
|
276
|
+
- `approvals [--mine] [--json]` / `approvals approve|reject <id> [reason]` — the human side, from your terminal (the list is workspace-wide; `--mine` narrows it to this directory's agent)
|
|
233
277
|
- `receipt <id>` — download a sealed decision's Authority Receipt to a `.json` file
|
|
234
|
-
- `verify [--issuer <did>] <file>...` — verify receipts offline (the canonical verifier; the standalone `@decidio/verify` package is the same implementation, for auditors who want zero Decidio dependency)
|
|
278
|
+
- `verify [--issuer <did>] <file>...` — verify receipts offline (the canonical verifier; the standalone `@decidio/verify` package is the same implementation, for auditors who want zero Decidio dependency). Unknown flags are refused, never ignored.
|
|
279
|
+
- `tokens list` / `tokens revoke <jti>` — see and kill agent tokens (values are never re-shown; the jti is the revocation handle). Each row carries its status — `active`, `expired`, or `REVOKED <date>` — so the list confirms the revocations it performs; re-revoking is an honest no-op (exit 1)
|
|
280
|
+
- `quickstart cleanup` — revoke the tour's token and delete its local credentials. What stays, honestly: sealed records (permanent by design) and the agent's registration row (inert without key or token; server-side deregistration is on the roadmap)
|
|
235
281
|
- `dev [--target URL]` — local relay for the resume webhook (operator setups)
|
|
236
282
|
|
|
283
|
+
The CLI's stream contract: **stdout carries results only** (safe to pipe — `--json` output is
|
|
284
|
+
pure JSON); errors, usage guidance, and the per-run target-host announcement go to **stderr**.
|
|
285
|
+
Exit codes: 0 success · 1 failure or honest no-op · 2 usage error.
|
|
286
|
+
|
|
237
287
|
Commands that administer your workspace (`init`, `approvals`, `receipt`) use a **session**
|
|
238
288
|
sign-in held in memory for that run. What lands on disk in `.env`: the agent's floor-limited
|
|
239
289
|
API token, its locally-generated private signing key, and a webhook secret (used only in
|