foldrun 0.6.0 → 0.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.
@@ -0,0 +1,65 @@
1
+ # Running it yourself
2
+
3
+ There are two places a workspace runs, and the same folder moves between
4
+ them unchanged.
5
+
6
+ | shape | for | what is yours |
7
+ |---|---|---|
8
+ | **your machine** | one person, no server — the open-source CLI and runtime | everything: the files, the runs, the model bill |
9
+ | **the hosted platform** | a team; schedules, sandboxes, gates, a vault, a dashboard | your workspaces and their records; we run the machines |
10
+
11
+ The framework — the format, the runner, the checks, the CLI — is Apache-2.0
12
+ on [GitHub](https://github.com/foldrun-io) and npm. The platform that runs it
13
+ for other people (the queue and its worker, per-step sandboxes on a cluster,
14
+ metering, tenancy) is ours and is not distributed: there is no self-hosted
15
+ platform. If you need it inside your own network, that is a conversation —
16
+ write to hello@foldrun.io.
17
+
18
+ ## Your machine
19
+
20
+ ```sh
21
+ npm install -g foldrun
22
+ export ANTHROPIC_API_KEY=... # an API key; or any provider via provider:
23
+ foldrun init my-desk
24
+ cd my-desk && foldrun check && foldrun run publish
25
+ ```
26
+
27
+ Everything the format defines works here: agents, flows with groups and
28
+ gates, tools in any language, skills, knowledge bundles, evals, `verify:`,
29
+ `each:`, `budget:`. Runs are recorded under `.foldrun/` beside the workspace;
30
+ secrets set with `foldrun secrets set` are encrypted there under a key the
31
+ CLI makes on first use.
32
+
33
+ What is different from the platform, and why:
34
+
35
+ - **No schedules.** Nothing is running when your laptop is closed. `foldrun
36
+ run` is the trigger; cron on your own machine works if you want one.
37
+ - **No sandbox by default.** Steps run as your user, in your workspace. Set
38
+ `FOLDRUN_RUN_ISOLATION=container` with Docker installed to get one hardened
39
+ container per step, the same executor the platform's single-box shape uses.
40
+ - **Gates wait in the terminal.** A `!` step parks the run; `foldrun run`
41
+ shows the approval and waits for your answer.
42
+ - **Budgets cap, and nothing meters.** `budget:` stops a run at its cap; the
43
+ cost of each step is on the record. No invoice, because the model bill is
44
+ yours.
45
+
46
+ ## Moving to the platform
47
+
48
+ ```sh
49
+ foldrun login
50
+ foldrun deploy # this folder → a workspace with the same name
51
+ ```
52
+
53
+ Or push it: every workspace on the platform is a git remote. Nothing about
54
+ the folder changes. What the platform adds is the operating around it —
55
+ [Scheduling](scheduling), [Runs](runs) in gVisor sandboxes,
56
+ [Secrets](secrets) in a vault, [Notifications](notifications),
57
+ [Budgets and billing](budgets-and-billing), [Team and access](team-and-access).
58
+
59
+ ## Where the data is
60
+
61
+ On your machine: in the folder. On the platform: your workspace's files and
62
+ every run's record, on our data volume and in the file store, readable
63
+ through the dashboard and the API, exportable as a git clone. A deploy never
64
+ touches what an agent learned or a run recorded. See [Storage and
65
+ sharing](storage-and-sharing) and [Security](security).
package/docs/status.md ADDED
@@ -0,0 +1,73 @@
1
+ # Status and incidents
2
+
3
+ Is it us or is it you? The platform answers that itself, in three places
4
+ that read the same record:
5
+
6
+ - **The status page** — [foldrun.io/status](https://foldrun.io/status/). A
7
+ static page on the website, not on the platform, so it still loads when
8
+ the platform does not. If it cannot reach the platform it says so: *status
9
+ unavailable — the platform may be down*, which is itself the answer.
10
+ - **The dashboard banner** — an amber line across every page during
11
+ maintenance or a minor incident, red during a major one, with the latest
12
+ update. It goes when the incident is resolved. **Status** in the account
13
+ menu opens the status page.
14
+ - **`foldrun status --platform`** — the same, in a terminal (`--json` for a
15
+ script). Plain `foldrun status`, which compares your folder with what is
16
+ deployed, now opens with one line saying whether the platform is
17
+ operational and lists any live incident.
18
+
19
+ ## What each component means
20
+
21
+ | Component | Operational when | Measured from |
22
+ |---|---|---|
23
+ | Dashboard and API | the web tier answers and its database does | the request itself; the worker also fetches `/api/healthz` through the public address every five minutes |
24
+ | Run workers | a worker holds the lease and nothing queued has waited over ten minutes | the worker lease and the queue's oldest job |
25
+ | Scheduler | it has ticked in the last fifteen minutes | the samples themselves — they are written from inside the scheduler's tick, so a stale sample *is* a stopped scheduler |
26
+ | Model providers | `api.anthropic.com` answers, and fewer than two step attempts in the last hour failed with a provider error (overloaded, rate limited, a 5xx; a refused credential only when two accounts saw one — one account's own expired key is that account's) | a reachability check, and the run records |
27
+ | Email | `api.resend.com` answers | a reachability check; `unknown` on an install without a platform mail key |
28
+ | Storage | the database answers and the workspace volume is writable | the same checks `healthz` makes |
29
+
30
+ Each is `operational`, `degraded`, `outage`, `maintenance` or `unknown`
31
+ (not measured — not counted against uptime). An incident or maintenance
32
+ window the operator posted raises the components it names: a minor incident
33
+ to `degraded`, a major one to `outage`.
34
+
35
+ ## Uptime history
36
+
37
+ Every five minutes the worker that holds the scheduler lease records one
38
+ sample per component. Ninety days are kept. A day's uptime is the share of
39
+ its measured samples that were not an outage; a day with no samples has no
40
+ figure rather than a hundred per cent. The status page draws these as 90
41
+ bars per component, with the incidents of the same period below.
42
+
43
+ These are the platform's own measurements of itself, from inside. They do
44
+ not see a network problem between you and the platform — the page saying
45
+ *unavailable* does.
46
+
47
+ ## Incidents and maintenance
48
+
49
+ The super admin posts them from **Admin → Incidents** (or
50
+ `/api/admin/incidents`): a title, what customers should read, the impact
51
+ (minor or major) and the components affected. Each update adds a line with
52
+ a status — `investigating`, `identified`, `monitoring`, `resolved`.
53
+ Maintenance is a window with a start and an end; it shows as upcoming before
54
+ it starts and as `maintenance` while it runs. Incidents are resolved, not
55
+ deleted, so the history stays; deleting is for one posted by mistake. Every
56
+ change is in the audit log as `status.*`.
57
+
58
+ What customers see never includes who wrote an update.
59
+
60
+ ## Reading it from code
61
+
62
+ `GET /api/status` and `GET /api/status/history?days=90` are open — no key —
63
+ and readable cross-origin from foldrun.io. See [the API](api) for the
64
+ shapes. The answer to `/api/status` is cached for fifteen seconds and never
65
+ calls a provider per request.
66
+
67
+ ## On your own install
68
+
69
+ The same routes and sampler run on a self-hosted install. Point the
70
+ dashboard's **Status** link at your own page with `FOLDRUN_STATUS_PAGE_URL`,
71
+ allow your page's origin with `FOLDRUN_STATUS_ORIGINS`, and see
72
+ [Environment](environment) for the rest. Without a database, samples and
73
+ incidents are files under `<data>/status/`.
@@ -0,0 +1,118 @@
1
+ # Storage and sharing
2
+
3
+ Two kinds of file live in a workspace, and the dashboard shows them on two
4
+ pages. **Files** is the markdown source — agents, flows, tools, knowledge —
5
+ the thing you edit and deploy. **Storage** is bytes: what agents produce
6
+ and what people upload — reports, CSVs, images, PDFs. This page is about the
7
+ second.
8
+
9
+ ## Where it lives, from an agent's point of view
10
+
11
+ An agent writes a deliverable to `workspace/storage/` (the older
12
+ `../../storage/` is the same place) and it appears on the workspace's Storage page after the
13
+ step, kept and downloadable. Uploads dropped on that page land in the same
14
+ directory and are there for the next run to read.
15
+
16
+ Two neighbours are not storage:
17
+
18
+ - **`outputs/`** is the step's scratch, archived with the run — read it from
19
+ the run page, not from Storage.
20
+ - **`state/`** is what the next run needs — a cursor, a history line — and a
21
+ person rarely reads it.
22
+
23
+ The rule: a value regenerated each run is `storage/`; a value accumulated
24
+ across runs is `state/`.
25
+
26
+ ## Limits
27
+
28
+ One object up to 512 MB; a workspace up to 5 GB, shown on the Storage page.
29
+ Both are platform settings (`FOLDRUN_STORAGE_MAX_MB`,
30
+ `FOLDRUN_STORAGE_QUOTA_MB`). Storage is metered per GB-month where billing is
31
+ on.
32
+
33
+ ## Under the hood
34
+
35
+ Blobs are content-addressed and go to object storage (S3-compatible — R2, S3
36
+ — or local disk on a small install); the index of what exists stays with the
37
+ workspace. Uploading the same bytes under a second name costs nothing, and a
38
+ rename moves no data. A run pod never holds the bucket credential: it reads
39
+ and writes through presigned URLs, so a step that goes wrong cannot list or
40
+ delete what other workspaces stored.
41
+
42
+ ## Sharing a file
43
+
44
+ Some work is not done until something outside can fetch the bytes — a
45
+ Google Business Profile post will not accept image data and wants a URL it
46
+ can GET for itself. A share is a public link to one file:
47
+
48
+ ```
49
+ POST /api/workspaces/<ws>/shares { "path": "storage/cover.jpg", "ttlDays": 7 }
50
+ → https://<your-install>/s/<token>
51
+ ```
52
+
53
+ or **Share** on the run page's Out column, or on the Storage page, or from
54
+ the terminal:
55
+
56
+ ```
57
+ foldrun storage share cover.jpg --to <ws> # 7 days; --ttl 30, or --forever
58
+ foldrun storage shares --to <ws> # live links; --all shows expired and revoked
59
+ foldrun storage unshare <token> --to <ws>
60
+ ```
61
+
62
+ - Links expire in **7 days** unless you say otherwise; `null` never expires.
63
+ - The token is 24 random bytes and never derived from the path; every failed
64
+ fetch is the same 404, so a guesser learns nothing.
65
+ - Only `storage/`, `outputs/` and `files/` can be shared. An agent talked
66
+ into sharing is confined to what the workspace produced and can never hand
67
+ out `memory/`, a prompt, or a credential.
68
+ - Revoking is permanent; a re-share mints a new token.
69
+
70
+ Files written under **`storage/public/`** get a link automatically after the
71
+ run — for the agent that needs a URL for what it just produced.
72
+
73
+ Shares need the install to know its public address (`FOLDRUN_PUBLIC_URL`);
74
+ without it the request answers `409` rather than minting a link that only
75
+ works from inside.
76
+
77
+ A share is a record the platform keeps, not a file in the workspace: minted
78
+ from the dashboard or after a step, it lands in the platform's database,
79
+ so every web and worker process sees the same links and a link survives a
80
+ workspace being redeployed.
81
+
82
+ ## The account view
83
+
84
+ Storage at the account level lists every workspace as its own section, each
85
+ closed until you open it, with each file's size, age and share state. It is a
86
+ view: a run still sees only its own workspace's folder.
87
+
88
+ You can upload any file, of any type, to any workspace from there. Use
89
+ **Upload** in the toolbar and pick the workspace, use the **Upload** button on
90
+ a workspace's section, or drop files onto that section. From a terminal,
91
+ `foldrun storage put` does the same, and it takes folders whole:
92
+
93
+ ```sh
94
+ foldrun storage put report.pdf photos/ --into inspections/ --to blog-desk
95
+ foldrun storage put draft.md --as drafts/today.md --to blog-desk
96
+ ```
97
+
98
+ ## Previews
99
+
100
+ Click a file to read it without downloading it. Images, video, audio, PDFs
101
+ and fonts play in the browser as themselves. Everything else is parsed on the
102
+ server and drawn as what it is:
103
+
104
+ | What | Formats |
105
+ |---|---|
106
+ | text and code | txt, md, mdx, json, yaml, csv as a table, source files, logs, anything that reads as text |
107
+ | office | docx, xlsx, pptx, odt, ods, odp, rtf; legacy doc, xls and ppt as their text |
108
+ | Apple and design | pages, numbers, key, sketch, xd by the preview picture inside them |
109
+ | camera and layered images | RAW (cr2, nef, arw, dng and others), psd, tiff, heic by their embedded preview; svg and svgz as a picture |
110
+ | mail and contacts | eml, mht, ics, vcf |
111
+ | notebooks and links | ipynb, url, webloc |
112
+ | archives | zip, tar, tgz, gz by their contents; 7z, rar and others by name only |
113
+ | 3D | stl, obj, ply, glb, drawn and turned by dragging |
114
+
115
+ A stored web page opens in a sandboxed frame with scripts off, and an SVG
116
+ only as an image, so a file cannot run code on the dashboard. Anything the
117
+ preview cannot read shows its first bytes, and the download button always
118
+ gives the file itself. Files over 25 MB are not previewed.
@@ -0,0 +1,146 @@
1
+ # Team and access
2
+
3
+ Every member and every API key has a role, and every write route asks for
4
+ the least role that may take that action. Reads are open to every role: a
5
+ viewer sees everything, including run output and files, because a platform
6
+ whose supervisors cannot see what the agents did is not supervised.
7
+
8
+ ## Roles
9
+
10
+ | role | may |
11
+ |---|---|
12
+ | **viewer** | read everything — workspaces, runs and their output, files, history, usage |
13
+ | **editor** | + edit files, upload, deploy, push; run, stop, re-run, approve and promote runs; test tools |
14
+ | **admin** | + create and delete workspaces; write secrets and connect credentials; mint keys; invite, re-role and remove editors and viewers |
15
+ | **owner** | + billing; make and unmake admins; transfer the account |
16
+
17
+ There is exactly one owner: the account's creator until they transfer it.
18
+ The owner is never re-roled or removed — transfer first. Nobody changes their
19
+ own role, and an admin cannot make or remove another admin: an admin who can
20
+ promote peers is an owner with extra steps.
21
+
22
+ A refused call answers `403` with the role that was needed.
23
+
24
+ ## Scoped members
25
+
26
+ A member can be limited to some workspaces. The customer whose desk lives in
27
+ one workspace sees that workspace's runs and files and nothing else; the
28
+ sidebar, Find, the runs list and the approvals banner all filter to their
29
+ scope. Scope is set on the invite and changed per member later.
30
+
31
+ Secrets and OAuth connections follow the scope too. A scoped member or key
32
+ sees and changes only its own workspaces' secrets and connections: not
33
+ another workspace's, and not the account-level ones, which belong to
34
+ everyone's workspaces at once.
35
+
36
+ ## Invites
37
+
38
+ An invite carries a role, a workspace scope, and an email address it is bound
39
+ to — only that address can accept it. It is sent through the account's email
40
+ connection, or returned as a link to pass on yourself.
41
+
42
+ ## API keys
43
+
44
+ A key is minted with a role (`editor` unless you say otherwise) and acts as
45
+ the account with that role. It can never be wider than the person who made
46
+ it: not a higher role, and not a workspace they cannot open — a key minted
47
+ by someone scoped to two workspaces is scoped to those two. The git remote
48
+ honours the same scope: pushing needs write on that workspace, and pushing
49
+ the library needs admin. Two things a key cannot do: act against a named
50
+ member — inviting, re-roling, removing, transferring need a signed-in person,
51
+ because a key names an account and never a who — and exceed its role.
52
+ A scoped admin sees and revokes only keys inside its own scope; a key wider
53
+ than that, the owner's included, is not in its list.
54
+
55
+ **Deploy keys** are keys scoped to one workspace's git remote, read or write.
56
+ They clone and push that workspace and are refused everywhere else, which is
57
+ what a CI job or a contractor's checkout should hold.
58
+
59
+ A key **is** its account: the platform reads the account off the key, so one
60
+ account's key can never reach another's workspaces. Someone who looks after
61
+ several accounts — an agency, a reseller — holds one key per account and
62
+ switches between them; the CLI stores each as a named profile. See
63
+ [More than one account](cli#more-than-one-account).
64
+
65
+ ### Expiry, last use and rotation
66
+
67
+ A key can be given an end when it is minted — 30, 90 or 365 days, or never
68
+ (Settings → API keys offers 90 days first; `foldrun keys create ci --expires
69
+ 90d`; the API's `expires`). After it, the key is refused with a 401 that
70
+ says it expired and on which day. The owner is emailed seven days before any
71
+ key ends, once per key.
72
+
73
+ Every key shows when it was created, when it was **last used** and roughly
74
+ from where — the address cut to its /24 (or /48 for IPv6), never the whole
75
+ of it. Last use is written at most once a minute per key, so a busy CI key
76
+ does not turn every request into a write.
77
+
78
+ **Rotate** mints a new key with the old one's label, role, workspaces and
79
+ deploy scope — and, if the old one had an end, the same lifetime from today —
80
+ and ends the old key: at once, or after a grace of an hour or a day so a CI
81
+ job can be moved across first. In the dashboard it is the Rotate button on
82
+ the key; `foldrun keys rotate <id> --grace 1h`; `POST /api/keys/<id>/rotate`.
83
+
84
+ A key is rotated **once**. While the old key runs out its grace it shows
85
+ **rotated → <new key>** (in `foldrun keys ls` too), and rotating it again is
86
+ refused with `this key was already rotated to <prefix>…; rotate that one`.
87
+ Lost the new key's secret? Rotate the **new** key: that mints another and
88
+ ends the lost one. Rotating the old key again would have left the lost key
89
+ working.
90
+
91
+ ## Audit log
92
+
93
+ Settings → Audit log is the account's record of what people did: sign-ins
94
+ (and refused ones), sign-outs and session revokes, password and email
95
+ changes, MFA turned on or off, keys minted, rotated and revoked, invites,
96
+ joins, role and scope changes, removals and ownership transfers, secrets
97
+ set and deleted — **by name, never the value** — deploys, workspace deletes,
98
+ plan and billing changes, the account export and a close request, and every
99
+ time support viewed the account. Filter by time, action, person or
100
+ workspace, page back, and download it as CSV for an auditor.
101
+
102
+ The owner and admins who can open every workspace read it — people, or an
103
+ `admin` key. A member or key scoped to some workspaces cannot: the log is
104
+ the whole account's. It is the caller's own account, always; another
105
+ account's entries are never in it. Entries are kept for the life of the
106
+ account (no plan sets a shorter retention) and go when the account is
107
+ deleted. Also `GET /api/audit` and `foldrun audit --since 7d --csv`.
108
+
109
+ What agents did is a different record: every run's trail, under Runs.
110
+
111
+ ## Support access
112
+
113
+ When you ask for help, foldrun support may open your account **read-only**
114
+ to look: your dashboard as the owner sees it, for thirty minutes at most.
115
+ They must give a reason, and it lands in your audit log word for word —
116
+ "support viewed your account: Ticket 42: daily flow not starting" — with
117
+ another line when the view ends. While it is open every change is refused,
118
+ in one place for every route: nothing can be run, deployed, edited,
119
+ invited, revoked or paid for, and the account export is refused too. The
120
+ support person sees a bar on every page saying whose account it is, that it
121
+ is read-only, how many minutes are left, and an Exit.
122
+
123
+ There is no API key or CLI command for this, on purpose: looking inside a
124
+ customer's account is an act a named person owns, from a browser, with a
125
+ reason you can read.
126
+
127
+ ## Sessions
128
+
129
+ Signing in creates a session; your Profile page lists them and revokes any
130
+ one of them, which signs that device out without touching the others.
131
+ Changing your password or email signs out every other session, and says
132
+ how many. Sign-
133
+ ins, key use and role changes are written to the account's audit log.
134
+
135
+ ## Appearance
136
+
137
+ The dashboard comes in light and dark. **Profile → Appearance** picks one:
138
+ **System** (the default) follows your computer's light or dark setting,
139
+ **Light** and **Dark** stay put whatever it says. The choice is yours alone
140
+ — it is kept on your profile, not in the browser, so it follows you to every
141
+ browser you sign in on, and the page is drawn in it from the first paint.
142
+ The sign-in pages, before anyone is signed in, follow the computer.
143
+
144
+ The API is `GET` / `PATCH /api/me/preferences` with `{ theme }`. There is no
145
+ CLI verb: a theme is how a browser draws the dashboard, and a terminal
146
+ already draws in its own colours.