foldrun 2.7.0 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +95 -29
- package/LICENSING.md +101 -0
- package/README.md +9 -4
- package/docs/api-usage.md +8 -1
- package/docs/api.md +2 -2
- package/docs/cli.md +1 -1
- package/docs/introduction.md +6 -4
- package/docs/self-hosting.md +48 -10
- package/docs/versions.md +2 -2
- package/package.json +5 -4
- package/src/commands.mjs +16 -10
package/LICENSE
CHANGED
|
@@ -1,39 +1,105 @@
|
|
|
1
|
-
|
|
1
|
+
# Functional Source License, Version 1.1, ALv2 Future License
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Abbreviation
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
foldrun. They are licensed, not sold.
|
|
5
|
+
FSL-1.1-ALv2
|
|
7
6
|
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
|
|
21
|
-
files) is yours.
|
|
11
|
+
## Terms and Conditions
|
|
22
12
|
|
|
23
|
-
|
|
24
|
-
dependencies) remain under their own licences.
|
|
13
|
+
### Licensor ("We")
|
|
25
14
|
|
|
26
|
-
|
|
27
|
-
stop using the software.
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
28
16
|
|
|
29
|
-
|
|
30
|
-
remain available under that licence for those versions only.
|
|
17
|
+
### The Software
|
|
31
18
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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 —
|
|
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
|
-
|
|
238
|
-
|
|
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/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
|
@@ -343,7 +343,7 @@ Reads return which secrets exist, never their values.
|
|
|
343
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 |
|
|
344
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 |
|
|
345
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 |
|
|
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; the
|
|
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` |
|
|
347
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` |
|
|
348
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 |
|
|
349
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 |
|
|
@@ -419,7 +419,7 @@ so a client learns what it is talking to without a second request:
|
|
|
419
419
|
|
|
420
420
|
```
|
|
421
421
|
X-Foldrun-Version: v2026.10.01.3 # the platform's version
|
|
422
|
-
X-Foldrun-Api: 2026-10-
|
|
422
|
+
X-Foldrun-Api: 2026-10-26 # the API contract — moves only on a breaking change
|
|
423
423
|
X-Foldrun-Cli: 0.6.0 # the CLI released with this version (absent when unknown)
|
|
424
424
|
```
|
|
425
425
|
|
package/docs/cli.md
CHANGED
|
@@ -149,7 +149,7 @@ claude.ai or Claude Code there, nor any MCP configuration on disk.
|
|
|
149
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 |
|
|
150
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`) |
|
|
151
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` |
|
|
152
|
-
| `foldrun billing credit <usd>` | put credit on the balance by hand (`POST /api/billing { usd, note }`, `--note "…"` on the ledger line) —
|
|
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 |
|
|
153
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 |
|
|
154
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` |
|
|
155
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) |
|
package/docs/introduction.md
CHANGED
|
@@ -32,12 +32,14 @@ The design bets on three things:
|
|
|
32
32
|
| | you need | what runs where |
|
|
33
33
|
|---|---|---|
|
|
34
34
|
| **Locally** | `npm install -g foldrun` and a model key | everything on your machine; no account, no server |
|
|
35
|
-
| **
|
|
35
|
+
| **Your own server** | Docker and the public repositories | the whole platform on one machine of yours, for you or your organisation |
|
|
36
|
+
| **Hosted** | an account | ours: schedules, sandboxes, a vault, a team — nothing to run |
|
|
36
37
|
|
|
37
38
|
The same workspace moves between them with `foldrun deploy`.
|
|
38
|
-
Start locally; that is where every workspace should be born.
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
Start locally; that is where every workspace should be born. foldrun is
|
|
40
|
+
source-available under the Functional Source License: free for your own
|
|
41
|
+
use and your organisation's, not for offering it to others as a service —
|
|
42
|
+
see [Running it yourself](self-hosting).
|
|
41
43
|
|
|
42
44
|
## Where to go
|
|
43
45
|
|
package/docs/self-hosting.md
CHANGED
|
@@ -1,20 +1,58 @@
|
|
|
1
1
|
# Running it yourself
|
|
2
2
|
|
|
3
|
-
There are
|
|
3
|
+
There are three places a workspace runs, and the same folder moves between
|
|
4
4
|
them unchanged.
|
|
5
5
|
|
|
6
6
|
| shape | for | what is yours |
|
|
7
7
|
|---|---|---|
|
|
8
8
|
| **your machine** | one person, no server — the foldrun CLI and runtime, free from npm | everything: the files, the runs, the model bill |
|
|
9
|
-
| **
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
| **your own server** | you or your organisation on one machine: the dashboard, schedules, sandboxes, gates, a vault and a team, with Docker Compose | everything, and the machine |
|
|
10
|
+
| **the hosted platform** | a team that would rather not run anything | your workspaces and their records; we run the machines |
|
|
11
|
+
|
|
12
|
+
foldrun is **source-available** under the Functional Source License 1.1
|
|
13
|
+
(FSL-1.1-ALv2): the format, the runner, the checks, the CLI, the engine and
|
|
14
|
+
the dashboard are free to use, change and run for yourself and inside your
|
|
15
|
+
own organisation, at any size. What needs a commercial licence is offering
|
|
16
|
+
foldrun to others as a product or service that competes with it. Each
|
|
17
|
+
release becomes Apache 2.0 two years after it ships. The licence and a
|
|
18
|
+
plain-English summary are in each repository (`LICENSE`, `LICENSING.md`);
|
|
19
|
+
for a commercial licence, write to hello@foldrun.io.
|
|
20
|
+
|
|
21
|
+
A self-hosted server has no billing: nothing is charged, and spend budgets
|
|
22
|
+
(`budget:`) still hold.
|
|
23
|
+
|
|
24
|
+
## Your own server
|
|
25
|
+
|
|
26
|
+
One machine with Docker. The platform runs in one container — the dashboard,
|
|
27
|
+
the API, the scheduler and the queue — and every agent step runs in a
|
|
28
|
+
throwaway container beside it, started through the Docker socket.
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
mkdir foldrun && cd foldrun
|
|
32
|
+
for r in foldrun-core foldrun-platform foldrun-web foldrun-docs; do
|
|
33
|
+
git clone https://github.com/foldrun-io/$r
|
|
34
|
+
done
|
|
35
|
+
cd foldrun-web/self-hosting
|
|
36
|
+
echo "FOLDRUN_SECRET_KEY=$(openssl rand -hex 32)" > .env
|
|
37
|
+
echo "FOLDRUN_PUBLIC_URL=http://<host>:3900" >> .env # the address people open
|
|
38
|
+
docker compose up -d --build
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Then open `http://<host>:3900/signup` (the first account needs no flag),
|
|
42
|
+
sign the CLI in to it, and deploy an account folder:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
npm install -g foldrun
|
|
46
|
+
foldrun login --url http://<host>:3900 # approve in the browser; or --token <a key from Settings>
|
|
47
|
+
foldrun deploy # from the account folder
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`docker-compose.yml` beside the Dockerfile lists every setting with what it
|
|
51
|
+
does: the install's model key (or none, and each account brings its own),
|
|
52
|
+
open sign-up (off), retention. `FOLDRUN_PUBLIC_URL` is required: CLI sign-in,
|
|
53
|
+
approve links, password resets and shares are made with it, so it must be
|
|
54
|
+
the address people actually open. Back up the `foldrun-data` volume and `FOLDRUN_SECRET_KEY` and
|
|
55
|
+
you have backed the install up.
|
|
18
56
|
|
|
19
57
|
## Your machine
|
|
20
58
|
|
package/docs/versions.md
CHANGED
|
@@ -119,8 +119,8 @@ whatever `FOLDRUN_VERSION` it was started with.
|
|
|
119
119
|
## The API version
|
|
120
120
|
|
|
121
121
|
`api` in `/api/version`, and the `X-Foldrun-Api` header, is a date —
|
|
122
|
-
`2026-10-01` — that changes only when a route changes
|
|
123
|
-
caller would break on. A new route or a new field in an answer does not move
|
|
122
|
+
`2026-10-26` now, after `2026-10-01` — that changes only when a route changes
|
|
123
|
+
in a way an existing caller would break on ([the list](api-usage#versions)). A new route or a new field in an answer does not move
|
|
124
124
|
it. Breaking changes are announced in the release notes of the version that
|
|
125
125
|
makes them.
|
|
126
126
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "foldrun",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.1",
|
|
4
4
|
"description": "Agents are just folders. Write them, check them, run them — on your machine.",
|
|
5
|
-
"license": "
|
|
5
|
+
"license": "FSL-1.1-ALv2",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"foldrun": "bin/foldrun.mjs"
|
|
@@ -11,12 +11,13 @@
|
|
|
11
11
|
"node": ">=22"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@foldrun/core": "^2.
|
|
14
|
+
"@foldrun/core": "^2.12.1"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"bin",
|
|
18
18
|
"src",
|
|
19
19
|
"README.md",
|
|
20
|
+
"LICENSING.md",
|
|
20
21
|
"docs"
|
|
21
22
|
],
|
|
22
23
|
"scripts": {
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@types/node": "^26.6.4",
|
|
48
49
|
"gray-matter": "^4.0.3",
|
|
49
|
-
"typescript": "^
|
|
50
|
+
"typescript": "^7.0.2"
|
|
50
51
|
},
|
|
51
52
|
"overrides": {
|
|
52
53
|
"zod": "4.6.7"
|
package/src/commands.mjs
CHANGED
|
@@ -883,6 +883,7 @@ async function scanCore() {
|
|
|
883
883
|
}
|
|
884
884
|
|
|
885
885
|
// The scanner module, once scanCore has loaded it — categoryOf and SARIF read it.
|
|
886
|
+
/** @type {any} */
|
|
886
887
|
let scanRules = null;
|
|
887
888
|
|
|
888
889
|
const SECURITY_CATEGORIES = new Set(["secret", "security", "content", "supply-chain"]);
|
|
@@ -1027,6 +1028,7 @@ function narrowCheck(findings, root, opts, label, accountRoot = root) {
|
|
|
1027
1028
|
}
|
|
1028
1029
|
let baselined = 0;
|
|
1029
1030
|
if (opts.baseline && fs.existsSync(file)) {
|
|
1031
|
+
/** @type {any} */
|
|
1030
1032
|
let b = null;
|
|
1031
1033
|
try {
|
|
1032
1034
|
b = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
@@ -1540,6 +1542,7 @@ async function checkHooks(workspace, agents, libraryRoot, platform, note) {
|
|
|
1540
1542
|
missing("account AGENTS.md", accountNames);
|
|
1541
1543
|
missing("AGENTS.md", workspaceNames);
|
|
1542
1544
|
|
|
1545
|
+
/** @type {any} */
|
|
1543
1546
|
let resolveSearch = null;
|
|
1544
1547
|
try {
|
|
1545
1548
|
({ resolveSearch } = /** @type {any} */ (await import("@foldrun/core/providers")));
|
|
@@ -1812,6 +1815,7 @@ async function probeCmd(modelArg) {
|
|
|
1812
1815
|
// provider gets the same translator a run would, on loopback, for the
|
|
1813
1816
|
// length of the probe — so what passes here passes there.
|
|
1814
1817
|
let env = { ...process.env };
|
|
1818
|
+
/** @type {any} */
|
|
1815
1819
|
let translator = null;
|
|
1816
1820
|
// No AGENTS.md, or no provider block, means Anthropic direct — like a run.
|
|
1817
1821
|
// Anything else that goes wrong here is said, not swallowed: a provider
|
|
@@ -2446,6 +2450,7 @@ async function versionCmd(flags) {
|
|
|
2446
2450
|
const url = remoteUrl(flags);
|
|
2447
2451
|
/** @type {Record<string, any> | null} */
|
|
2448
2452
|
let platform = null;
|
|
2453
|
+
/** @type {string | null} */
|
|
2449
2454
|
let unreachable = null;
|
|
2450
2455
|
if (url) {
|
|
2451
2456
|
try {
|
|
@@ -3671,6 +3676,7 @@ async function connect(positional, flags) {
|
|
|
3671
3676
|
// secret, nothing typed. The redirect is the platform's own callback, which
|
|
3672
3677
|
// rewrites the same secret at the same scope; we wait for it to land.
|
|
3673
3678
|
if (url && !flags["client-id"] && !env("OAUTH_CLIENT_ID") && flags["new-client"] !== true) {
|
|
3679
|
+
/** @type {any} */
|
|
3674
3680
|
let started = null;
|
|
3675
3681
|
try {
|
|
3676
3682
|
started = await remoteCall(url, flags, "/api/oauth/reconnect", {
|
|
@@ -4492,6 +4498,7 @@ async function deployAccount(layout, flags, only) {
|
|
|
4492
4498
|
|
|
4493
4499
|
/** "<profile> (<email or key label>)" — who a deploy is about to act as,
|
|
4494
4500
|
* asked of the platform once per command. */
|
|
4501
|
+
/** @type {string | null} */
|
|
4495
4502
|
let identityCache = null;
|
|
4496
4503
|
async function deployIdentity(url, flags) {
|
|
4497
4504
|
if (identityCache) return identityCache;
|
|
@@ -4889,6 +4896,7 @@ async function pullCmd(layout, flags, only) {
|
|
|
4889
4896
|
|
|
4890
4897
|
let written = 0;
|
|
4891
4898
|
for (const f of incoming) {
|
|
4899
|
+
/** @type {string | null} */
|
|
4892
4900
|
let before = null;
|
|
4893
4901
|
try {
|
|
4894
4902
|
before = fs.readFileSync(f.file, "utf8");
|
|
@@ -4968,6 +4976,7 @@ async function workspacesCmd(positional, flags, layout) {
|
|
|
4968
4976
|
|
|
4969
4977
|
const here = layout.workspaces;
|
|
4970
4978
|
let there = [];
|
|
4979
|
+
/** @type {string | null} */
|
|
4971
4980
|
let reach = null;
|
|
4972
4981
|
if (url) {
|
|
4973
4982
|
try {
|
|
@@ -5591,16 +5600,12 @@ async function billingCmd(flags) {
|
|
|
5591
5600
|
const entries = body.entries ?? [];
|
|
5592
5601
|
|
|
5593
5602
|
console.log(`\n ${balance > 0 ? c.green("✓") : c.red("✗")} balance ${c.bold(`$${balance.toFixed(2)}`)} ${c.dim(body.enabled ? "billing on" : "billing off — nothing is charged on this install")}`);
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
// absorbed, and that is the state people mistake for "it is working".
|
|
5601
|
-
const waived = [...new Set(entries.flatMap((e) => e.waived ?? []))];
|
|
5602
|
-
if (waived.length) {
|
|
5603
|
-
console.log(` ${c.amber("⏸")} ${c.dim(`${waived.join(", ")} ${waived.length === 1 ? "is" : "are"} being waived on recent runs — those lines are charged $0`)}`);
|
|
5603
|
+
// What the account should be told — an empty wallet, an overdraft, a
|
|
5604
|
+
// waiver — as the platform words it: it knows the gate, the overdraft and
|
|
5605
|
+
// the waivers; the numbers here do not say enough to guess.
|
|
5606
|
+
for (const notice of Array.isArray(body.notices) ? body.notices : []) {
|
|
5607
|
+
const empty = /wallet is empty/.test(notice);
|
|
5608
|
+
console.log(` ${empty ? c.red("✗") : c.amber("⏸")} ${empty ? notice : c.dim(notice)}`);
|
|
5604
5609
|
}
|
|
5605
5610
|
|
|
5606
5611
|
const limit = Number(flags.limit) > 0 ? Math.floor(Number(flags.limit)) : 15;
|
|
@@ -8068,6 +8073,7 @@ function writeIfUnchanged(desk, rel, before, next) {
|
|
|
8068
8073
|
|
|
8069
8074
|
/** Throw, as writeIfUnchanged does, when a desk file no longer reads `before`. */
|
|
8070
8075
|
function assertUnchanged(desk, rel, before) {
|
|
8076
|
+
/** @type {string | null} */
|
|
8071
8077
|
let now = null;
|
|
8072
8078
|
try {
|
|
8073
8079
|
now = fs.readFileSync(path.join(desk.dir, rel), "utf8");
|