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:
| Option | Description |
|---|---|
--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. |
--testnet | Join 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-mnemonic | Generate 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-mnemonic | Do 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-autoupgrade | Enable 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:
| Option | Description |
|---|---|
--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:
| Option | Description |
|---|---|
--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:
| Option | Description |
|---|---|
--config <CONFIG> | Path to config.json |
--dir <DIR> | Node directory containing config.json |
--no-tui | Print logs to stdout instead of the terminal UI |
--tui | Force 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:
| Field | Default | Meaning |
|---|---|---|
validators | omitted / empty | Peer IDs allowed to sign prefix certificates |
validator_min_stake | 0 | Minimum 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_cert | false | When 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_version | v0 | Predicate 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 |
emission | omitted (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:
| Option | Description |
|---|---|
--config <CONFIG> | Path to config.json |
--dir <DIR> | Node directory containing config.json |
--verbose / -v | Show extended information |
--sample-recent-blocks <COUNT> | For stats, number of recent blocks to sample; defaults to 1000 |
Address
modal node address [OPTIONS]
Options:
| Option | Description |
|---|---|
--config <CONFIG> | Path to config.json |
--dir <DIR> | Node directory containing config.json |
--one / -1 | Show only one address |
--prefer-public | Prefer public IP addresses |
--prefer-local | Prefer 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:
| Option | Description |
|---|---|
--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:
| Option | Description |
|---|---|
--config <CONFIG> | Path to config.json |
--dir <DIR> | Node directory containing config.json |
--timeout-secs <SECS> | Timeout for network requests; defaults to 30 |
--precise | Find the exact fork point with binary search |
Logs
modal node logs [OPTIONS]
Options:
| Option | Description |
|---|---|
--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 / -f | Follow log output |
--offline | Show logs even when the node is not running |
Network Operations
Ping
modal node ping --target <MULTIADDR> [OPTIONS]
Ping a remote Modality node.
Options:
| Option | Description |
|---|---|
--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:
| Option | Description |
|---|---|
--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:
| Option | Description |
|---|---|
--config <CONFIG> | Path to config.json |
--dir <DIR> | Node directory containing config.json |
--show | Show 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-autoupgrade | Enable autoupgrade |
--disable-autoupgrade | Disable autoupgrade |
--merge-in <FILE> | Merge settings from a JSON file |
--dry-run | Show 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.
| Field | Default | Refuses |
|---|---|---|
max_commits | 512 | a request that carries more commits |
requests_per_peer_per_minute | 60 | a peer's requests past this rate |
commits_per_contract_per_minute | 600 | a contract's commits past this rate, across all peers |
commits_per_node_per_minute | 6000 | the 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:
| Option | Description |
|---|---|
--config <CONFIG> | Path to config.json |
--dir <DIR> | Node directory containing config.json |
--yes / -y | Skip the confirmation prompt |