BulkForge
<!-- GENERATED by ops/tools/skill-sync — do not edit by hand. Run pnpm skills:sync. -->
<!-- GENERATED by ops/tools/skill-sync — do not edit by hand. Run pnpm skills:sync. -->
BulkForge — what you can do
/admin/d/bulkforge · pillar apps
Run one function, or a chain of them, over a list of items, and get a table back.
Fetch this, never remember it
These change per install and per release. Call for them - a list written here would be a future lie.
| What | Call | Why |
|---|---|---|
| the ready-made batches this install ships | POST /api/adapters/bulkforge/presets | POST, not GET — /api/adapters/:system/:fn is POST-only because running an adapter is an action with side effects, and the route is gated and metered on that basis. The answer is wrapped in { result }. |
| exactly what a batch WOULD call, before running anything | POST /api/adapters/bulkforge/preview | it resolves every template against the first few items and calls nothing. This is how a wrong token is caught for the price of one request instead of five thousand failures. |
| one item end to end, for debugging | POST /api/adapters/bulkforge/runOne | preview shows what would be called; this actually calls it, once. The fastest way to find out why a batch is failing without paying for the batch. |
| what is callable at all — the thing a step points at | GET /api/function-index/entries?q=<text> | the catalogue is per-install and grows as the operator wires things up; a remembered list is wrong the day after it is written. GET /api/function-index/entry/:id gives its declared inputs. |
| the batches that have run, and what came out | GET /api/jobs?kind=bulkforge.batch | a run IS a job row; there is no second record of it. |
Tabs
Every one is a real URL. A tab with its own section below carries a real job.
| Tab | Path | Group | What it is for |
|---|---|---|---|
forge | /admin/d/bulkforge | - | Pick a preset, pick a list, preview, then run — inline for a try, queued for real work. |
lists | /admin/d/bulkforge/lists | - | Build and keep the item sets batches run over. |
runs | /admin/d/bulkforge/runs | - | The queue: watch a batch, cancel it, and read the table it produced. |
Tabs in focus
forge - Forge
Pick a preset, pick a list, preview, then run — inline for a try, queued for real work.
Address: /admin/d/bulkforge
Read with: POST /api/adapters/bulkforge/presets | GET /db/bulkforge_list
Write with: POST /api/adapters/bulkforge/run | POST /api/jobs
- Choose the callable. A preset is a starting point, not a fixed menu — the executor is a { kind, ref } descriptor and can point at anything in the function index.
- Choose the items: a saved list by id, or pasted text split one per line.
- Preview. Read the resolved args, not just the status.
- Run now for under 200 items; queue anything bigger.
Trap: Run now is CAPPED at 200 items and answers 413 past that, on purpose: an HTTP request cannot promise a five-thousand-row batch anything — nothing survives a restart, nothing can be cancelled, and the client that disconnects takes the answer with it. When a saved list is picked the job is sent its listId, not the expanded items, so the batch reflects the list as it is when it RUNS.
lists - Lists
Build and keep the item sets batches run over.
Address: /admin/d/bulkforge/lists
Read with: GET /db/bulkforge_list
Write with: POST /db/bulkforge_list | PUT /db/bulkforge_list/:id | DELETE /db/bulkforge_list/:id
Trap: A list is a separate record from a batch on purpose — the same list runs through several setups and the same setup points at several lists. Blank lines and duplicates are dropped on save, order is kept.
runs - Runs
The queue: watch a batch, cancel it, and read the table it produced.
Address: /admin/d/bulkforge/runs
Read with: GET /api/jobs?kind=bulkforge.batch | GET /api/jobs/:id
Write with: POST /api/jobs/:id/cancel
Trap: Cancellation is COOPERATIVE — the runner stops dispatching new items and lets in-flight ones finish, so the partial table stays coherent. A cancelled batch reports cancelled, never failed.
What this domain owns
Its verb is Open.
Entity kinds: bulkforge.list | bulkforge.recipe
Traps
THERE IS NO /api/bulkforge ROUTE. Presets, preview and a small run go through POST /api/adapters/bulkforge/<fn>; a real batch is POST /api/jobs { kind: "bulkforge.batch" }; lists and saved batches are /db/bulkforge_list and /db/bulkforge_recipe. Each of those already decides who may do it, and a fourth door would be a second, weaker copy of that decision. STEPS RUN IN ORDER PER ITEM. {{steps.<id>.output}} in step 2 is step 1's answer FOR THE SAME ITEM. This is the one thing a @leumas/workflows loop node cannot express — its body fans every item onto the frontier at once, so a downstream node reads the LAST item's result and the run still finishes green. If a workflow needs per-item chaining, it wants a single bulkforge.batch node, not a loop. The tokens are {{item}}, {{item.field}}, {{index}}, {{input.key}} and {{steps.<id>.output}}. A token that resolves to nothing becomes an EMPTY STRING, not undefined — so a { n = 5 } default never fires and '' reaches arithmetic as 0. Every number in a policy is coerced back to its default for exactly this reason; anything else a step is sent must do the same. A FAILED ITEM IS A ROW, NOT AN EXCEPTION. A batch that processed 4,998 of 5,000 reports done with failed: 2, and the summary names the failures out loud. Never read status: "done" alone as "it all worked". A queued batch survives a restart: it checkpoints its cursor onto the job row and resumePending() re-dispatches it at boot, restarting at the cursor rather than at zero. Result rows are kept on the row only while they fit a 256KB budget; past that the run sets truncated: true and reports carried vs total rather than silently dropping them. Two legacy BulkForge modes are deliberately absent. command-line ran an interpolated shell command per item — on a public subdomain that is remote code execution with a list attached. fileProcessor did fs.unlink, rename and copy on arbitrary absolute paths from the request body. Neither is a preset, and neither belongs on the member lane. An adapter executor ref splits at the LAST dot, so it must be exactly system.fn. A dotted tool name like a-transformation.json.parse addresses a system that does not exist and fails at run time for a ref that looks correct. pnpm check:bulkforge-presets holds that line for the shipped presets. The subdomain bulkforge.leumas.tech and Studio's /admin/d/bulkforge render the SAME components, from @leumas/features/bulkforge. A change to one is a change to both.