Skip to content

Server CLI Reference ​

Every flag aerini-server accepts, for both the serve and api subcommands, plus the control subcommands (list, stop, start, restart, status, tokens) and restore-key. For what each mode is for and how to get one running, see Server Deployment. For the reasoning behind the security-relevant defaults, see Security.

The whole binary accepts --version; every subcommand accepts --help for this same information printed from the binary itself.

serve ​

Runs one workflow exported from the desktop app (Export → Export for Server).

FlagEnv varDefaultNotes
--config <path>aerini-server.jsonPath to the config file produced by the export.
--port <port>noneOverrides the status page port set in aerini-server.json. Leave unset to use that file's own port.
--bind <address>AERINI_BIND127.0.0.1Interface the status page binds to. Set to 0.0.0.0 to expose it beyond localhost. An IPv6 address may be written with or without brackets (::1 or [::1]).
--trusted-proxy-count <n>AERINI_TRUSTED_PROXY_COUNT0Reverse-proxy hops to trust when reading X-Forwarded-For. Must match your proxy topology exactly, too high a value lets a client spoof its IP and dodge per-IP rate limiting.
--allow-shellfalseEnables Shell Command nodes. If the workflow has one and this is left unset, the server prints a startup warning instead of refusing to start.
--allow-codefalseEnables Code (JS) nodes. Same startup-warning behavior as --allow-shell if the workflow has one and this is unset.
--allow-databasefalseEnables Database nodes (PostgreSQL, MySQL, SQLite, Redis). Same startup-warning behavior if the workflow has one and this is unset.
--allow-legacy-run-secretfalseLets the server start when the config's run_secret is a legacy BLAKE3 hash, or a plain-text secret from an even older export, instead of argon2id. Without it, either makes the server refuse to start. With it, the server logs a warning saying which format it found. serve-only, since only serve has a run_secret at all.
--file-sandbox-dir <dir>noneRestricts File and Save to Folder node reads and writes, and the paths a .wasm plugin may watch with fs-watch, to this directory tree. If the workflow has a File node and this is left unset, the server prints a startup warning and File nodes can reach any path the process can. api mode handles the unset case differently, see below.
--i-acknowledge-partial-sandboxfalseserve-only. Required to start with --allow-code --code-sandbox on macOS, see Platform behavior of --code-sandbox below.
--ssrf-firewall-acknowledgedfalseSuppresses the startup warning about the SSRF remaining DNS-rebinding gap (Postgres and MySQL connections) when bound to a non-loopback address. Pass it only once a host-level egress firewall is actually in place.
--parallel-executionfalseRuns independent workflow branches concurrently instead of sequentially.
--max-concurrent-nodes <n>8Caps simultaneous nodes when --parallel-execution is set; ignored otherwise. A value below 1 is clamped to 1, not rejected.
--max-workflow-duration-secs <secs>none (no limit)Server-level ceiling on one workflow execution, applied as min(the workflow's own duration setting, this value) when the workflow has one. A value outside 10 to 86400 (24 hours) is clamped to that range rather than rejected.
--code-sandboxfalseApplies ESM import restrictions to Code (JS) nodes, plus CPU/memory limits on Linux. See Platform behavior of --code-sandbox below.
--max-code-memory-mb <mb>512 (Linux only)Memory a sandboxed Code node's script may use. Aerini adds 2 GB of address space for Node.js's own startup on top (4 GB on Linux arm64, where the startup reservation has not been measured), so the process limit is this value plus that amount. Only takes effect with --allow-code --code-sandbox on Linux; no effect on macOS or Windows.
--plugin-dir <dir>noneDirectory of .wasm plugin nodes to load. A file that fails to load is skipped with a warning. serve reloads this directory on SIGHUP without restarting the process.

api ​

Runs the multi-workflow REST API, with bearer-token auth and no export package or config file, everything here is a flag or an environment variable.

FlagEnv varDefaultNotes
--token <token>AERINI_TOKENauto-generatedBearer token for API auth. If you set one, it must be at least 32 characters, the server exits with an error otherwise. Left unset on a first run (no tokens exist yet), the server generates a 43-character token, prints it once to stderr, and grants it all three scopes (read, write, admin). On later restarts it keeps the tokens already stored and prints nothing, so save the first one. A --token the server doesn't already know is added as a new admin token and the server warns that the older tokens stay active; revoke them with tokens revoke. A --token that was revoked stops the server with an error. The server also refuses to start when no unrevoked, unexpired admin token exists: start it once with --token <new token> to add one.
--port <port>AERINI_PORT7700Port to listen on. Unlike serve's --port, this one is env-backed and always has a default.
--data-dir <dir>AERINI_DATA_DIR~/.aerini-serverDirectory for the SQLite database and the token/credential key file. ~ or a leading ~/ expands to your home directory ($HOME, or USERPROFILE on Windows when HOME is unset); ~name/... is used as written. The server exits with an error if it needs a home directory and can't find one. A folder the server creates is owner-only (0700 on Unix); an existing folder keeps its permissions, and the server logs a warning at start-up when group or other users can access it.
--allow-origin <list>noneComma-separated additional origins allowed to call the API. Localhost origins (http://localhost[:port], http://127.0.0.1[:port], http://[::1][:port]) are always allowed regardless of this flag.
--allow-env-vars <list>noneComma-separated environment variable names a workflow may read via {{$env.VAR}}. Anything not listed resolves to an empty string.
--bind <address>AERINI_BIND127.0.0.1Same as serve's --bind, including IPv6 addresses with or without brackets.
--file-sandbox-dir <dir><data-dir>/filesRestricts File and Save to Folder node I/O, and the paths a .wasm plugin may watch with fs-watch, to this directory. Unlike serve, leaving this unset doesn't just warn: the server creates <data-dir>/files and uses it as the sandbox automatically.
--trusted-proxy-count <n>AERINI_TRUSTED_PROXY_COUNT0Same as serve's.
--allow-shellfalseEnables Shell Command nodes. Unlike serve, this prints its startup warning banner whenever the flag itself is passed, regardless of whether any current workflow has a Shell Command node yet, since any token with write scope can create one later.
--allow-codefalseEnables Code (JS) nodes. Same always-on-when-passed warning pattern as --allow-shell.
--allow-databasefalseEnables Database nodes. Same always-on-when-passed warning pattern.
--code-sandboxfalseSame as serve's. See Platform behavior of --code-sandbox below.
--ssrf-firewall-acknowledgedfalseSame as serve's.
--keychainfalseBacks the credential/token encryption key with the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service) instead of a plain file. The keychain entry belongs to --data-dir, so servers with different data directories never share a key. Falls back to the file automatically, with a warning, if the keychain isn't available, and always on a platform where the keychain library has no persistent store.
--parallel-executionfalseSame as serve's.
--max-concurrent-nodes <n>8Same as serve's, same clamp-to-1 floor.
--max-workflow-duration-secs <secs>none (no limit)Same as serve's: a ceiling combined with the workflow's own setting via min(), same 10 to 86400 clamp.
--db-pool-size <n>AERINI_DB_POOL_SIZEmax(available parallelism, 8)SQLite connection pool size. Should be at least --max-concurrent-nodes to avoid connection starvation.
--max-concurrent-runs <n>10Maximum workflow executions running at once, across every caller.
--max-queue-wait-secs <secs>30How long a run request waits for a free execution slot before the server gives up and returns 503. 0 disables the queue entirely, reverting to an immediate 503 at capacity.
--max-code-memory-mb <mb>512 (Linux only)Same as serve's.
--plugin-dir <dir>noneSame purpose as serve's. api mode reloads plugins through POST /api/plugins/reload (see Server API Reference) instead of SIGHUP.

Most flags above are identical between the two subcommands. --file-sandbox-dir is the one that isn't: serve warns and leaves File nodes unrestricted when it's absent, api sandboxes to a directory under --data-dir automatically. --port, --token, --data-dir, --allow-origin, --allow-env-vars, --keychain, --db-pool-size, --max-concurrent-runs, and --max-queue-wait-secs exist only on api. --config, --allow-legacy-run-secret, and --i-acknowledge-partial-sandbox exist only on serve.

Logging ​

Both subcommands log at info by default. Set RUST_LOG to change the level or filter by module (for example RUST_LOG=debug); a value that doesn't parse falls back to info. Set AERINI_LOG_FORMAT=json to emit one JSON object per log line for a log shipper; any other value keeps the default human-readable format.

Platform behavior of --code-sandbox ​

--code-sandbox behaves differently on each platform, for both subcommands:

  • Linux: full enforcement. An ESM loader blocks fs/net/child_process-style imports, eval/new Function are separately blocked, and setrlimit caps both CPU time and memory (--max-code-memory-mb, default 512 MB, plus 2 GB of address space for Node.js's own startup, 4 GB on arm64) on the Node.js subprocess.
  • macOS: partial. The ESM import restrictions and the eval/new Function block still apply, but setrlimit isn't available, so CPU and memory are uncapped and the per-node timeout is the only real ceiling. serve refuses to start with --allow-code --code-sandbox on macOS unless --i-acknowledge-partial-sandbox is also passed; api has no equivalent flag and only prints a warning before continuing.
  • Windows: neither mechanism exists. Nothing at startup stops you from combining --allow-code --code-sandbox on either subcommand, but the first Code node that actually tries to run fails with a SANDBOX_NOT_SUPPORTED error instead of running unsandboxed. Run without --code-sandbox on Windows, or deploy on Linux for real sandboxing.

Control commands ​

list, stop, start, restart, and status talk to a running api-mode server over HTTP using the same bearer token a client would. They accept no config file and start no server themselves.

CommandPositionalScope requiredNotes
listreadLists every scheduled workflow.
stop <workflow>workflow name or IDread + writeread to resolve the name/ID, write to actually stop it. Partial matches are accepted; an ambiguous match prints every candidate instead of guessing.
start <workflow>workflow name or IDread + writeSame matching rule as stop. Keeps the workflow's always-on setting.
restart <workflow>workflow name or IDread + writeCalls stop then start against the same REST endpoints a scoped token would use, and keeps the workflow's always-on setting.
statusreadIdentical output to list.

Each of the five accepts:

FlagEnv varDefault
--server <url>http://localhost:7700
--token <token>AERINI_TOKENrequired

tokens ​

Manages scoped API tokens against a running api-mode server. Every tokens action requires admin scope.

SubcommandArgsNotes
tokens list--server, --tokenLists active and revoked tokens.
tokens create--label <label> (required), --scopes <list> (default read,write), --expires-in <secs> (optional, omit for a non-expiring token), --server, --tokenlabel must be 1 to 256 characters; scopes must be a subset of read, write, admin. Either violation returns an error instead of creating a token. The raw token is only ever printed once, at creation.
tokens revoke <token_id>token_id (positional, from tokens list), --server, --tokenFails with an error if token_id matches the token currently authenticating the call, you can't revoke your own in-use token.

--server and --token behave the same way here as for list/stop/start/restart/status above.

restore-key ​

Puts a backed-up credential encryption key back into an api data folder. Stop the server first. The key is the value shown by Backup Encryption Key in the desktop app, or the contents of a saved aerini.key. It is checked against the saved credentials before anything is written; a key that does not decrypt them changes nothing.

FlagEnv varDefaultDescription
--data-dir <dir>AERINI_DATA_DIR~/.aerini-serverData folder holding credentials.db.
--key-file <path>read from standard inputFile holding the key, at most 1 KiB. A key typed at a terminal is refused, since it would stay on screen; pipe it in or use a file.
--keychainoffRestore into the OS keychain, as api --keychain stores it, and remove aerini.key.

What's next ​

  • Server Deployment, for getting either mode actually running
  • Server API Reference, for the REST routes these flags and control commands sit on top of
  • Security, for the reasoning behind the sandboxing, SSRF, and token defaults
  • Credentials, for how serve's environment-variable credentials and api's own encrypted store differ