A script is logic over what the node hands it. This page maps what a
script author is likely to want onto where it comes from — the release, a
library, a service, a release of your own — and states the test that
decides when the node itself grows. The contract a script implements and
the calls it may rely on across releases are documented once, at
YmerNode.Script (What a script may call) and YmerNode.Script.Context;
this page points there and never restates them. A promised package's own
documentation is one call away in a session — scripts info <name> renders
it from the release at the version it carries. Terms:
script, battery,
declaration,
files directory.
The boundary
In scope: reaching another system and moving or transforming data — read what it holds into a shape a worker can use, write what a worker produced into the shape the system accepts. A periodic report compiled from any data the user points at is in scope; so is a browser-driven test of a web UI.
Out of scope: serving. The node has no user-facing listener and a script gets none. A script compiles and pushes its output to a host; it never hosts. A framework that exists to serve — a web server, a UI — is the shape that is too large for a script.
Where a capability comes from
Five rungs, tried in order. A request for "libraries X and Y" is answered by the first rung that fits.
The release already has it. Elixir's and Erlang/OTP's standard libraries reach further than most authors expect:
EExtemplating,:zip,:erl_tarand:zlib,:cryptoand:public_key(hashing, HMAC, signatures),DateandDateTime,FileandPath. One caveat: a release ships only the OTP applications its dependencies need, so an OTP application outside that set —:sshas of this writing — is absent until a use case adds it.A library. Shared Elixir code authored like a script and declared by the scripts that use it: the home for anything expressible in Elixir at the size of a module or a few — a converter, a client, a protocol.
A service over HTTP. The node is an integration host, so a capability that exists as a service is reached the way any system is: a PDF renderer, a browser, an LLM or embedding API. No battery, and often the better operational shape.
A release of your own. The node is open source, and an application that runs it builds its own release. An organisation with a native need the node does not carry adds the dependency to its own release; the script contract is unchanged. The promise in
YmerNode.Scriptcovers the packagesymer_nodeitself depends on only.A battery. The node itself grows, through its roadmap, when a use case in hand needs something no library can be:
- native code — a compiled extension the running node cannot build from a script's text;
- a node-owned process or configuration — a throttle shared by several scripts, a token cache, a connection pool;
- a package a library would only vendor — thousands of lines with their own upkeep;
- a format so common that every integration host is expected to speak it, where a good library exists. Forcing every author to replicate a good library the release could carry is waste; the bar is ubiquity plus a good library, never a good library alone. Parquet is the counter-example — cool, but a much less used format with no direct use case here, so not defensible.
A use case in hand, never a category, for the first three reasons: a battery joins for a script someone is writing. The fourth names its own use case — every integration host's.
The survey
What script authors on comparable platforms reach for — the classes are those of Google Apps Script's services, n8n's core nodes and Huginn's agents — and where each lands here.
| Class | Needs | Where it comes from |
|---|---|---|
| HTTP APIs, JSON | Req, JSON | the release |
| Rate limits, lockout protection | a throttle keyed by name | the release |
| HTML to markdown, markdown out | Floki, MDEx | the release |
| OAuth2 client flows, token refresh | a token cache per name | a battery when a use case arrives |
| Templating, reports | EEx | the release |
| Files, zip, tar, gzip | File, :zip, :erl_tar, :zlib | the release |
| Files on the host | the files directory, YmerNode.Script.Context.files_dir/1, and File | the release |
| XML, RSS, SOAP | read: sweet_xml over :xmerl; write: saxy | the release |
| CSV, XLSX | CSV: nimble_csv; read XLSX: xlsx_reader; write XLSX: elixlsx | the release |
| Time zones | DateTime over the release's zone database; the node's time zone, YmerNode.Script.Context.time_zone/1 | the release |
| Email, send | gen_smtp | a battery when a use case arrives; Outlook and Gmail over HTTP need nothing |
| Email, read | IMAP | a service: Graph or Gmail over HTTP |
| SSH, SFTP transfer | :ssh | one release line when a use case arrives |
| typst | the release | |
| Web UI test automation | Playwright | a service: the browser service, reached through YmerNode.Script.Context.playwright/3 — set up as the README's The browser service says |
| Images, charts | vix, image | a service or a release of your own; SVG through EEx needs nothing |
| Crypto, JWT, TOTP | :crypto, :public_key; jose | the release; TOTP is a library; JWT a battery when an assertion flow needs it |
| Scheduling | a schedule, YmerNode.Schedules | a node feature, not a battery |
| Storage, state, vectors | the notebook | the release |
| Shell commands | System.cmd/3 | reachable under the trust model, never promised |