Skip to main content
← Back to list
01Issue
FeatureOpenSwamp ClubPublicTeam
AssigneesNone

Relationships

#2036 Document env.* namespace for model-instance globalArguments (host-portable config)

Opened by webframp · 9/6/2026

Problem

The env.* CEL namespace works in model instance globalArguments but is undocumented in the model expression reference. This is the model-instance sibling of the datastore-layer gap fixed in #1801 — same shape ("a committed config file needs a value that varies per host/operator"), one layer up.

Concretely: a model definition YAML is committed to git, but a globalArguments value often must vary per host (e.g. an absolute filesystem path that differs between Linux /home/[REDACTED]/... and macOS /Users/[REDACTED]/...). Today the only portable option is to hardcode one host's absolute path, which breaks the moment the repo is used from another machine.

What actually works (but isn't documented)

${{ env.VAR }} in globalArguments resolves correctly at method-run time:

globalArguments:
  repo_root: ${{ env.HOME }}/src/webframp/swamp-extensions   # portable, no new var
  # or an explicit var:
  # repo_root: ${{ env.EXT_MAINT_REPO_ROOT }}

Verified on swamp 20260904.230512.0:

  • Resolves at run time, not evaluate time — consistent with the documented behavior that vault.*/env.* are "left untouched during expansion — they resolve at their own runtime/execution stage."
  • ${{ env.HOME }} + literal suffix produces a fully host-portable path with zero new environment variables — works on both macOS and Linux.
  • Missing var fails loudly and precisely, which is good:
    error: No such key: EXT_MAINT_REPO_ROOT
    path: globalArguments.repo_root
    envVar: EXT_MAINT_REPO_ROOT

The documentation gap

references/model/references/expressions.md — the "Reference Types" table lists inputs, model, file, self, data (and vault in prose) but has no mention of env. The only place env.* is documented is the workflow reference (references/workflow/references/expressions-and-foreach.md, "Environment Variables" section). A user working with model instances has no signal the namespace exists there, so relying on it feels like depending on undocumented behavior.

Requested changes

  1. Document env.* in the model expression reference — add it to the Reference Types table alongside inputs/self/data, with a host-portable path example (${{ env.HOME }}/...) and a note that it resolves at method-run time (not at model evaluate).
  2. Call out the cross-host portability pattern explicitly in the model / model create docs: prefer ${{ env.* }} over hardcoded absolute paths in committed globalArguments.
  3. (Optional) Validation / discoverability improvements:
    • Surface required env vars at create/evaluate time so an operator learns up front which host vars a model instance depends on (today model evaluate and model get show the literal ${{ env... }}, so the resolved value and the dependency aren't inspectable until a method runs).
    • Consider a model validate signal that flags committed absolute paths in globalArguments as a portability smell, nudging toward env.*.

Relationship to #1801

#1801 (shipped) added env/interpolation support at the datastore layer, which had a genuine bootstrap blocker (datastore initializes before vault resolution). Model instances have no such blocker — they run well after the environment is available, and env.* already resolves for them. So this is narrower: primarily a documentation coverage issue (make env a documented, first-class option for model-instance config), plus optional validation/discoverability niceties to help operators keep committed configs host-portable.

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED

Open

9/6/2026, 3:20:41 AM

No activity in this phase yet.

03Sludge Pulse

Sign in to post a ripple.