Skip to main content

Node Commands (modal node)

Manage network nodes in the full Rust wrapper. These commands are available in full builds, not in the lean first-contract onboarding wrapper.

Most node commands resolve configuration from --config <CONFIG> or from --dir <DIR>/config.json. If neither flag is supplied, commands that operate on one node default to the current directory.

Interactive picker​

modal node --dir ./tmp/node1

With no subcommand, modal node opens a terminal UI to pick an action: run from config, hybrid, miner, sequencer, validator, observer, create, start, stop, info, or logs. Arrow keys move, Enter runs the highlighted action, and q, Esc, or Ctrl-C quits the picker. Requires a TTY. Background scripts should keep using an explicit subcommand such as run-hybrid.

After you run a node from the picker, q / Esc / Ctrl-C on the dashboard returns to this menu and the node keeps running. Choose View dashboard to watch it again, or Stop this node to shut it down. Quitting the picker stops a node started from this menu. node start is still the way to leave a node running after the CLI exits.

Create​

modal node create [OPTIONS]

Create a node directory with config.json and node.modal_passfile.

Options:

OptionDescription
--dir <DIR>Node directory to create; defaults to the current directory when no config.json exists
--node-id <NODE_ID>Existing peer ID to record; otherwise a new identity is generated
--data-dir <DATA_DIR>Data directory written into config; defaults to ./data
--bootstrappers <ADDRS>Comma-separated bootstrapper multiaddrs
--network <NETWORK>Network preset such as testnet, devnet1, devnet2, or devnet3. Joins that network with a new key; does not copy a bundled identity. Local devnet1 bootstraps at 127.0.0.1:10101.
--testnetJoin the public testnet with a new key. Sets bootstrappers, network_config_path: modality-networks://testnet, listen /ip4/0.0.0.0/tcp/4040/ws, hybrid_consensus, and autoupgrade from get.modality.org. See Join the public testnet.
--from-config <CONFIG>Merge settings from an existing config file
--from-passfile <PASSFILE>Import an existing node identity passfile
--from-template <TEMPLATE>Load a bundled template such as devnet1/node1 (that identity is the local genesis node: peer ID 12D3KooW9pte76rpnggcLYkFaawuTEs5DC5axHkg3cK3cewGxxHd, listen 10101). testnet/node1, testnet/node2, and testnet/node3 are the Foundation bootstrap configs (listen 4040), and testnet/node0 the Foundation observer / explorer (status_port 1337). Public-network templates carry no key: create generates one on the machine it runs on, so only the Foundation hosts hold the Foundation identities. Do not use them as a joiner.
--use-mnemonicGenerate or import the node key from a BIP39 mnemonic
--mnemonic-words <WORDS>Mnemonic word count; defaults to 12
--mnemonic-phrase <PHRASE>Existing mnemonic phrase to import
--account <INDEX>BIP44 account index; defaults to 0
--change <INDEX>BIP44 change index; defaults to 0
--index <INDEX>BIP44 address index; defaults to 0
--passphrase <PASSPHRASE>Optional BIP39 passphrase
--no-store-mnemonicDo not store the mnemonic in the passfile
--logs-enabled <BOOL>Enable or disable file logging
--log-level <LEVEL>error, warn, info, debug, or trace; defaults to info
--bootup-enabled <BOOL>Enable or disable bootup tasks
--bootup-minimum-genesis-timestamp <TIMESTAMP>Minimum genesis timestamp for pruning
--bootup-prune-old-genesis-blocks <BOOL>Enable pruning of old genesis blocks
--enable-autoupgradeEnable autoupgrade
--autoupgrade-base-url <URL>Autoupgrade base URL
--autoupgrade-branch <BRANCH>Autoupgrade branch
--autoupgrade-check-interval-secs <SECS>Autoupgrade check interval

Creates:

node/
|-- config.json
|-- node.modal_passfile
|-- data/
`-- logs/

--from-template and --network are different commands. Template devnet1/node1 is the local bootstrapper. --network devnet1 creates a joiner that dials that bootstrapper. modal node create --testnet listens on public testnet port 4040 (/ip4/0.0.0.0/tcp/4040/ws). Without --testnet or a template, create uses an ephemeral local port.

After --testnet, run modal node run-miner --dir <dir> or modal node run-hybrid --dir <dir>.

create writes "config_version": 2. A node refuses a config.json or network config file without it, because before version 2 run_validator meant the sequencer. Recreate the node from a current template, or rename run_validator to run_sequencer and run_contract_validator to run_validator (network files: validators to sequencers and contract_validators to validators), then add the version.

Build the full CLI from rust/ (cargo build -p modal). A modality binary already on PATH may be an old language-only CLI with no node commands.

Lifecycle​

Start​

modal node start [OPTIONS]

Start a node in the background. The command writes node.pid in the node directory.

Options:

OptionDescription
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json
--node-type <TYPE>miner, hybrid, observer, sequencer, validator, or server; otherwise resolved from config

Stop, Restart, Kill, and PID​

modal node stop [OPTIONS]
modal node restart [OPTIONS]
modal node kill [OPTIONS]
modal node pid [OPTIONS]

Shared options:

OptionDescription
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json

stop, restart, and kill also accept --force / -f to use SIGKILL instead of graceful SIGTERM. restart accepts --node-type <TYPE> with the same values as start.

Foreground Run Commands​

modal node run [OPTIONS]
modal node run-miner [OPTIONS]
modal node run-hybrid [OPTIONS]
modal node run-sequencer [OPTIONS]
modal node run-validator [OPTIONS]
modal node run-observer [OPTIONS]
modal node run-noop [OPTIONS]

run-sequencer runs the ordering committee (Shoal). run-validator is the separate third role: it issues prefix certificates and does not mine or sequence. A single process may still run miner + sequencer + validator together (hybrid/dev).

All foreground run commands accept:

OptionDescription
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json
--no-tuiPrint logs to stdout instead of the terminal UI
--tuiForce the terminal UI even when stdout is not a TTY

Foreground run* commands open a terminal UI by default when stdout is a TTY. Status, recent blocks, and logs are on one screen. Press q, Esc, or Ctrl-C to quit (this stops that standalone process). From the picker, the same keys leave the dashboard without stopping the node. Log type and topic show as chips with counts: arrow keys (or h j k l) move the highlight, space turns that chip on or off, Enter leaves only that chip on, and 0 shows every line again. Background node start always uses --no-tui. Set MODALITY_NO_TUI=1 to disable the UI without a flag.

modal node run additionally accepts --enable-consensus, which is deprecated; prefer config-driven node roles.

The top-level quick-run aliases use the same options:

modal run miner --dir ./my-node
modal run hybrid --dir ./my-node
modal run sequencer --dir ./my-node
modal run validator --dir ./my-node
modal run observer --dir ./my-node

Network info.json may include, besides the static sequencer committee sequencers:

FieldDefaultMeaning
validatorsomitted / emptyPeer IDs allowed to sign prefix certificates
validator_min_stake0Minimum stake to validate; 0 on testnet/dev
validation_fees{ "nominal": 0, "meter_coefficient": 0 }Quoted as nominal + meter_coefficient * gas_used (recorded, not transferred)
repost_requires_validator_certfalseWhen true, dest REPOST and dest RECV apply need a validator supermajority (⌈2n/3⌉ named prefix_cert signatures on the same digest through the source commit), not one signature
predicate_theory_versionv0Predicate theory validators enforce on every contract, from network genesis. v2 refuses a MODEL whose edge labels cannot hold together (a dead edge) and matches rule labels by entailment. A rule check also follows accepted state from the rule's anchor: it starts from the state when the rule was added, a fact about a path an edge's -modifies label keeps unchanged carries to the next step, and an edge or a rule label that contradicts what is known at its node is taken by no commit. After the first step, a diamond counts only a move every run at that node can take, so v2 refuses some true rules. v2 also verifies every commit signature and refuses a commit whose signatures do not all verify (see Standard Predicates, Commit signatures). v3 is v2 with num_* and amount_in_range compared exactly rather than as 64-bit floats. v1, the same checks without accepted state, is refused: it accepts rules some runs break. A node refuses every commit on a network whose version it does not know. Changing it on a running network re-judges accepted logs: a hard fork
emissionomitted (no mint)Native MOD mint for this network. block_subsidy is credited to the peer nominated in each canonical miner block after index 0. Optional halving_interval_blocks (0 = never), cap (0 = none), and genesis_allocations ([{ "account": "<peer id>", "amount": n }]) applied once on first config load. Distinct from contract-asset CREATE/SEND/RECV

Omitted fields keep existing networks unchanged. Local devnet1 names the single node as a validator and sets repost_requires_validator_cert so dest REPOST and dest RECV wait for that node's prefix cert. The public testnet network names the three Foundation bootstrappers as validators with validator_min_stake 0 and repost_requires_validator_cert true. That is a named bootstrap set, not stake-gated mainnet membership. Request a certificate with /contract/prefix_cert (source_contract, through_commit). Local devnets also set emission.block_subsidy so mining mints native MOD. Copy emission into your own info.json (or network config file) to choose a different schedule.

Information​

Info and Stats​

modal node info [OPTIONS]
modal node stats [OPTIONS]

Options:

OptionDescription
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json
--verbose / -vShow extended information
--sample-recent-blocks <COUNT>For stats, number of recent blocks to sample; defaults to 1000

Address​

modal node address [OPTIONS]

Options:

OptionDescription
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json
--one / -1Show only one address
--prefer-publicPrefer public IP addresses
--prefer-localPrefer loopback or local IP addresses

Inspect​

modal node inspect [COMMAND] [KEY|INDEX] [OPTIONS]

Inspect local datastore state. COMMAND may be general, mining, blocks, block <INDEX>, or datastore-get <KEY>. --level <LEVEL> remains available for backward compatibility with general, mining, and blocks. When the node is running, inspect opens the datastore read-only. ping --dir uses a temporary datastore and does not bind the node's listen port; pinging from a second node directory is the usual connectivity check.

Options:

OptionDescription
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json
--level <LEVEL>Backward-compatible inspection level

Compare​

modal node compare <PEER> [OPTIONS]

Compare the local chain with a remote peer ID or full multiaddr.

Options:

OptionDescription
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json
--timeout-secs <SECS>Timeout for network requests; defaults to 30
--preciseFind the exact fork point with binary search

Logs​

modal node logs [OPTIONS]

Options:

OptionDescription
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json
--lines <COUNT> / -n <COUNT>Number of lines to show; defaults to 50
--follow / -fFollow log output
--offlineShow logs even when the node is not running

Network Operations​

Ping​

modal node ping --target <MULTIADDR> [OPTIONS]

Ping a remote Modality node.

Options:

OptionDescription
--target <MULTIADDR>Peer multiaddr to ping
--times <COUNT>Number of ping attempts; defaults to 1
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json

Sync​

modal node sync [OPTIONS]

Sync blockchain data from bootstrappers configured for the local node.

Options:

OptionDescription
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json
--block-height-minus <COUNT>Stop this many blocks before the highest known block height; defaults to 10
--max-peers <COUNT>Maximum peers to attempt; defaults to 5
--timeout-secs <SECS>Timeout per peer sync attempt; defaults to 30

Maintenance​

Config​

modal node config [OPTIONS]

View or modify config.json.

Options:

OptionDescription
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json
--showShow current configuration
--set-listeners <ADDRS>Replace listener addresses with a comma-separated list
--add-listener <ADDR>Add one listener address
--remove-listener <ADDR>Remove one listener address
--set-bootstrappers <ADDRS>Replace bootstrappers with a comma-separated list
--add-bootstrapper <ADDR>Add one bootstrapper address
--remove-bootstrapper <ADDR>Remove one bootstrapper address
--replace-ip <FROM=TO>Replace IP addresses in listeners and bootstrappers
--enable-autoupgradeEnable autoupgrade
--disable-autoupgradeDisable autoupgrade
--merge-in <FILE>Merge settings from a JSON file
--dry-runShow merge changes without modifying the config

Push limits​

A node that takes /contract/push and /contract/submit from strangers limits what it stores and queues. Set push_limits in config.json (for example with --merge-in); a missing field keeps its default and 0 turns that limit off.

FieldDefaultRefuses
max_commits512a request that carries more commits
requests_per_peer_per_minute60a peer's requests past this rate
commits_per_contract_per_minute600a contract's commits past this rate, across all peers
commits_per_node_per_minute6000the node's commits past this rate, across all contracts

A refused push names the limit and is not charged; retry after a pause. This is each node's own policy, not consensus: two nodes may set different limits. Peer ids are free to mint, so the contract and node limits are the ones that hold.

{
"push_limits": {
"commits_per_contract_per_minute": 120
}
}

Clear​

modal node clear [OPTIONS]
modal node clear-storage [OPTIONS]

Clear both storage and logs, or only storage.

Options:

OptionDescription
--config <CONFIG>Path to config.json
--dir <DIR>Node directory containing config.json
--yes / -ySkip the confirmation prompt