foldrun 2.6.0 → 2.8.0

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/LICENSE CHANGED
@@ -1,39 +1,105 @@
1
- foldrun proprietary licence
1
+ # Functional Source License, Version 1.1, ALv2 Future License
2
2
 
3
- Copyright (c) 2026 foldrun. All rights reserved.
3
+ ## Abbreviation
4
4
 
5
- This software, its source code and its documentation are the property of
6
- foldrun. They are licensed, not sold.
5
+ FSL-1.1-ALv2
7
6
 
8
- You may install and run the foldrun packages published to npm (`foldrun`
9
- and `@foldrun/core`) to write, check, run and deploy your own agents,
10
- flows and workspaces, on your own machines and with the foldrun platform.
11
- That includes the copies installing and running need, for your own use:
12
- package caches and mirrors, CI and build machines, container images and
13
- backups.
7
+ ## Notice
14
8
 
15
- You may not, except where the law allows it despite this restriction:
16
- copy, modify, merge, publish, distribute, sublicense, rent or sell the
17
- software or any part of it; reverse engineer, decompile or disassemble it;
18
- or use it to build a product or service that competes with foldrun.
9
+ Copyright 2026 foldrun
19
10
 
20
- What you write with the software (your agents, flows, knowledge and other
21
- files) is yours.
11
+ ## Terms and Conditions
22
12
 
23
- Third-party components the software includes or installs (its npm
24
- dependencies) remain under their own licences.
13
+ ### Licensor ("We")
25
14
 
26
- This licence ends automatically if you break its terms, and you must then
27
- stop using the software.
15
+ The party offering the Software under these Terms and Conditions.
28
16
 
29
- Versions published before 17 October 2026 under the Apache License 2.0
30
- remain available under that licence for those versions only.
17
+ ### The Software
31
18
 
32
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. TO THE EXTENT THE
35
- LAW ALLOWS, IN NO EVENT SHALL FOLDRUN BE LIABLE FOR ANY CLAIM, DAMAGES OR
36
- OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
37
- ITS USE.
19
+ The "Software" is each version of the software that we make available under
20
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
21
+ Conditions with the Software.
38
22
 
39
- Questions: hello@foldrun.io
23
+ ### License Grant
24
+
25
+ Subject to your compliance with this License Grant and the Patents,
26
+ Redistribution and Trademark clauses below, we hereby grant you the right to
27
+ use, copy, modify, create derivative works, publicly perform, publicly display
28
+ and redistribute the Software for any Permitted Purpose identified below.
29
+
30
+ ### Permitted Purpose
31
+
32
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
+ means making the Software available to others in a commercial product or
34
+ service that:
35
+
36
+ 1. substitutes for the Software;
37
+
38
+ 2. substitutes for any other product or service we offer using the Software
39
+ that exists as of the date we make the Software available; or
40
+
41
+ 3. offers the same or substantially similar functionality as the Software.
42
+
43
+ Permitted Purposes specifically include using the Software:
44
+
45
+ 1. for your internal use and access;
46
+
47
+ 2. for non-commercial education;
48
+
49
+ 3. for non-commercial research; and
50
+
51
+ 4. in connection with professional services that you provide to a licensee
52
+ using the Software in accordance with these Terms and Conditions.
53
+
54
+ ### Patents
55
+
56
+ To the extent your use for a Permitted Purpose would necessarily infringe our
57
+ patents, the license grant above includes a license under our patents. If you
58
+ make a claim against any party that the Software infringes or contributes to
59
+ the infringement of any patent, then your patent license to the Software ends
60
+ immediately.
61
+
62
+ ### Redistribution
63
+
64
+ The Terms and Conditions apply to all copies, modifications and derivatives of
65
+ the Software.
66
+
67
+ If you redistribute any copies, modifications or derivatives of the Software,
68
+ you must include a copy of or a link to these Terms and Conditions and not
69
+ remove any copyright notices provided in or with the Software.
70
+
71
+ ### Disclaimer
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
+
77
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
+
81
+ ### Trademarks
82
+
83
+ Except for displaying the License Details and identifying us as the origin of
84
+ the Software, you have no right under these Terms and Conditions to use our
85
+ trademarks, trade names, service marks or product names.
86
+
87
+ ## Grant of Future License
88
+
89
+ We hereby irrevocably grant you an additional license to use the Software under
90
+ the Apache License, Version 2.0 that is effective on the second anniversary of
91
+ the date we make the Software available. On or after that date, you may use the
92
+ Software under the Apache License, Version 2.0, in which case the following
93
+ will apply:
94
+
95
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
96
+ this file except in compliance with the License.
97
+
98
+ You may obtain a copy of the License at
99
+
100
+ http://www.apache.org/licenses/LICENSE-2.0
101
+
102
+ Unless required by applicable law or agreed to in writing, software distributed
103
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
+ specific language governing permissions and limitations under the License.
package/LICENSING.md ADDED
@@ -0,0 +1,101 @@
1
+ # Licensing
2
+
3
+ foldrun is **source-available** under the **Functional Source License,
4
+ Version 1.1, with an Apache 2.0 future licence** (`FSL-1.1-ALv2`). The full
5
+ terms are in [LICENSE](LICENSE); they are the standard FSL text, unchanged,
6
+ and they are what binds. This page explains them in plain English. If the
7
+ two ever disagree, LICENSE wins.
8
+
9
+ ## In one paragraph
10
+
11
+ Use foldrun for anything except selling it, or offering it to others as a
12
+ product or service that competes with foldrun. Personal use and use inside
13
+ your own company are free, at any size. Every version becomes Apache 2.0,
14
+ with no restrictions, two years after it is released.
15
+
16
+ ## What you may do, free
17
+
18
+ - **Use it yourself**: on your laptop, on your own server, for your own
19
+ agents and flows.
20
+ - **Use it inside your company or organisation**, of any size, for your own
21
+ work: your team's agents, your internal automations, your CI.
22
+ - **Read, change and fork the code**, and keep your changes private or
23
+ share them, as long as the result is used for one of the purposes on
24
+ this list.
25
+ - **Teach and research with it** (non-commercial education and research).
26
+ - **Set it up for a client as a consultant or agency**, as long as the
27
+ client is the one using it, for their own purposes, under these same
28
+ terms.
29
+
30
+ ## What needs a commercial licence
31
+
32
+ The licence calls these a *Competing Use*: making foldrun available **to
33
+ others** in a **commercial** product or service that substitutes for
34
+ foldrun, substitutes for a foldrun product or service that existed when that
35
+ version was released, or offers the same or substantially similar
36
+ functionality. For example:
37
+
38
+ - running foldrun, or a modified copy, as a hosted agent platform that other
39
+ people or companies sign up to or pay for;
40
+ - reselling it, white-labelling it, or bundling it into a product you sell
41
+ whose value is what foldrun does;
42
+ - selling access to a managed foldrun instance.
43
+
44
+ If you want to do any of these, or are not sure whether your use counts,
45
+ write to **hello@foldrun.io**. Commercial licences are available.
46
+
47
+ ## The two-year rule
48
+
49
+ Each version is offered under FSL from the day it is released. On the
50
+ second anniversary of that release, that version is **also** available under
51
+ the Apache License 2.0 — irrevocably, for everyone, for any purpose. Newer
52
+ versions are not affected until they reach their own second anniversary.
53
+
54
+ ## Versions released under other terms
55
+
56
+ | Versions | Licence |
57
+ |---|---|
58
+ | released before 17 October 2026 | Apache License 2.0 |
59
+ | released 17 October 2026 up to the first FSL release | the foldrun proprietary licence that shipped in each package |
60
+ | the first FSL release and later | FSL-1.1-ALv2 (this page) |
61
+
62
+ A version keeps the licence it was released under.
63
+
64
+ ## What stays yours
65
+
66
+ What you write with foldrun — your agents, flows, knowledge, skills, tools,
67
+ evals and the outputs of your runs — is yours. This licence covers foldrun's
68
+ code, not your work.
69
+
70
+ ## Name and logo
71
+
72
+ The licence does not give you the foldrun name, logo or other trademarks,
73
+ except to say truthfully where the code came from. A fork you distribute
74
+ needs its own name.
75
+
76
+ ## Third-party code
77
+
78
+ foldrun's dependencies, and anything it installs, stay under their own
79
+ licences.
80
+
81
+ ## Patents
82
+
83
+ Using foldrun for a permitted purpose includes a licence to any foldrun
84
+ patents that use needs. That patent licence ends for anyone who sues claiming
85
+ the software infringes a patent.
86
+
87
+ ## No warranty
88
+
89
+ foldrun is provided as is, with no warranty, and with no liability for
90
+ damages, as LICENSE sets out in full.
91
+
92
+ ## Contributing
93
+
94
+ Contributions are welcome. Before we merge one, we ask you to agree that we
95
+ may release it under these terms and under commercial licences, so the
96
+ project can keep both. We will send the agreement with your first pull
97
+ request.
98
+
99
+ ## Questions
100
+
101
+ hello@foldrun.io. This page is a summary to help you, not legal advice.
package/README.md CHANGED
@@ -146,8 +146,8 @@ declared the same way.
146
146
  | `foldrun storage <verb>` | what a workspace produced: `ls [prefix]`, `cat <path>`, `get <path>` — with when each file was written and which run wrote it. `put <file|folder>...` uploads any files (`--into <folder/>`, `--as <path>` for one), `rm <path>` removes one, and `share`, `shares`, `unshare` manage public links |
147
147
  | `foldrun storage put <file>` | upload a file into a workspace's storage (`--as <path>` names it) — also `rm <path>` |
148
148
  | `foldrun storage share <path>` | a public link to one produced file (`--ttl <days>`, default 7; `--forever`) — also `shares` (`--all`) and `unshare <token>` |
149
- | `foldrun billing` | the account's balance and its recent ledger entries, with what each was for |
150
- | `foldrun billing credit <usd>` | credit added by hand — only on an install without Stripe (self-hosted, dev) |
149
+ | `foldrun billing` | the account's balance and its recent ledger entries, with what each was for — on foldrun's hosted platform (a self-hosted install has no billing) |
150
+ | `foldrun billing credit <usd>` | credit added by hand — on foldrun's hosted platform without Stripe (dev) |
151
151
  | `foldrun billing plans` | the plans and this cycle's credits — also `plan <id>`, `plan cancel`, `plan resume`, `top-up <usd>`, `card` (Stripe's own pages for anything with a card) |
152
152
  | `foldrun account` | the account's defaults: timezone, notify, budget, concurrency — also `set <key> <value>` and `clear <key>` |
153
153
  | `foldrun account providers` | which model providers the account's files use and whether each key still answers (`--check` asks now) |
@@ -234,5 +234,10 @@ wins over the credentials file, so a job never reads one from disk.
234
234
 
235
235
  ## Licence
236
236
 
237
- Proprietary; see [LICENSE](LICENSE). Versions published before 17 October
238
- 2026 were Apache-2.0 and stay so.
237
+ Source-available under the [Functional Source License 1.1, Apache 2.0 future
238
+ licence](LICENSE) (`FSL-1.1-ALv2`). Use it for anything except offering it to
239
+ others as a competing commercial product or service: personal use and use
240
+ inside your own company are free, at any size. Each version becomes Apache 2.0
241
+ two years after its release. [LICENSING.md](LICENSING.md) explains what is
242
+ allowed and what needs a commercial licence (hello@foldrun.io), and which
243
+ licence earlier versions shipped under.
package/bin/foldrun.mjs CHANGED
@@ -15,6 +15,7 @@
15
15
  // foldrun runs what has run lately, across the account
16
16
  // foldrun report <run-id> one run, whole: every step, what it cost, what it wrote
17
17
  // foldrun approvals what is waiting for a person, anywhere in the account
18
+ // foldrun inbox what is waiting on YOU — assigned, started by you, the team's (read, dismiss)
18
19
  // foldrun approve <run-id> release a waiting gate (asks first) — reject refuses it
19
20
  // foldrun stop <run-id> kill a run in flight
20
21
  // foldrun account the account's own defaults — timezone, notify, budget, concurrency, deploy_block, network_enforce
@@ -36,6 +37,9 @@
36
37
  // foldrun agent new <name> one more agent in this workspace — also flow new, tool new (--platform: in the deployed one)
37
38
  // foldrun agent ls the agents deployed in a workspace — also flow ls
38
39
  // foldrun eval new <name> a new eval in a deployed workspace
40
+ // foldrun eval compare <eval> its cases under two to four models, side by side
41
+ // foldrun proposals proposed fixes for repeated failures — show, apply, dismiss
42
+ // foldrun eval grades <eval> what a grader found in the real runs it graded — eval grade <eval> --run <id> grades one
39
43
  // foldrun agent run <name> run one agent once on a platform, no flow
40
44
  // foldrun tool test <name> exercise one tool alone — no model, no run
41
45
  // foldrun hook <verb> ls / add / test / rm — your own code at every tool call and step
@@ -122,6 +126,7 @@ const HELP = `foldrun — agents are just folders
122
126
  foldrun flow rotate-hook <flow> a new webhook URL for a flow; the old one stops at once — asks first, --yes means it
123
127
  foldrun flow set <flow> --step <n|agent> key=value … the step editor: model, effort, retry, timeout, verify, when, case, else, loop, until, each, max, limits, instruction (key= clears) — diff, checked, --dry-run
124
128
  foldrun flow trigger <flow> manual|webhook|schedule the trigger picker (--schedule "<cron>", --timezone <zone>) — diff, checked, --dry-run
129
+ foldrun flow filter <flow> --payload <file|-|json> would this delivery start it? its filter: and the condition that held it back (--to <ws>: the deployed flow); exit 1 when not
125
130
  foldrun flow move-step <flow> --step <n|agent> drag a card: --group <g> runs it beside group g, --after <g> gives it its own group after g (0 = first) — diff, checked, --dry-run
126
131
  foldrun flow copy-step <flow> --step <n|agent>[,<n>…] the steps' markdown on stdout, as the canvas's Copy
127
132
  foldrun flow paste <flow> step markdown from stdin or --file in as new groups (--after <g>, default last) or beside one (--group <g>) — diff, checked, --dry-run
@@ -137,6 +142,11 @@ const HELP = `foldrun — agents are just folders
137
142
  foldrun run <target> run an agent or flow HERE (target: name, or flow:name) — on the platform: flow run / invoke a flow, agent run one agent
138
143
  foldrun eval [name] run one eval, or all of them (--to <workspace>: the deployed evals, run on the platform; --last reads their latest results, --run <id> one run's verdict, running nothing)
139
144
  foldrun eval new <name> a new eval in the deployed workspace, its agent the first one there — edit its cases, then eval <name> --to (--to)
145
+ foldrun eval compare <eval> --models fast,default --to <ws> the cases under 2–4 models side by side (m:effort, --agent, --repeat, --max-usd; --list, --run <id>)
146
+ foldrun eval improve <eval> --to <ws> ask the assistant for a proposed fix from the failures, wait for the draft (--no-wait)
147
+ foldrun proposals --to <ws> proposed fixes (--status ready, --eval) — show|apply|dismiss <id> (apply asks; --yes)
148
+ foldrun eval grades <eval> --to <ws> a grader's findings (trigger: runs): pass rate over --days (30), each graded run (--status fail, --limit); exit 1 on a failure
149
+ foldrun eval grade <eval> --run <id> --to <ws> grade one finished run now, sampled or not; exit 1 unless it passed
140
150
  foldrun promote <run-id> keep a finished run as a regression case in evals/ (--eval <name>, --expect "contains: …" repeatable, --case <name>); a run that went wrong takes --should "what it should have done"
141
151
  foldrun probe <model> live check: can this model hold a tool loop here?
142
152
  foldrun logs [run-id] recent runs in one workspace, or one run's full event trail (--local: this machine's)
@@ -153,6 +163,8 @@ const HELP = `foldrun — agents are just folders
153
163
  foldrun report <run-id> live the live browser view: which agents have a frame; --agent <name> saves the newest as a JPEG (--file <path>|-)
154
164
  foldrun approvals every gate waiting on a person, with its question (--to <workspace> for one)
155
165
  foldrun insights recurring problems found in the runs, with what they cost and what to do (--days, --to, --json)
166
+ foldrun inbox what waits on you: approvals, questions, issues, proposed fixes, your failed runs (--team, --all, --kind, --unread, --dismissed)
167
+ foldrun inbox read|unread|dismiss|restore <id>… mark items in your own view (dismiss sets aside; it still waits where it lives)
156
168
  foldrun issues what went wrong, grouped, open until resolved (--to <workspace>, --all, --status, --json)
157
169
  foldrun issues show|ack|snooze|resolve|reopen <id> one issue — snooze --for 1d or --times 5, --note "…"
158
170
  foldrun issues doctor <id> the run doctor on the issue's newest run, in its workspace: why, and the fix as diffs, saved on yes (--yes, --dry-run, --json)
@@ -278,6 +290,11 @@ Options
278
290
  --on-fail <agent> flow add: who takes the step over when it fails
279
291
  --off flow add: take the pattern off the step instead (fan-out, loop, approval, ask, wait, rescue)
280
292
  --schedule "<cron>" flow trigger: the cron line a schedule fires on (5 fields, or @daily); --timezone <zone> the zone it is read in
293
+ --team, --started, --mine, --all inbox: which bucket (default: assigned to you and started by you)
294
+ --dismissed, --unread inbox: what you set aside; only what you have not read
295
+ --models <m[:effort],…> eval compare: two to four tiers or model ids to compare, each with an optional :effort
296
+ --max-usd <n> eval compare: the spend limit — no run starts once the runs and judges have spent it (default 5)
297
+ --payload <file|-|json> flow filter: the delivery to test — a file, - for stdin, or JSON inline
281
298
  --kind <k> secrets set: file (--file <path>), ssh (--host, --user, --port, --key-file or a prompted password), api (--base-url, --header "Name: value" repeatable, or --basic-user <u> with the password prompted or --basic-password), service-account (--file <key.json>, --scopes, --subject <user to act as>), client-cert (--cert-file, --key-file, --passphrase, --export to put it in the sandbox as files too), identity (--audience: keyless cloud access, no credential stored), m2m (--token-url, --client-id, --scopes; secret prompted)
282
299
  --client <name> connect: run the consent from that OAuth client saved on the platform (secrets clients lists them)
283
300
  --subagent <name> agent link, agent unlink: a worker it delegates to (subagents:)
@@ -385,7 +402,7 @@ if (!command || command === "--help" || command === "-h") {
385
402
  // `--value` as the account's argument and stored an empty secret; `--force
386
403
  // ./dir` swallowed the directory. A flag followed by another flag is also
387
404
  // boolean, so an unlisted switch at least does not eat its neighbour.
388
- const BOOLEAN_FLAGS = new Set(["account", "follow", "force", "oauth2", "wait", "watch", "print", "dry-run", "help", "no-browser", "local", "test", "flat", "yes", "platform", "json", "forever", "all", "check", "new-client", "quiet", "off", "can-ask", "preview", "csv", "failed", "starter", "history", "list", "library", "clear", "security", "changed", "write-baseline", "no-baseline", "rules", "calls", "tree", "tool-error", "stop", "last", "no-pkce", "export", "isolated"]);
405
+ const BOOLEAN_FLAGS = new Set(["account", "follow", "force", "oauth2", "wait", "watch", "print", "dry-run", "help", "no-browser", "local", "test", "flat", "yes", "platform", "json", "forever", "all", "check", "new-client", "quiet", "off", "can-ask", "preview", "csv", "failed", "starter", "history", "list", "library", "clear", "security", "changed", "write-baseline", "no-baseline", "rules", "calls", "tree", "tool-error", "stop", "last", "no-pkce", "export", "isolated", "no-wait", "dismissed", "unread", "team", "started", "mine"]);
389
406
  // Flags said more than once collect into a list: `--tag a --tag b`.
390
407
  const REPEATABLE = new Set(["tag", "expect", "header", "site", "add", "remove", "rule", "authorize-param"]);
391
408
  // `--wait` is a switch everywhere but `flow add <flow> wait`, where it takes
package/docs/agents.md CHANGED
@@ -292,7 +292,7 @@ The parent is unchanged (`subagents: [reader]`). Its model gets a
292
292
  | where it runs | inside the parent's sandbox | a sandbox of its own, started for the job |
293
293
  | tools | its own, cut to the parent's | its own — the parent may hold less |
294
294
  | secrets, network, size, runtime | the parent's | its own file's |
295
- | gives back | its reply | its reply, and the paths of files it changed |
295
+ | gives back | its reply | its reply, and the files it changed, copied into the parent's sandbox |
296
296
  | on the run | lines in the parent's trace | a step of its own after the parent's, marked `subagentOf` |
297
297
  | cost | on the parent's step | on its own step, in the run's total |
298
298
 
@@ -308,10 +308,16 @@ What holds:
308
308
  - **Only the reply comes back.** The reply is still text the parent reads —
309
309
  it can carry an instruction — but it reaches a model whose sandbox never
310
310
  held the page.
311
- - **Files.** What it writes reaches the workspace when its job ends, so the
312
- next step sees it. The parent's own sandbox does not: it was copied in when
313
- the parent started. The reply lists the paths. If both write one path, the
314
- parent, finishing later, wins — as between two steps of a parallel group.
311
+ - **Files.** What it writes reaches the workspace when its job ends, and is
312
+ copied into the parent's sandbox at the same paths before the reply comes
313
+ back — so the parent's model, its `verify: file:` and the next step all see
314
+ it. The reply lists the paths. Up to 4 MiB and 100 files a job are copied
315
+ back; what is larger is listed as not in the parent's sandbox and reaches
316
+ the workspace for the next step only. A file the parent had already
317
+ changed in its own sandbox is not overwritten: the job's version is put
318
+ beside it as `<name>.from-<agent><ext>`, and the reply says so. If both
319
+ write one path, the parent, finishing later, wins — as between two steps of
320
+ a parallel group.
315
321
  - **One level deep.** Its own `subagents:` are not offered to it.
316
322
  - **Bounded by its parent.** A job runs within the parent step's `timeout:`
317
323
  and under two budgets. The sub-agent's own `budget:`: a job holds what is
package/docs/api-usage.md CHANGED
@@ -36,7 +36,7 @@ Every response says which version answered it, in `Foldrun-Version`.
36
36
  - **An unknown version** — a typo, a date that was never released, one
37
37
  retired after its support window — is a `400`, not a silent fallback to
38
38
  current. The body says why in a form code can act on:
39
- `{ "error": "…", "code": "unknown_api_version", "known": ["2026-10-01"] }`
39
+ `{ "error": "…", "code": "unknown_api_version", "known": ["2026-10-01", "2026-10-26"] }`
40
40
  (`code` is `bad_api_version` when the header is not a `YYYY-MM-DD` date).
41
41
  - **What moves the version**: only a change an existing caller would break
42
42
  on — a field removed or renamed, a type changed, a status code changed. A
@@ -46,6 +46,13 @@ Every response says which version answered it, in `Foldrun-Version`.
46
46
  pinned before it gets the response transformed back to the shape its
47
47
  version promised.
48
48
 
49
+ The versions so far:
50
+
51
+ | Version | What changed |
52
+ |---|---|
53
+ | `2026-10-26` | `GET /api/usage`: `ledger.providerCostUsd` and `ledger.marginUsd` are withdrawn. They were the platform's own accounting of your lines, not part of your account. A caller pinned to `2026-10-01` still gets both keys, as `null`: the values are withheld, not reproduced. |
54
+ | `2026-10-01` | The first dated version. Every CLI released so far sends it. |
55
+
49
56
  The CLI sends the version it was built for on every call. When a platform
50
57
  refuses it, every command stops with exit 1 and says which side is older:
51
58
  a platform older than the CLI names the CLI released with it
package/docs/api.md CHANGED
@@ -136,6 +136,7 @@ installer's `error`, its cause on the first line. `foldrun deploy` polls it afte
136
136
  | `/api/workspaces/<ws>/flows/<flow>` | POST, PATCH, DELETE | edit a step (`step`, `instruction`, `options`, `target`, `subflow`), rearrange (`groups`), set `trigger`, a canvas edit (`edit`, `edits`), undo (`restore` + `expect`); delete. Every PATCH and DELETE takes `expect` — the text the step numbers were read from, or its sha256 — and is refused with `409` and the current `text`, nothing written, when the file no longer reads it (the canvas, the list view's board and step options, and the CLI's `flow add`/`rm-step`/`dup-step --to` send it; the dashboard shows the 409 as "this flow changed since you opened it — reload") |
137
137
  | `/api/workspaces/<ws>/flows/draft` | POST, PATCH, DELETE | POST draft a flow with a model: `{ description, flow? }` (`flow` redrafts that one). Returns `{ ok, files: [{ path, content, before, sha256 }], issues: [{ where, message, level }], repaired, notes }` — checked with the deploy's checks and the flow lint, repaired once. **Writes nothing**; save with the source PUT. Needs `workspace:write`; a description over 4,000 characters is `413`; a Chat-Completions `provider:` is `422`. On the platform's models the balance is checked first (`402`) and the call is charged as one ledger line, flow `ai-draft`. PATCH and DELETE, and a POST without `description`, are the edits of a flow that happens to be named `draft`, exactly as at `flows/<flow>` |
138
138
  | `/api/workspaces/<ws>/flows/<flow>/run` | POST | start it. An `Idempotency-Key` header, or `idempotencyKey` in the body, makes a retried call safe: a dropped response, a proxy timeout or a CI step that ran twice is answered `started: false` with the `runId` it already started, rather than starting a second run and billing for it. Keys are remembered for 24 hours, per flow |
139
+ | `/api/workspaces/<ws>/flows/<flow>/filter` | POST | test the flow's `filter:` against a delivery without starting anything: `{ payload }` — a webhook's JSON body (or the body as a string, read as JSON), an email's `{ from, to, subject, text }`, a chained run's `{ run, flow, status, ending, verdict, summary }`, a storage event's `{ by, paths }`. Answers `{ flow, trigger, filter, applies, match, reason }` — `reason` names the first condition that failed; a flow with no filter matches everything. Reads the deployed flow; nothing is recorded or charged |
139
140
 
140
141
  `POST .../run` takes `task` (the input), `from` (start at step N — a rerun of
141
142
  the interesting half), `tags`, and `test` (`true` for a [test run](runs#test-runs):
@@ -176,10 +177,16 @@ history with each message.
176
177
  | `/api/workspaces/<ws>/agents/<agent>` | PATCH | edit one line of an agent's frontmatter in place, as the flow canvas does: `{ list: { key, name, action } }` — `key` one of `subagents`, `agents`, `tools`; `action` `add` or `remove` — or `{ set: { key: "description" | "sandbox", value } }` (`sandbox` takes `own` or `parent`, else 400), or `{ network }` — the sites its sandbox may reach: `"open"`, `"trusted"`, `"none"`, a list of sites, or `{ level, allow, defaults }`; `null` removes the line so it inherits ([Network](network)). A `network` nobody could read is a 400 that says why. Only that key's lines change — comments, key order and prose stay. Answers `{ ok, changed }`; 404 for an unknown agent. `workspace:write` |
177
178
  | `/api/workspaces/<ws>/agents/<agent>/run` | POST | run one agent alone (`task`; `test: true` for a test run) |
178
179
  | `/api/workspaces/<ws>/agents/import` | GET, POST | copy an agent in from another workspace of the account. GET lists what could be imported (every other workspace you can read, with its agents). POST `{ from, agent, as? }` copies `agents/<agent>/` — its agent.md and own skills/, scripts/, knowledge/; never memory/, outputs/, state/ — and answers `{ name, files, warnings }`; `warnings` names tools, skills, scripts and secrets the copy uses that this workspace lacks. 409 on a name clash (pass `as`), 404 for an unknown workspace or agent, 403 when `from` is outside your key's scope. Idempotent |
180
+ | `/api/workspaces/<ws>/proposals` | GET | the workspace's proposed fixes, newest first: `{ proposals: [{ id, workspace, eval, by (auto, or who asked), createdAt, updatedAt, status, failures: [{ runId?, case?, check, detail, at }], jobId, reply (the assistant's reasoning), files: [{ path, content, before, sha256 }], issues: [{ where, message, level }], error?, notes?, decidedBy?, decidedAt?, applied? }] }`. `status` is `drafting`, `ready`, `failed`, `applying`, `applied`, `partial` (a write failed part-way; `applied` names what was written) or `dismissed`. `?status=`, `?eval=`. A drafting one is settled as it is read |
181
+ | `/api/workspaces/<ws>/proposals/<id>` | GET, POST | one proposal. `POST { action: "apply" }` writes its files, each a revision by the caller, only when every one still reads what it was drawn against (`409` naming the file that changed) and can be written (`422`; a check error the deploy would refuse is `422` too); `POST { action: "dismiss" }` sets it aside — its failures stay looked at. Only agents, flows and skills are ever in one. Needs `workspace:write` |
179
182
  | `/api/workspaces/<ws>/export` | GET | this workspace, one flow or one agent as a `.zip` — `?kind=flow&name=<flow>` (the flow, every flow it runs as a step, every agent those steps and their colleagues name, and the workspace tools, skills and scripts they grant), `?kind=agent&name=<agent>` (its folder and what it grants), or neither for the whole authored tree. Never memory/, state/, outputs/, storage, runs or a secret's value; `foldrun-package.json` inside says what it is. Any role that can read the workspace |
180
183
  | `/api/workspaces/<ws>/import` | POST | take a package in; the body is the `.zip` (`content-type: application/zip`, at most 20 MB). `?dryRun=1` answers `{ kind, name, from, creates, added, overwritten, unchanged, needs: { secrets, tools, skills, scripts, agents, flows } }` plus `skipped` (entries it will not write: memory, state, anything outside the authored folders) and writes nothing. Without it, applies as one revision; 409 when it would replace a file with different text unless `?overwrite=1`, or when a file cannot be written there (all or nothing). Never deletes. A `Content-Length` is required (411 without). A workspace package into a name that does not exist makes that workspace (`workspace:manage`, the plan's workspace count). 400 for anything not a package, or one holding memory/, state/ or outputs/. Idempotent |
181
184
  | `/api/workspaces/<ws>/evals` | GET, POST | list; create (`name`) |
182
185
  | `/api/workspaces/<ws>/evals/<eval>/run` | GET, POST | POST runs one eval and answers with its result; with `{ async: true }` it answers `202 { started, eval, runId, startedAt }` at once and the eval runs on — an eval of slow cases outlives a proxy's read timeout (Cloudflare's is 125 s by default). One run of an eval at a time: a second is `409` naming the run that holds it. `GET ?run=<runId>` is what to poll — that run alone, whatever else runs or writes the eval's latest result meanwhile: `{ runId, state, running }` where `state` is `running`, `done` (with its `result`), `failed` (with `error`), `lost` (it stopped reporting before saving a result, e.g. a restart) or `unavailable` (an id not on record — the last 20 runs are kept). Plain `GET` answers who holds the eval now (`running`, `runId`, `startedAt`) and the latest `result`. The dashboard and `foldrun eval --to` start async and poll by run id |
186
+ | `/api/workspaces/<ws>/evals/<eval>/compare` | GET, POST | compare models on one eval: its cases under two to four settings, side by side. `POST { configs: [{ model, effort?, agent? }], repeat?, maxUsd? }` — `model` a tier (`fast`, `default`, `max`) or a model id; `effort` low…max; `agent` (flow evals) forces only that agent's steps, else every step; `repeat` 1–5 (1); `maxUsd` the spend limit, above 0 and at most 100 (5). At most 60 runs (cases × settings × repeat, else `413`). Answers `202 { started, eval, runId, startedAt, trials, maxUsd }` and runs on: every run a test run, the eval's own judge for all. `GET ?run=<runId>` → `{ runId, state, running }` — `running` (with `progress: { done, total }`), `done` (with `result`), `failed` (with `error`), `lost` or `unavailable`. `result` is `{ eval, target, judge, startedAt, finishedAt, repeat, maxUsd, spentUsd, stopped, configs: [{ model, effort, agent, label, trials, passed, notRun, rate, costUsd (runs and judges), judgeCostUsd, avgCostUsd, avgSecs (worker pick-up to end), runIds }], cases: [{ case, passed: [per setting], trials: [per setting] }] }`. Plain `GET` → `{ running, runId?, startedAt?, progress?, comparisons }` (the last 20, newest first). One comparison of an eval at a time (`409`); a grader, saved inputs or an eval with a `run:` check `400`. Needs `run:start` to start |
187
+ | `/api/workspaces/<ws>/evals/<eval>/improve` | POST | ask for a proposed fix now: for a grader, from its failed grades no proposal has covered; for an eval that runs cases, from its last result's failed cases. Answers `202` with the proposal, `status: "drafting"` — the assistant drafts it (one reply, paid as Ask AI's are); poll `GET …/proposals/<id>`. `409` when there is nothing to fix, a proposal for this eval is open, or the account or workspace is paused. Needs `run:start` |
188
+ | `/api/workspaces/<ws>/evals/<eval>/grades` | GET | a grader's grades (an eval with `trigger: runs`): `{ eval, flow, agent, sample, improve, days, summary, grades }`. `summary` is the window's `{ graded, passed, failed, errors, rate, costUsd, byDay: [{ day, graded, passed, failed }] }` (`rate` is passed ÷ decided, `null` when nothing was decided); `grades` the newest first, one per run — `{ eval, runId, flow, at, status (pass, fail or error — not decided), checks: [{ name, passed, error?, assertions: [{ type, value, passed, detail }] }], costUsd (the judges'), model, evalRevision, runRevision, runFinishedAt, by }`. `?days=` 1–90 (30), `?status=` pass, fail or error, `?limit=` 1–500 (100). An eval that runs cases is `400` |
189
+ | `/api/workspaces/<ws>/evals/<eval>/grade` | POST | grade one finished run now, sampled or not: `{ run }` → the grade (the shape above), kept like any other — the newest grade of a run is the one shown. Needs `run:start`; the judges run on the account's model key. A run that is not this grader's (another flow, or no step by its agent) is `400`, a run still going `409`, one with no reply to grade `409`, an eval that runs cases `400`, a paused account or workspace `409` |
183
190
  | `/api/workspaces/<ws>/tools/<tool>/test` | POST | exercise one tool (`args`, `path`). An http tool with an `operations:` allowlist is probed only with a GET to one of its operations (no `path`: the first GET without parameters), and fails if the allowlist resolves nothing, as a run does |
184
191
  | `/api/workspaces/<ws>/hooks` | GET | the [hooks](hooks) this workspace can turn on — its own and the library's (shadowing marked), invalid ones with the reason, and who turns each on — plus `recent`: every deny, rewrite and failure hooks wrote in the last `?runs=` runs (1–500, default 50), newest first; `?all=1` includes notes and context |
185
192
  | `/api/workspaces/<ws>/hooks/<name>/test` | POST | run one [hook](hooks) on a sample event: body `{ event }`, answer the hook's own (`ok`, `decision`, `reason`, `input`, `context`, `reply`, `note`, `failure`, `ms`). Shares the `hooks/` path with flow webhooks below — `/test` is only ever a hook's. Answers `404` for no such hook, `422` for an invalid `hook.md`, `400` for an event that is not an object. On an isolated install hook code never runs in the platform's own process, so this answers with where to test it instead (`foldrun hook test` locally, or a test run) |
@@ -192,7 +199,7 @@ paying for the steps around it.
192
199
  | Route | Methods | |
193
200
  |---|---|---|
194
201
  | `/api/workspaces/<ws>/runs?limit=` | GET | `{ runs: [{ id, flow, status, verdict, outcome, startedAt, finishedAt, ... }] }`; search (see [Runs](runs#searching-runs)) with `tool` (a step called a tool whose name contains it), `tool_error=1`, `agent`, `model` (contains), `min_tokens` (`50k`), `min_secs` — `limit` counts the matches — `verdict` is the word the summary leads with (`GOOD`, `QUIET`, `BLOCKED`, `BAD` or null) and `outcome` the one word every page shows (`running`, `queued`, `waiting`, `good`, `done`, `quiet`, `blocked`, `bad`, `failed`, `stopped`); `failure` is `{ agent, reason }` for a run that failed (null otherwise), `chargedUsd` is what the account was charged for the run (one credit is one cent), null until the ledger settles it, while `costUsd` is the provider's token cost — off the run index (see [Runs](runs#the-runs-list)); a finished run's steps carry `agent`, `status`, `costUsd` and `tokens` (`{ input, output, cacheRead, cacheWrite }`, see [Runs](runs#the-record)), and the run its summed `tokens` — not their reply or trace |
195
- | `/api/workspaces/<ws>/runs/<id>/calls/<call>` | GET | one tool call's recorded content (see [Runs](runs#what-a-run-records)): `{ call: { id, tool, input, output, inputChars, outputChars, truncated, inputCut, outputCut } }` — what it was given and what it gave back, secrets masked, each at most 65,536 characters; `inputChars`/`outputChars` are the whole length, `inputCut`/`outputCut` say which part was cut (`truncated`: either). `<call>` is the tool event's `call`; an event with `captured: true` has content here. 404 when nothing was recorded: the workspace says `capture: metadata`, or the run is from before 19 Oct 2026. A run's steps also carry `calls`, each model call (`n`, `at`, `ms`, `model`, `stop`, `tokens`, `tools`, and `subagent` / `attempt` when a sub-agent or a later attempt made it); a step that handed jobs to `sandbox: own` sub-agents carries `delegations` (`id`, `agent`, `status`, `costUsd`, `ms`), and each job is a step of its own with `subagentOf` (the delegating agent), `delegation` (that `id`) and `wrote` (the workspace paths it changed); and the run its `revision` (the workspace's latest revision when a worker picked it up — a deploy's commit, or the id an edit through `/source` was saved as) and `drivenAt` (when that was) |
202
+ | `/api/workspaces/<ws>/runs/<id>/calls/<call>` | GET | one tool call's recorded content (see [Runs](runs#what-a-run-records)): `{ call: { id, tool, input, output, inputChars, outputChars, truncated, inputCut, outputCut } }` — what it was given and what it gave back, secrets masked, each at most 65,536 characters; `inputChars`/`outputChars` are the whole length, `inputCut`/`outputCut` say which part was cut (`truncated`: either). `<call>` is the tool event's `call`; an event with `captured: true` has content here. 404 when nothing was recorded: the workspace says `capture: metadata`, or the run is from before 19 Oct 2026. A run's steps also carry `calls`, each model call (`n`, `at`, `ms`, `model`, `stop`, `tokens`, `tools`, and `subagent` / `attempt` when a sub-agent or a later attempt made it); a step that handed jobs to `sandbox: own` sub-agents carries `delegations` (`id`, `agent`, `status`, `costUsd`, `ms`), and each job is a step of its own with `subagentOf` (the delegating agent), `delegation` (that `id`) and `wrote` (the workspace paths it changed — copied into the delegating step's sandbox too, up to 4 MiB a job); and the run its `revision` (the workspace's latest revision when a worker picked it up — a deploy's commit, or the id an edit through `/source` was saved as) and `drivenAt` (when that was) |
196
203
  | `/api/workspaces/<ws>/runs/<id>/trace` | GET | the run as one tree (see [Runs](runs#the-trace-tree)): `{ tree, failure }`. Each span is `{ id, kind, label, start, end, status, children, … }`, where `kind` is `run`, `step`, `model` (one model call: `model`, `stop`, `tokens`), `tool` (`call`, `captured` when its input and output were recorded) or `error` (`text`); `start`/`end` are epoch milliseconds and `status` is `ok`, `error`, `running`, `waiting`, `skipped` or `pending`. A tool call sits under the model call that asked for it. `failure` is the ids from the root to the first thing that went wrong, which the run page opens on; `[]` when nothing did |
197
204
  | `/api/workspaces/<ws>/runs/<id>/compare?with=` | GET | this run beside another of the same flow (see [Runs](runs#compare-with-the-last-good-run)): `{ comparison: { base, run, revisionChanged, changedFiles, steps }, chosen }`. Each step is `{ step, agent, base, run, changes }`: both sides' status, instruction, model, seconds, tokens, model calls, tool counts, tool errors, first errors and first line said, and `changes` in words (`status: completed → failed`, `new error: …`, `instruction changed`, `tools: +web ×3`, `took 12s → 48s`, …). `changedFiles` lists the files changed between the revisions the two ran (null when one is unknown). `with` names the other run; unasked it is the newest earlier run of the flow that finished well, else the run this one re-ran (`chosen` says which) |
198
205
  | `/api/workspaces/<ws>/runs/<id>` | GET, DELETE | the whole run: every step, its output, cost, timing, the runner `image` it ran on and — for a step that browsed through the account's pod from slim — its `browserPod` reconnects and fallback ([runs](runs#the-record)). `?wait=true&timeout=<s>` instead blocks until the run stops (or `timeout`, default 300, max 900) and answers the verdict the run routes give — `200` completed, `500` failed with the record, `202` still going (`timedOut`) or parked on a person (`awaitingApproval`). Ask in short pieces: whatever sits in front of the platform cuts a request that stays silent too long (Cloudflare at 100 s, an AWS ALB at 60 s), and a flow can run for many minutes — the CLI's `--wait` asks 25 s at a time and comes back here on every `202` |
@@ -336,7 +343,7 @@ Reads return which secrets exist, never their values.
336
343
  | `/api/usage/history?days=` | GET | charged spend by flow, by agent and by workspace over time, read from the ledger rather than the run records — so it survives runs being pruned and reports what was billed rather than what was consumed. Buckets by week over three weeks, by day under. Each series carries its periods, its total, and the change between the last two COMPLETE periods, so a partial week never reads as a collapse. `unattributedUsd` is charges from before a line recorded its flow. A caller scoped to some workspaces sees only the charges in those; `days` 1–365, default 56 |
337
344
  | `/api/account/model` | GET, PUT, DELETE | the account's own model key — what every step runs on unless an agent, workspace or the account's AGENTS.md names a `provider:`. GET: `{ set, provider, baseUrl, format, keyHint, runsOn, platformKeyAllowed }` — never the key, only its last four characters; `runsOn` is `account` (its own key), `platform` (the platform's credential, for the operator's accounts) or `none` (runs are refused until a key is set). PUT `{ provider, apiKey, baseUrl?, format? }` (needs `secrets:write`): `provider` is a preset name (anthropic, openrouter, openai, groq, … — see providers) or `custom` with an https `baseUrl` and a `format` (anthropic or openai); a Claude login token (sk-ant-oat…) is refused for any account not allowed the platform's credential. Stored as the account secrets `FOLDRUN_MODEL_PROVIDER`, `FOLDRUN_MODEL_API_KEY`, `FOLDRUN_MODEL_BASE_URL`, `FOLDRUN_MODEL_FORMAT`. DELETE removes them. Honours Idempotency-Key on PUT; audited as model.key_set / model.key_removed |
338
345
  | `/api/account/providers` | GET, POST | GET: the model providers this account's files actually use — each one's preset name, where it is declared, the model a check would send — plus the last daily health check. POST forces one now, which spends one minimal request at each distinct endpoint, and needs the permission that runs |
339
- | `/api/usage` | GET | what has been spent, by meter; each bucket's tokens are `inputTokens` (all input), `outputTokens`, `cacheReadTokens` and `cacheWriteTokens` (the part of the input the prompt cache served and stored), and `cacheHitRate` — reads over `measuredInputTokens`, the input of steps that report the split, `null` when none do. A key or member scoped to some workspaces sees those workspaces, and totals over them; the ledger figures are the account's, as the wallet's are |
346
+ | `/api/usage` | GET | what has been spent, by meter; each bucket's tokens are `inputTokens` (all input), `outputTokens`, `cacheReadTokens` and `cacheWriteTokens` (the part of the input the prompt cache served and stored), and `cacheHitRate` — reads over `measuredInputTokens`, the input of steps that report the split, `null` when none do. A key or member scoped to some workspaces sees those workspaces, and totals over them; `ledger` is the account's `balanceUsd` and `chargedUsd` (all time), the account's as the wallet's are — since API version `2026-10-26` nothing else; earlier pins see `providerCostUsd` and `marginUsd` as `null` |
340
347
  | `/api/approvals` | GET | every gate waiting on a person, across workspaces — one entry per waiting **step** (`workspace`, `runId`, `flow`, `step`, `agent`, `question`, `asked`, `waitingSince`), oldest first. By step status, not run status: a decided gate leaves the list at once, before the worker resumes the run. `wait: event` steps are not listed; no button answers them. Beside it, `questions`: every question an agent is asking mid-step in a running run (`kind: "question"`, `id`, `workspace`, `runId`, `flow`, `agent`, `question`, `options?`, `askedAt`) — answered with `…/runs/<id>/answer` |
341
348
  | `/api/insights?days=&workspace=` | GET | recurring problems found in the runs of the window (see [Runs](runs#insights)): `{ days, insights: [{ id, kind, workspace, agent, tool?, title, why, fix, credits, steps, evidence: [{ workspace, runId, step }] }] }`. `kind` is `cache` (an agent's big prompt mostly uncached), `big-result` (a tool result over 20k characters sent again on every later model call), `retry-loop` (a tool erroring three or more times in a step) or `timeout` (steps using 80% or more of their `timeout:`); `credits` is about what it cost in the window, null when it is not money. `days` 1–30, 7 unasked. A key scoped to some workspaces sees theirs |
342
349
  | `/api/issues?status=&workspace=` | GET | the account's issues: what went wrong, grouped and kept open until a person resolves it (see [Runs](runs#issues)). One issue is one desk's flow failing at one agent, or ending BLOCKED or BAD, or one platform cause across desks. Each carries `id`, `kind` (`platform`, `failed`, `blocked`, `bad`, `missed` — a scheduled fire that started no run), `status` (`open`, `acknowledged`, `snoozed`, `resolved`), `regressed` and `sinceRevision` (it was resolved and came back, since the revision its new run ran), `snoozedFor`, `workspace`/`workspaces`, `what`, `agent`, `reason`, `action` (what to do), `firstSeen`, `lastSeen`, `count`, the newest `runs`, `recoveredAt` (the flow's newest good run since — it closes nothing), `acknowledged`, `snoozedUntil`, `resolved` and the `history` of what people did. `status` is `active` unasked (open + acknowledged), or `open`, `acknowledged`, `snoozed`, `resolved`, `all`; `workspace` keeps the ones that hit it. A key scoped to some workspaces sees the issues of those |
@@ -353,7 +360,7 @@ Reads return which secrets exist, never their values.
353
360
  | `/api/openapi.json` | GET | this API as an OpenAPI 3.1 document — every route and method, bearer auth, the rate-limit, version and Idempotency-Key headers, and request/response schemas for runs, flow runs, deploy, source, secrets, keys and billing. No key needed. Generated from the route files by `scripts/gen-openapi.mjs`; the dashboard renders it at Docs → API reference, `foldrun api spec` saves it |
354
361
  | `/api/account` | GET, PATCH | the account's defaults from its AGENTS.md frontmatter — `timezone`, `budget` (a USD cap — a number for a month, `"60/day"`, `"60/week"`, or `{ usd, period }`; null is no limit), `notify` (`{ url?, email?, events }`), `concurrency`, `deploy_block` (`none`, `secrets` or `security` — answered as `deployBlock`), `network_enforce` (answered as `networkEnforce`), `owner`, `alerts` (as written), `judge` (`{ model?, effort? }`), `telemetry` (`{ otlp, headers }` — header values are `${SECRET}` names; answered as `{ endpoint, headers }`); PATCH sets the keys sent, null clears one, and edits the file in place |
355
362
  | `/api/audit?since&until&action&actor&workspace&limit&cursor&format` | GET | the account's audit log, newest first — the caller's account only, whatever a header, query or body names. The owner and unscoped admins (people, or `admin` keys); `audit:read`, and refused to a member or key scoped to some workspaces, because the log is the whole account's. `since`/`until`: `7d`, `24h`, `30m` or a date; `action`: exact (`apikey.created`) or a family (`apikey`); `actor`: exact (an email, `key:<label>`, `support:<email>`); `workspace`: entries about one; `limit` 1–1000 (100; 1000 for CSV); `cursor`: the `next` of the page before. JSON `{ entries: [{ id, at, actor, action, subject, detail }], next, retention }`; `format=csv` downloads the same rows (`x-next-cursor` header when there are more). Records sign-ins and refusals, sign-outs, session revokes, password and email changes, MFA on/off, key mint/rotate/revoke, invites, joins, role/scope changes, removals, ownership transfers, secrets set/deleted (by name — never a value), deploys, workspace deletes, plan and billing changes, export and close requests, and `support.viewed`/`support.ended`. The super admin's own levers (`operator.*`) are the platform's record and not listed. Kept for the life of the account |
356
- | `/api/avatars/<kind>/<id>` | GET, PUT, DELETE | a picture for a `user` (their own id), a `workspace` (its name) or the `account` (the tenant). PUT the bytes of a PNG, JPEG or WebP under 1 MB; a person sets their own, an admin a workspace's or the account's. GET is cached for a year — the URL's `?v=` changes with the picture |
363
+ | `/api/avatars/<kind>/<id>` | GET, PUT, DELETE | a picture for a `user` (their own id), a `workspace` (its name) or the `account` (the tenant). PUT the bytes of a PNG, JPEG or WebP under 1 MB; a person sets their own, an admin a workspace's or the account's. GET needs a signed-in tenant and is privately cached for a year — the URL's `?v=` changes with the picture |
357
364
  | `/api/search?q=` | GET | find anything in the account by name — workspaces, agents, flows, tools, skills, knowledge, memory, runs (by id, flow or headline); ranked, at most six per kind. The dashboard's Find palette reads it |
358
365
  | `/api/schedule` | GET, POST | GET: every scheduled flow with `valid` (the cron parses) and `upcoming` (the next three fires). POST: tick the scheduler now — install-wide, so `workspace:manage`; returns `{ ok, fired }` |
359
366
  | `/api/library/<kind>?path=` | GET, POST, PUT, DELETE | account-level shared documents (`name`, `content`, `path`, `template`) |
@@ -412,7 +419,7 @@ so a client learns what it is talking to without a second request:
412
419
 
413
420
  ```
414
421
  X-Foldrun-Version: v2026.10.01.3 # the platform's version
415
- X-Foldrun-Api: 2026-10-01 # the API contract — moves only on a breaking change
422
+ X-Foldrun-Api: 2026-10-26 # the API contract — moves only on a breaking change
416
423
  X-Foldrun-Cli: 0.6.0 # the CLI released with this version (absent when unknown)
417
424
  ```
418
425
 
@@ -454,6 +461,7 @@ signed-in person, never by a key — mints an ordinary API key at their role.
454
461
  | `/api/cli/authorize` | GET, POST | `?code=` describes the request (machine, expiry). POST `{ code, decision }` from a session approves (mints the key, labelled `cli · <hostname>`) or denies — `decision` is `approve` or `deny`, and absent approves; any other word is a `400`. Every role may sign its own CLI in; an owner's key is an admin's |
455
462
  | `/api/me` | GET | who is calling: `account`, `owner`, `role`, `workspaces` (null: all), and the `actor` — a person's email, or a key's id, label, prefix and who minted it |
456
463
  | `/api/me/onboarding` | GET, PATCH | the account's getting-started steps, each derived from what is really there — `{ steps: [{ id, title, why, href, cli?, done }], done, total, complete, next, dismissed, dismissedAt }`. Steps: `model` (first; only for an account that must bring its own key — done once it has one, or a `provider:` block in the account's AGENTS.md), `workspace`, `agent` (an agent written or deployed after the workspace was made), `run`, `success` (a completed run), `secret`, `trigger` (a schedule or webhook), `teammate` (a second member), `billing` (hosted, not fully waived: a saved card or a plan), `cli` (any API key or CLI login). PATCH `{ dismissed: true or false }` hides or brings back the dashboard card for the signed-in person (kept in their prefs); a key reads `dismissed: false` and cannot PATCH |
464
+ | `/api/me/inbox` | GET, POST | your inbox — what waits on you across the workspaces you may see. GET `{ person, items: [{ id, kind (approval, question, issue, proposal, run), bucket (mine, started, team), why, workspace, title, detail, at, href, read, dismissed }], counts: { mine, started, team, unread } }`, newest first. `mine` is assigned to you (named in `approvers:`, owner of the flow or agent, or you asked for the proposal); `started` is runs you started — failed or BLOCKED/BAD this week, a gate on one (someone else decides it), a question it asked; `team` is the rest that waits in your workspaces. By default `mine` and `started`; `?bucket=mine\|started\|team\|all`, `?kind=`, `?workspace=`, `?dismissed=1` for what you set aside. `counts.unread` is unread `mine` + `started`. POST `{ ids \| id, action: read\|unread\|dismiss\|restore }` changes your view only — dismissing never decides a gate or resolves an issue; ids name an occurrence, so a thing that happens again is new. A key acts for the person who minted it, inside the key's own scope; one no person minted is a `400` |
457
465
  | `/api/me/notifications` | GET, PATCH | what mail you get. GET `{ email, categories: [{ category, label, description, required, why?, perWorkspace, enabled, workspaces: { <ws>: bool } }] }` for `security`, `invites`, `billing`, `account` (required — always sent) and `run-alerts`, `approvals` (per workspace), `low-balance`, `product-updates`. PATCH `{ category, enabled, workspace? }` or `{ preferences: [ … ] }`; answers the same as GET. Turning a required category off is a `409` with the reason; `workspace` on an account-wide category is a `400`; `enabled: true` account-wide clears that category's per-workspace offs. A key acts for the person who minted it |
458
466
  | `/api/me/preferences` | GET, PATCH | your own display preferences: `{ theme, runViews }` — `theme` is `system` (the default: follow the computer's light or dark setting), `light` or `dark`; `runViews` your saved run searches, `[{ name, query }]` (see [Runs](runs#searching-runs)). PATCH `{ theme }` and/or `{ runViews }` (the whole list, at most 20, each query of the runs filters) answers the same; anything else is a `400`. Kept in your prefs, so it follows you to every browser; the dashboard applies it on the server, before the first paint. A key acts for the person who minted it; a key minted by nobody is a `400` |
459
467
  | `/api/unsubscribe?token=` | POST | one-click unsubscribe (RFC 8058) — no login, the signed token is the credential. It is the `List-Unsubscribe` URL on every optional mail, beside `List-Unsubscribe-Post: List-Unsubscribe=One-Click`; a mail client POSTs `List-Unsubscribe=One-Click` to it. Turns off the one category (for the one workspace) the token was minted for, for its address. The token may also come as a form field (`token`, and `from=page` to be sent back 303 to the `/unsubscribe` confirmation page) or JSON. `200 { ok, category, workspace }`; `400` no token, `401` forged, `410` expired (180 days; `FOLDRUN_UNSUBSCRIBE_TTL_DAYS`). Never on a GET — `/unsubscribe?token=` is the page that asks first |
package/docs/cli.md CHANGED
@@ -44,7 +44,7 @@ claude.ai or Claude Code there, nor any MCP configuration on disk.
44
44
  | `foldrun extract [dir]` | move each single-file script tool — a `tools/<name>.md` with its program in a fenced block — into a folder: `tools/<name>/tool.md` with `run:` pointing at `run.js`, `run.py` or `run.sh` beside it. Frontmatter is edited as text, never re-serialised, so the diff is only what moved. A tool that already has a folder is left for you; `--dry-run` lists what it would do |
45
45
  | `foldrun check --to <ws>` | validate the copy that is DEPLOYED, rather than the folder in front of you — a workspace edited through the API, by an agent or by `foldrun source put`, has had no way to be checked short of spending a run. The files are fetched into a temporary folder and the ordinary check runs over them, so there is one copy of the rules; the output names the workspace and the platform it checked. `--online` adds the network checks the platform runs: known vulnerabilities for exact runtime pins and remote MCP servers' tool text, and what could not be checked |
46
46
  | `foldrun agent run <name>` | run one agent once on a platform, with no flow file: a flow of one step. `--task "…"` is the instruction and is required. Prints the run id and how to follow it; `--wait` holds on (in 25-second pieces, as `invoke` does) and then prints the same report `foldrun report` would; `--test` makes it a [test run](runs#test-runs) |
47
- | `foldrun agent link <agent>` | add to an agent's team, in its own frontmatter — `--subagent <worker>` (`subagents:`, a worker it delegates to), `--consult <agent>` (`agents:`, a colleague it asks) or `--can-ask` (`ask` in `tools:`, so it may ask you mid-step). The edit is core's, the one the canvas's docks make: only the lines of that one list change, flow style stays flow style, comments and the prose stay byte for byte. A sub-agent without a `description:` needs one, because the model picks a sub-agent by it — asked for at a terminal, `--description "…"` otherwise, and written into the worker's file first. `--isolated` also writes `sandbox: own` on the worker: each job it is handed runs in its own sandbox, with its own tools, secrets and network, not cut to the delegating agent's, and only its reply comes back (`foldrun docs agents`). Says which flows use the agent ("used by 3 flows"), since the change reaches all of them. Prints the diff, and refuses an edit `foldrun check` would call an error; `--dry-run` writes nothing. In this folder by default (`--workspace <name>` in an account with several); `--to <workspace>` edits the deployed copy through `PATCH /api/workspaces/<ws>/agents/<name>`. In this folder it re-reads each file just before writing — after the description prompt, after `check` — and refuses, writing nothing to either file, when one changed since it was read |
47
+ | `foldrun agent link <agent>` | add to an agent's team, in its own frontmatter — `--subagent <worker>` (`subagents:`, a worker it delegates to), `--consult <agent>` (`agents:`, a colleague it asks) or `--can-ask` (`ask` in `tools:`, so it may ask you mid-step). The edit is core's, the one the canvas's docks make: only the lines of that one list change, flow style stays flow style, comments and the prose stay byte for byte. A sub-agent without a `description:` needs one, because the model picks a sub-agent by it — asked for at a terminal, `--description "…"` otherwise, and written into the worker's file first. `--isolated` also writes `sandbox: own` on the worker: each job it is handed runs in its own sandbox, with its own tools, secrets and network, not cut to the delegating agent's; its reply comes back with the files it wrote (`foldrun docs agents`). Says which flows use the agent ("used by 3 flows"), since the change reaches all of them. Prints the diff, and refuses an edit `foldrun check` would call an error; `--dry-run` writes nothing. In this folder by default (`--workspace <name>` in an account with several); `--to <workspace>` edits the deployed copy through `PATCH /api/workspaces/<ws>/agents/<name>`. In this folder it re-reads each file just before writing — after the description prompt, after `check` — and refuses, writing nothing to either file, when one changed since it was read |
48
48
  | `foldrun agent import <workspace>/<agent>` | copy an agent you already have in another workspace into this one: its `agent.md` and own `skills/`, `scripts/`, `knowledge/` — never `memory/`, `outputs/` or `state/`. Into the workspace you stand in, or `--workspace <name>`; `--as <name>` imports it under another name (and rewrites `name:`), which a name clash requires. `--to <workspace>` does it on the platform (`POST /api/workspaces/<ws>/agents/import`) and lists the tools, skills, scripts and secrets the copy uses that the workspace lacks. See [Importing an agent](workspaces#importing-an-agent-you-already-have) |
49
49
  | `foldrun agent import --list` | what could be imported into a deployed workspace: every other workspace this key may read, and each one's agents with their descriptions (`GET …/agents/import`). Imports nothing. `--to <workspace>`, `--json` |
50
50
  | `foldrun agent unlink <agent>` | take one away: `--subagent <name>`, `--consult <name>` or `--can-ask`. An emptied list is written `key: []`, not deleted. In this folder, refused the same way, nothing written, when the file changed since it was read |
@@ -58,6 +58,7 @@ claude.ai or Claude Code there, nor any MCP configuration on disk.
58
58
  | `foldrun flow rotate-hook <flow>` | a new webhook URL for the flow (`POST …/hooks/<flow>/rotate`). The old URL stops working the moment it returns, so it asks first — `--yes` with no terminal. Prints the new URL, which is itself a credential |
59
59
  | `foldrun flow set <flow> --step <n\|agent> key=value …` | the step editor on the Flows page, from a terminal (core's `updateFlowStep`, and `updateFlowStepInstruction` for `instruction=`): `model`, `effort`, `retry`, `timeout`, `verify`, `when`, `case`, `else`, `loop`, `until`, `each`, `max`, `limits` — only the keys named are touched, `key=` clears one. `each=` takes `lines` only; the other fan-outs are `flow add … fan-out`. A value the rewriter would drop or clamp is refused, nothing written: `effort` one of low, medium, high, xhigh, max (or an alias core reads, e.g. `deep`); `timeout` a whole number of seconds (`timeout=900`, not `15m`); `retry` 0–5, `loop` 1–5, `max` 1–20, whole numbers. Shows the diff, refuses an edit `check` would call a new error, `--dry-run` writes nothing; `--to <workspace>` sends the editor's `PATCH …/flows/<flow> { step, options }` / `{ step, instruction }` with `expect` |
60
60
  | `foldrun flow trigger <flow> manual\|webhook\|schedule` | the trigger picker on a flow card (core's `setFlowTrigger`): only the `trigger:`, `schedule:` and `timezone:` lines change. `--schedule "0 9 * * 1"` (5 fields, or `@daily`) and `--timezone <zone>` go with `schedule`. Diff, checked, `--dry-run`; `--to` sends `PATCH { trigger }` |
61
+ | `foldrun flow filter <flow> --payload <file\|-\|json>` | would this delivery start the flow? Its `filter:` against a payload — a webhook's JSON body, an email's `{ from, to, subject, text }`, a chained run's `{ run, flow, status, ending, verdict, summary }`, a storage event's `{ by, paths }` — and the condition that held it back. Reads the local flow; `--to <workspace>` asks the deployed one (`POST …/flows/<flow>/filter`, the Triggers page's Test box). Starts nothing; exits `0` when it would start a run, `1` when not; `--json` for the whole answer |
61
62
  | `foldrun flow move-step <flow> --step <n\|agent>` | dragging a card on the board: `--group <g>` runs it beside group g, `--after <g>` gives it a group of its own after g (`0` = first). Only step numbers change (core's `reorderFlowSteps`). Diff, checked, `--dry-run`; `--to` sends `PATCH { groups }` |
62
63
  | `foldrun flow copy-step <flow> --step <n\|agent>[,<n>…]` | the canvas's Copy: the steps' markdown — line, marker and every option (core's `stepSource`) — on stdout. Reads only |
63
64
  | `foldrun flow paste <flow>` | the canvas's Paste: step markdown from stdin or `--file <path>` goes in as new groups after `--after <g>` (default last), or beside group `--group <g>`, renumbered to fit (core's `pasteSteps`) — `foldrun flow copy-step a --step 2 \| foldrun flow paste b`. Diff, checked, `--dry-run`; `--to` sends `PATCH { edit: { op: "paste" } }` |
@@ -70,7 +71,13 @@ claude.ai or Claude Code there, nor any MCP configuration on disk.
70
71
  | `foldrun hook test <name>` | run one hook HERE on one event, exactly as a step runs it (the event on stdin, a stripped environment, its `timeout:`), and print its answer — decision, reason, a rewritten input, context, reply or note — and how long it took. `--event '<json>'` or `--event @file`; without it, a sample event for the hook's `on:`. A deny is an answer (exit 0); a hook that crashes, times out or answers in the wrong shape is a failure (exit 1) — which, on a gate, refuses the call. `--to <workspace>` runs the DEPLOYED hook on the platform instead (`POST …/hooks/<name>/test { event }`) |
71
72
  | `foldrun hook rm <name>` | delete a hook folder (`--library` for the account's). Says which agents and AGENTS.md files still turn it on — their steps are refused until it goes from their `hooks:` — and asks; `--yes` on a pipe |
72
73
  | `foldrun run <target>` | run an agent or a flow HERE, on this machine (`name`, or `flow:name`) — `--test` for a [test run](runs#test-runs). On a platform: `flow run`/`invoke` for a flow, `agent run` for one agent |
73
- | `foldrun eval [name]` | one eval, or all of them. `--to <workspace>` runs the DEPLOYED workspace's evals on the platform (`POST …/evals/<name>/run` with `async: true`, then polling `GET …/run?run=<id>` — an eval longer than a proxy's timeout still gets its own verdict), waiting for each (`--timeout <s>`, default 900; past it, the run id to read it with). `--run <id>` prints that run's verdict and runs nothing — a run that was lost or is unknown exits 1; `--last` prints each eval's latest result and runs nothing, and prints the same lines; exits 1 when a case fails |
74
+ | `foldrun eval [name]` | one eval, or all of them — a grader (`trigger: runs`) is listed and skipped, since it has no cases. `--to <workspace>` runs the DEPLOYED workspace's evals on the platform (`POST …/evals/<name>/run` with `async: true`, then polling `GET …/run?run=<id>` — an eval longer than a proxy's timeout still gets its own verdict), waiting for each (`--timeout <s>`, default 900; past it, the run id to read it with). `--run <id>` prints that run's verdict and runs nothing — a run that was lost or is unknown exits 1; `--last` prints each eval's latest result and runs nothing, and prints the same lines; exits 1 when a case fails |
75
+ | `foldrun eval compare <eval> --models <m[:effort],…> --to <workspace>` | an eval's cases under two to four models, side by side (`POST …/evals/<eval>/compare`, then polled) — the Evals page's **Compare models**. `--models fast,default,max` or `fast:low,max:high`; `--effort` for the items that name none; `--agent <name>` compares only that agent's steps of a flow eval; `--repeat` 1–5; `--max-usd` the spend limit (default 5). Every run is a test run. Waits (`--timeout <s>`, default 3600; past it, the id to read it with) and prints each setting's passing, cost, cost and time per run, then the cases where they differ. `--list` the kept comparisons; `--run <id>` one of them; `--json` |
76
+ | `foldrun eval improve <eval> --to <workspace>` | ask for a proposed fix now (`POST …/evals/<eval>/improve`) — from a grader's failed grades no proposal covers, or an eval's last failed cases — and wait for the draft (`--timeout`, default 300), then print it like `proposals show`. `--no-wait` returns with the id. Exits 1 unless the draft is ready |
77
+ | `foldrun proposals --to <workspace>` | the proposed fixes in a workspace, newest first: status, the eval, the failures it covers, the files it changes. `--status ready` for the ones waiting on you, `--eval <name>`, `--json`. The Evals page's Proposed fixes |
78
+ | `foldrun proposals show\|apply\|dismiss <id> --to <workspace>` | `show`: the assistant's reasoning, the failures, the change per file as `-`/`+` lines. `apply`: prints the change and asks before writing it (`--yes` without a terminal); each file is a revision by you; refused when a file changed since. `dismiss`: set it aside |
79
+ | `foldrun eval grades <eval> --to <workspace>` | what a grader (an eval with `trigger: runs`) found in the real runs it graded: the pass rate over `--days` (default 30), then each graded run, newest first, with the check that failed — `--status fail` for the failures alone, `--limit`, `--json`. `GET …/evals/<eval>/grades`, the Evals page's grader card. Exits 1 when a graded run in the window failed |
80
+ | `foldrun eval grade <eval> --run <id> --to <workspace>` | grade one finished run now, sampled or not (`POST …/evals/<eval>/grade`) — **Grade a run** on the card. Prints each check; exits 1 unless it passed |
74
81
  | `foldrun eval new <name>` | the Evals page's New, on the deployed workspace (`POST …/evals { name }`): an eval whose `agent:` is the workspace's first agent and whose case is a placeholder — edit it (`source cat`/`put`), then `foldrun eval <name> --to <workspace>` runs it. `--to <workspace>` |
75
82
  | `foldrun promote <run-id>` | keep a finished run as a regression case: its task and what the next run must still say go into `evals/<target>-regressions.md` (or `--eval <name>`), appended when the file exists. `--expect "contains: $34"` — repeatable, eval syntax — replaces the default judge line that holds the next run to the recorded conclusion; `--case <name>` names the case. A run that went wrong (failed, BLOCKED, BAD) takes `--should "what it should have done"` — the judge's claim — or `--expect` |
76
83
  | `foldrun probe <model>` | can this model hold a tool loop here? A live check |
@@ -85,6 +92,8 @@ claude.ai or Claude Code there, nor any MCP configuration on disk.
85
92
  | `foldrun report <run-id> get <agent>/<path>` | download one file the run archived — whatever that agent left in `outputs/`, copied under the run when it ended. Writes it beside you under its own name; `--file <path>` names somewhere else (`-` for stdout), `--force` overwrites |
86
93
  | `foldrun report <run-id> live` | the run page's live browser view: which agents' browsers have posted a frame, and when; `--agent <name>` saves the newest frame as a JPEG (`--file <path>`, `-` for stdout) and prints the page's address, the engine and whether the browser has closed (`GET …/runs/<id>/live`) |
87
94
  | `foldrun insights` | recurring [problems](runs#insights) found in the last week of runs — a prompt mostly uncached, a big tool result sent again, a retry loop, steps near their timeout — each with why, what to do, about what it cost and the runs it was seen in. `--days <1-30>`, `--to <workspace>`, `--json` |
95
+ | `foldrun inbox` | what waits on you across your workspaces ([your inbox](runs#your-inbox)): gates, questions agents ask, open issues, proposed fixes, your runs that went wrong this week — assigned to you and started by you by default; `--team`, `--started`, `--mine`, `--all`, `--dismissed`, `--kind approval\|question\|issue\|proposal\|run`, `--unread`, `--json`. Each item shows its id; exits 1 when something assigned to you is unread |
96
+ | `foldrun inbox read\|unread\|dismiss\|restore <id>…` | mark items in your own view: `dismiss` sets one aside (it still waits where it lives), `restore` puts it back |
88
97
  | `foldrun issues` | the account's [issues](runs#issues): what went wrong, grouped, open until someone resolves it — kind, desk and flow (or the platform cause and every desk it hit), how many times since when, the newest reason and what to do. `--to <workspace>` narrows it, `--all` adds resolved ones (`--status open\|acknowledged\|snoozed\|resolved\|all`), `--json` |
89
98
  | `foldrun issues show\|ack\|snooze\|resolve\|reopen <id>` | one issue: `show` adds its runs and history; `ack` says you have seen it, `snooze --for 30m\|4h\|1d\|1w` (or `--until <ISO>`, or `--times <n>`: until it happens n more times) hides it for a while, `resolve` closes it until it happens again, `reopen` undoes that. `--note "…"` is kept in its history |
90
99
  | `foldrun issues doctor <id>` | the run doctor on an issue's newest run, in that run's workspace — the issue card's **Doctor** button: why (platform, check, work or outside), and the fix as diffs, saved on yes (`--yes`, `--dry-run`, `--json`). A missed schedule has no run and is refused |
@@ -140,7 +149,7 @@ claude.ai or Claude Code there, nor any MCP configuration on disk.
140
149
  | `foldrun billing` | the account's balance, whether billing is on at all, what the platform is currently waiving, and the recent ledger entries with what each was for — a run names its workspace, flow and run id; an adjustment carries its own note. `--limit <n>` shows more. `statement [YYYY-MM]` is a month of the ledger (this month by default) — `--csv` for the file an accountant wants, to stdout or `--file <path>`. `wallet` is the burn, the runway and auto top-up; `wallet set auto-top-up --threshold <usd> --amount <usd>` turns it on (a refill of 5–500), `set auto-top-up off` turns it off, `set email <address>` is where receipts go. `details` is who invoices are made out to; `details set --name "…" --abn … --address "line1, city, state, postcode, AU" --email …` changes it, merged with what is there. `portal` prints a link to Stripe's billing portal. Changing the wallet, the details, and the portal are the account owner's; anyone else is told so |
141
150
  | `foldrun billing plans` | the Plans page: every plan with its monthly fee, credits, runs at once and workspaces, which one the account is on and this cycle's credits left (`GET /api/billing/plans`). `billing plan <id>` chooses one — a first plan answers with Stripe's checkout page, a change on a live plan is prorated at Stripe at once (asks first; `--yes`); `plan cancel` stops it at the end of the cycle, `plan resume` undoes that until then (`POST`/`DELETE /api/billing/subscribe`) |
142
151
  | `foldrun billing top-up <usd>` | the Payment page's top-up: Stripe's checkout page for that amount, opened in the browser (`--no-browser`, or no terminal, prints it). The credit lands when Stripe confirms the payment. `billing card` is the same for saving a card for auto top-up. Both need `billing:manage` |
143
- | `foldrun billing credit <usd>` | put credit on the balance by hand (`POST /api/billing { usd, note }`, `--note "…"` on the ledger line) — only on an install without Stripe, a self-hosted or dev platform; once billing is live the platform refuses it and top-ups go through `billing top-up`. The dashboard's Billing → Add credit does the same while billing is off. Needs `billing:manage` |
152
+ | `foldrun billing credit <usd>` | put credit on the balance by hand (`POST /api/billing { usd, note }`, `--note "…"` on the ledger line) — on foldrun's hosted platform where Stripe is not connected (a dev install); once billing is live the platform refuses it and top-ups go through `billing top-up`. The dashboard's Billing → Add credit does the same while billing is off. Needs `billing:manage`. A self-hosted install has no billing |
144
153
  | `foldrun gallery` | the tools the platform ships to every account (`web`), and for each whether this account keeps its own copy and whether that copy still matches. `pull` lays the shelf down under `~/.foldrun/gallery/<host>/` for offline runs (`foldrun run` and `foldrun eval` refresh it themselves before each run); `upgrade <tool>` replaces the account's copy with the current gallery version, the old one a revision back |
145
154
  | `foldrun identity` | keyless cloud identity: the issuer your cloud must trust and the subject each agent's tokens carry (`GET /api/identity`); `--to <workspace>` fills the workspace in, `--json` |
146
155
  | `foldrun jobs` | the four jobs — governance, guardrail, observability, evaluation — and every `AGENTS.md` field of each, with what is set (`GET /api/account/jobs`). `--to <workspace>` shows the workspace's value beside the account's and how the two combine; `--json` the document. `account set <job>.<field>` and `workspace set <job>.<field>` refuse a field that scope cannot set and name the `AGENTS.md` to write it in. See [The four jobs](four-jobs) |
@@ -186,6 +195,11 @@ claude.ai or Claude Code there, nor any MCP configuration on disk.
186
195
  | `--flow <name>` | a bulk `stop` or `rerun`: only that flow's runs. `flow add … subflow`: the other flow to run as a step |
187
196
  | `--agent`, `--instruction`, `--after`/`--before`, `--group`, `--step`, `--cases`/`--else`, `--each`/`--max`, `--loop`/`--until`/`--judge`, `--question`, `--wait`, `--on-fail`, `--off` | `flow add`: see the patterns above. `--agent` on `rerun` is the first step that agent runs; `--question` on `answer` picks one of several questions; `--wait` alone stays the switch `invoke` and `agent run` read |
188
197
  | `--schedule "<cron>"`, `--timezone <zone>` | `flow trigger schedule`: the cron line (5 fields, or `@daily`) and the zone it is read in |
198
+ | `--team`, `--started`, `--mine`, `--all` | `inbox`: which bucket — the rest of what waits in your workspaces, runs you started, what is assigned to you, or every one (default: assigned and started) |
199
+ | `--dismissed`, `--unread` | `inbox`: what you set aside; only what you have not read |
200
+ | `--models <m[:effort],…>` | `eval compare`: the settings to compare — two to four tiers or model ids, each with an optional `:effort` |
201
+ | `--max-usd <n>` | `eval compare`: stop starting runs once the runs and judges have spent this (default 5) |
202
+ | `--payload <file\|-\|json>` | `flow filter`: the delivery to test — a file, `-` for stdin, or JSON inline |
189
203
  | `--kind <k>` | `secrets set`: `file`, `ssh`, `api`, `service-account` or `m2m` — each with its own flags, in the `secrets set NAME --kind` row above |
190
204
  | `--client <name>` | `connect`: run the consent from that OAuth client saved on the platform (`secrets clients` lists them) |
191
205
  | `--subagent`, `--consult`, `--can-ask`, `--description`, `--isolated` | `agent link`, `agent unlink`: which list to edit, a worker's description when it has none, and (`link --subagent` only) `sandbox: own` on the worker |