When to Promote from :script
When to Promote from :script
Section titled “When to Promote from :script”:script is the bazaar. :core is the monastery. The whole point of the Script Law is that the door between them is one mechanical command — janus desugar — and promotion loses nothing. The question is never can you promote. The question is when you should.
This page names the six triggers. When any of them becomes true, your .jans file has outgrown :script and the honest move is to promote.
The six triggers
Section titled “The six triggers”Per SPEC-045 §1 (Non-Goals) and §7.4 (Publication Restriction), promote to :core when any of these becomes true:
1. The program wants to live longer than a session
Section titled “1. The program wants to live longer than a session”:script artifacts cannot be published to a Hinge registry, installed as dependencies, or referenced from other Janus projects (E3101_PROFILE_NOT_PUBLISHABLE). The moment you reach for git to version this file, or you imagine another project importing it, you should have written :core. Scripts are throwaway artifacts by design — that is what keeps them honest.
2. It needs a capability outside the template’s default set
Section titled “2. It needs a capability outside the template’s default set”OS threads, raw sockets, network listening, ptrace, or any capability beyond the §4 default set requires an escalate declaration. A one-off escalate :service do ... end for a single bounded operation is fine — that is what escalation is for. But if you need the capability permanently, you are in :service or :cluster, not :script. Escalation is for borrowing a rung; it is not for living there.
3. It needs tensors, actors, grains, or compute offload
Section titled “3. It needs tensors, actors, grains, or compute offload”Those belong to the :compute, :cluster, and future game/scientific templates (SPEC-045 §0.1.3). They are deferred — not in the current-quarter product. Using :script for them is forcing a future product into the current profile. Write the :core (or :compute) module directly.
4. It needs a second file
Section titled “4. It needs a second file”:script is single-file. Top-level statements desugar into one synthesized main; there is no multi-module :script story, and there will not be one. The moment you want to use a sibling module you wrote, you have crossed into :core territory. Multi-module programs are what :core is for.
5. It needs hot reload or live state
Section titled “5. It needs hot reload or live state”Hot reload is deferred (SPEC-045 §6.4), not denied — it lights up when JIT-mode :script ships post-SovereignMC. But v1.0 :script is AOT-cached only. Production code does not run in :script. If your program needs to stay alive and swap code at runtime, it is a :service or :cluster program today, and it will be a JIT-mode :script program tomorrow. Today is today.
6. You’re writing a library
Section titled “6. You’re writing a library”Same root as trigger 1, restated for clarity: libraries are :core. A library that cannot be published, cannot be a dependency, and cannot outlive a session is not a library — it is a script that forgot to promote.
The Lua lesson behind the triggers
Section titled “The Lua lesson behind the triggers”Roberto Ierusalimschy describes Lua’s role in games with a sharp image: the C loop keeps the frame rate and the rhythm; Lua updates the characters and the images each frame. The hard, durable, resource-intensive substrate lives in the host language. The dynamic, frequently-changing, non-critical part lives in the script. That is the dual-language architecture that earns the word “scripting.”
Translated to Janus: {.script: sysadmin.} is for the part that changes often and gets thrown away or promoted. The durable substrate — the C side of Roberto’s games, the :core / :service side of ours — is where the hard parts live. The $-family, shell literals, stream pipelines (SPEC-045 §3.5) exist so the throwaway part stays readable. The moment it stops being throwaway, it stops being :script.
This is why the triggers above are all growth signals, not failures. A script that triggers one of them did its job: it let you explore fast, and now it is telling you it is ready to grow up.
The mechanical test
Section titled “The mechanical test”You do not have to guess. The doctrinal test for “is this script ready to promote?” is already mechanical and falsifiable:
janus validate --promotable path/to/file.jans- Exit 0 —
<file> is promotable to :core. The Script Law holds. Promotion is guaranteed to round-trip losslessly. - Exit 1 —
Script Law violated for <file>: <error>. The diagnostic names which rule fired. Fix it, then promote.
Run this in CI before you ship any .jans file you intend to promote later. It is faster than a full compile (no lowering, no codegen, no linking) and it catches every Script-Law violation that sema can see. When it passes, the actual promotion is one command:
janus desugar path/to/file.jans -o path/to/file.jan # canonical :core outputThat is the “when to promote” answer, automated. The triggers on this page tell you when to ask the question; validate --promotable answers it.
When not to promote
Section titled “When not to promote”The triggers cut one way. The honest counter-list — when to stay in :script — is shorter:
- The script is a one-shot experiment. You will read the answer once and delete the file.
- You are still iterating on the algorithm and rewrites are cheap. The auto-imports and synthesized
mainare saving you time on every edit. - The whole point is “I want to run this, see the output, and move on.” Promoting adds ceremony that buys you nothing.
:script is the bazaar. :core is the monastery. Both speak the same language; the bazaar just makes the boring parts invisible. Promote when the boring parts start mattering. Stay when they don’t.
Related
Section titled “Related”:script— The Gateway — what:scriptgives you, the ratified surface, the deferred$-family.:scriptTier 2 deep dive — how the desugar actually works, the three synthetic-main cases,validate --promotableinternals.:core— The Monastery — where promotion lands.- Profile Escalation — borrowing one rung without redeclaring the whole module.
- SPEC-045 §1 (Non-Goals) and §7.4 (Publication Restriction) — the normative source for the six triggers.