CLI commands
dry-run, inspect, trigger, start, config.
The runner ships six CLI verbs. Together they form a ramp from safe to live: introspect with no chain access, simulate with no gas, fire one real tick, then run the daemon.
Rule:dry-runnever signs and never spends.triggeris exactly one real tick.startis the long-lived daemon.
Plugins are registered by editing src/plugins/index.ts — every bin imports the registry from there. The bins themselves are marked ENGINE. DO NOT EDIT.
The commands
| Command | Invocation | Chain access | What it does |
|---|---|---|---|
plugins | pnpm plugins | none | Lists every plugin in the registry with its vaultId and triggers. |
show-config | pnpm show-config | none | Prints resolved config (no secrets). |
inspect | pnpm inspect <plugin-name> | read-only | Live snapshot of what the plugin would see right now. |
dry-run | pnpm dry-run <plugin-name> | simulate | Runs decide() once and simulates the tx. No signature, no gas. |
trigger | pnpm trigger <plugin-name> | one tx | Fires the plugin once — a single real decide()/execute(), then exits. |
start | pnpm start | live | Starts the daemon: registers every plugin, runs the scheduler. |
plugins
Pure introspection: no RPC, no signer, no state read. It does not need RUNNER_PLUGINS — it lists everything in the registry regardless of what the daemon would load. For each plugin it calls the factory and prints vaultId (truncated) plus triggers, formatted as cron(<everySeconds>s), event(<topic>), or the raw kind. A factory that throws shows as factory-error; the footer counts the failures and points you at the matching PLUGIN_<NAME>_VAULT_ID env vars.
show-config
Prints the resolved runtime config and exits. Echoes Network, Sui RPC URL, the Predict package/object refs, the Plugins to load list, and the State backend (custom if you export stateFactory, else in-memory). OPERATOR_PRIVATE_KEY is shown only as ✅ set or ❌ MISSING — never the value, even partial. HEALTH_PORT and LOG_LEVEL are echoed with their defaults. On a config error it prints the message and exits 1. See Configuration reference.
inspect
Read-only snapshot: no tx, no signing, no state mutation. Loads the plugin, reads the wallet balance (no signature), fetches the vault via Vault.fetch, and prints the highlights — nav, navPerShare, quoteBalance, aggregateExposure, maxSinglePosition, exposureHeadroom, paused, strategyPaused, isFrozen, open-position counts, and the granted strategy permissions. With a custom stateFactory it also previews the first 10 plugin state keys. This is the command for *"why isn't my plugin acting?"* — check isFrozen, headroom, and granted perms.
dry-run
Runs the plugin's decide() once, simulates the resulting tx via devInspect, and prints the decision it took (actions, noop reasons, gas estimate) regardless of LOG_LEVEL. Read-only: no signature, no gas, no on-chain change. The simulated result has no digest, but effects, events, and a gas estimate are populated. The signer is still loaded — for its address, not to sign. The plugin must be a member of RUNNER_PLUGINS, or the command throws dry-run: plugin "<name>" not in RUNNER_PLUGINS list. Only that one plugin is registered. Plugins that persist via onExecuted should check result.dryRun and skip writes on simulations. A missing <plugin-name> arg exits 2.
trigger
Fires the plugin once: a single real decide()/execute() with a real signature and real gas, then exits. Use it to debug without the daemon, as a CI smoke test, or to force a manual trigger in an emergency. Like dry-run, the target must be in RUNNER_PLUGINS (else exec: plugin "<name>" not in RUNNER_PLUGINS list), and only the requested plugin is registered — others in the CSV are ignored in this mode. Missing arg exits 2.
start
The daemon entrypoint. Loads config, builds the client and signer, registers every plugin in RUNNER_PLUGINS, and starts the scheduler. As a pre-flight it logs the operator address and SUI balance so you can spot an empty wallet before the first tick — there is no threshold assertion; monitor externally. It starts the healthcheck HTTP server when HEALTH_PORT > 0 (default 3030, bound to HEALTH_HOST, default 127.0.0.1; set HEALTH_PORT=0 to disable) and shuts down gracefully on SIGINT/SIGTERM, waiting (up to 30s) for an in-flight tick to finish so lifecycle hooks aren't cut off. A second signal skips the wait. A fatal startup error logs JSON to stderr and exits 1.
Next: the full env-var list → Configuration reference.