Nava CLI
Developer Preview
@navalabs/sdk ships the nava binary with the four base verification
commands:
nava request-verification --proposed-tx-json '{…}' --reason 'Why this action'
nava await-verification --proposed-tx-json '{…}' --reason 'Why this action'
nava check-verification-status --request-hash 0x…
nava get-user-addressEvery option, default, and requirement is on the operations reference; this page covers only what is specific to running the CLI. Credentials and chain selection come from the environment; see configuration.
Adapters
Installing an adapter adds its protocol's commands to the same nava binary,
spelled nava <protocol> <operation>:
@navalabs/uniswap-adapteraddsnava uniswap <operation>. See Uniswap operations.@navalabs/hyperliquid-adapteraddsnava hyperliquid <operation>. See Hyperliquid operations.
An adapter brings @navalabs/sdk with it, so installing it alone is enough. Or
skip installing and run it directly:
npx -p @navalabs/uniswap-adapter nava uniswap find-all-pools --protocol v3pnpm dlx, yarn dlx, and bunx work the same way. For base verification
with no protocol, point them at @navalabs/sdk instead.
Help output
Every level has help. nava --help lists the four base commands, then the
protocols this install registers. A bare @navalabs/sdk registers none and
says so. nava <protocol> --help lists that protocol's commands.
nava <command> --help covers one command.
Exit code 0 does not mean approved
The exit code tracks whether the command ran, not what the verdict was. A
rejected verdict is a completed operation, so it exits 0. Exit 2 is a usage
error, exit 1 is an unknown command or a thrown error, including an
await-verification timeout, which raises NavaTimeoutError rather than
returning a PENDING payload.
Branch on the payload, not $?. The fields that carry the answer:
{
"status": "APPROVED", // or REJECTED | UNDECIDED | PENDING | EXECUTED | FAILED
"canExecute": true, // false on anything that is not an approval
"verdict": {
"outcome": "approved", // or "rejected" | "pending"
"reasonCode": "allowed", // a violation code when rejected
"humanReason": "…",
"policyVersion": 7 // the version the action was permitted under
}
}An approval has status: "APPROVED", outcome: "approved",
reasonCode: "allowed", and canExecute: true. Anything else, including a
missing verdict, is not approval. The Hyperliquid writes wrap the same
information as success: false, the message under error, and requestHash
plus decision under verification.
A script that keys off the exit code alone reads a rejection as a success, the
same trap MCP has with isError.