Spaces
A job's config/spaces maps names to spaces. Each mapping becomes a folder inside the running job, so your code reads and writes a space as ordinary files instead of calling the API.
AI assisted, human approved — novem uses AI to review and keep our documentation up to date.
Note: Spaces are an early-access feature, gated behind a per-account
flag — the endpoints return 404 unless it's enabled on your account. See
spaces.
A job reaches a space by mounting it. You write a
mapping of names to spaces into the job's config/spaces, and each name
becomes a folder the running job can read — or write, if you ask for it.
data_in => /u/alice/s/project_a,ro
scratch => /u/alice/s/scratch,rw
This attaches two spaces. The job sees data_in holding the contents of
project_a, which it may only read, and scratch holding the contents of the
scratch space, which it may also write to.
The file format
One mapping per line:
<name> => /u/<user>/s/<space>[,ro|,rw]
<name>is the folder name the job sees. Lower-case, starts with a letter, then letters, digits and underscores, up to 63 characters. Each name must be unique within the file./u/<user>/s/<space>is the space to attach. The leading slash is optional, sou/alice/s/project_ais accepted too.,roor,rwsets the mode. It is optional and defaults toro— a mapping with no suffix is read-only.
Blank lines are ignored. There is no comment syntax: a line that isn't a
mapping is an error, # included.
A job may mount at most 16 spaces, and the config body itself is capped
at 4096 bytes — a longer body is rejected with a 413 and nothing is
stored.
Writing the config
The file is validated as a whole. Every line is parsed before anything is
stored, and a malformed line fails the write with a 400 quoting the line that
caused it — so a rejected write leaves the previous config untouched rather
than half-applying. Posting an empty body clears the config, the same as
DELETE.
Reading the file back gives you the text you wrote:
data_in => /u/alice/s/project_a,ro
scratch => /u/alice/s/scratch,rw
Seeing the effective mounts
The config file gives back the text you wrote, including any rw you asked
for. To see what a run will actually get, read the job's spaces/ listing —
its permissions are the effective access, already narrowed by what the job
owner can reach:
Each entry gives the mount name, the target space it resolves to, and
permissions of {r} for a read-only mount or {r,w,d} for a writable one. A
mapping you wrote as rw that shows {r} here is one the owner can only read
— the run will see it read-only.
Access
Every space you reference must be one the job owner can read, whoever is editing the config. If a job has been shared with you for writing, you cannot attach a space that only you can see: the set of spaces a job touches never goes beyond what its owner could reach on their own.
A reference to a space that does not exist and a reference to one the owner cannot read fail the same way, so the error never reveals whether a given space exists.
Requesting rw on a space the owner can only read is accepted when you write
the config, since grants change over time. The mode that actually applies is
recomputed from live access on every run and enforced on every call, so writing
rw here never widens access on its own.
Note: If a mount cannot be resolved when a run starts — the space is gone, or the owner's access to it was revoked — the run fails immediately and says which mount was at fault, rather than starting with an empty folder.
What the job sees
Mounts apply to the whole run: every chain step
sees the same set of folders, under /mnt. A mapping named scratch is
/mnt/scratch inside the running job.
The mount point is the space's content/ tree — there is no extra level to
descend. A file the space holds at content/reports/q1.csv is
/mnt/scratch/reports/q1.csv in the job, and a file the job writes to
/mnt/scratch/runs/day.tsv lands at content/runs/day.tsv in the space,
creating the intermediate folders as it goes.
Changes your code makes under a rw mount are written back to the space, so
they go through the same journal, quota and event machinery as any other write
— the change history of a space records what a job did to it, attributed to the
job's owner.
Changes reach the space as the job writes them, not in one batch when the run ends — the space's change journal records each write at the time it happened. A run that ends in failure keeps whatever it had already written.
Nothing written under a ro mount reaches the space.
Note: That makes a rw mount useful as durable progress, not just as
a place to put a result. A long job that writes each unit of work as it
finishes — a file per day collected, per report rendered — leaves that work in
the space even if a later unit fails, and the next run can pick up where it
left off instead of starting over. Write each unit so that repeating it is
harmless, and re-running is always safe.
Note: A run stopped by the runtime's time limit is the one case this doesn't cover — don't count on writes from a run that was cut off part-way.
Resource limits
A job's CPU, memory and wall-clock budget are fixed by the runtime and are not
configurable through job config — there is no config/memory or
config/timeout. A job that runs out of any of them is stopped, so work that
grows without bound (a full history sweep that gets longer every month) needs
to be split into a smaller unit of work per run rather than given a bigger
budget.
Each step's output is capped at 100 MB. That applies to what a step hands to the next step and to a job's final result.