Command-line tool for deploying, running, and managing OutLayer agents.
outlayer login # Import NEAR full access key
outlayer create my-agent # Create project from template
outlayer deploy my-agent # Deploy agent to OutLayer
outlayer run alice.near/my-agent '{"command": "hello"}' # Execute agentcurl -fsSL https://raw.githubusercontent.com/out-layer/outlayer-cli/main/install.sh | shFrom crates.io (requires Rust)
cargo install outlayer-clicargo install --git https://github.com/out-layer/outlayer-cliPre-built binaries for macOS (ARM/x86), Linux (x86/ARM), and Windows are available on the Releases page.
# 1. Login (prompts for Account ID and Private Key)
outlayer login # mainnet
outlayer login testnet # testnet
# 2. Create a new agent
outlayer create my-agent # basic template (stdin/stdout)
outlayer create my-agent --template contract # with OutLayer SDK (VRF, storage, RPC)
cd my-agent
# 3. Edit src/main.rs, build, upload the .wasm and deploy it
./build.sh
outlayer upload out/my-agent.wasm
outlayer deploy my-agent <FastFS URL printed by upload>
# 4. Create a payment key for HTTPS calls
outlayer keys create
# 5. Run your agent
outlayer run alice.near/my-agent '{"command": "hello"}'| Command | Description |
|---|---|
outlayer login |
Import NEAR full access key (mainnet) |
outlayer login testnet |
Login to testnet |
outlayer logout |
Delete stored credentials |
outlayer whoami |
Show current account and network |
| Command | Description |
|---|---|
outlayer create <name> |
Create project from template (basic) in ./<name>/ |
outlayer create <name> --template contract |
Create with OutLayer SDK (VRF, storage, RPC) |
outlayer create <name> --dir /path |
Create in a custom directory |
outlayer deploy <name> <wasm-url> |
Deploy a published .wasm (FastFS URL from outlayer upload, or any URL) |
outlayer deploy <name> --no-activate |
Deploy without activating |
outlayer run <project> [input] |
Execute agent (HTTPS or on-chain fallback) |
outlayer projects [account] |
List projects for a user |
outlayer status [call_id] |
Project info or poll async call |
A version is a published .wasm, named by its sha256: what a caller runs and pays for is
exactly the file you deployed, and it cannot change under that version afterwards. For a
reproducible build — the same pinned Docker image, the same hash on every machine — use
scripts/build_github_wasm.sh from the OutLayer repository.
# Run from project (uses payment key if available, else on-chain NEAR)
outlayer run alice.near/my-agent '{"command": "hello"}'
outlayer run alice.near/my-agent --input request.json # input from file
outlayer run alice.near/my-agent '{"command": "heavy"}' --async # async (HTTPS only)
outlayer run alice.near/my-agent '{"command": "premium"}' --deposit 0.01 # attached deposit
outlayer run alice.near/my-agent '{}' --compute-limit 1000000000 # custom compute limit
outlayer run --wasm <url> '{}' --attach-near 0.5 # on-chain: attach 0.5 NEAR, unused refunded
# On-chain, the CLI attaches the estimate for the compute and the input it sends. An output of
# 1 KB or more is held in the contract until the request settles, at 0.00001 NEAR per byte, out of
# what is attached: a run whose output does not fit fails with `output_storage_unpaid:` and the
# amount to attach. --attach-near attaches more; whatever the run does not use is refunded.
# Attach secrets to execution (secrets must be stored via `outlayer secrets set`)
outlayer run alice.near/my-agent '{}' --secrets-profile default --secrets-account alice.near
# Run from WASM URL (on-chain) — FastFS, any HTTP URL
outlayer run --wasm https://alice.near.fastfs.io/outlayer.near/abc.wasm '{"cmd": "hi"}'
outlayer run --wasm https://example.com/file.wasm --hash abc123... '{}'
# List your projects
outlayer projects
outlayer projects bob.near| Command | Description |
|---|---|
outlayer secrets set '{"KEY":"val"}' |
Encrypt and store secrets |
outlayer secrets set-for-agent '{"KEY":"val"}' --project <owner>/<name> |
Leave a secret for an agent to use with one connector |
outlayer secrets access --project <owner>/<name> --profile <p> --access <cond> |
Change who may read a stored secret (update_access); grant or revoke an agent without re-storing |
outlayer secrets update '{"KEY":"val"}' |
Merge with existing (preserves PROTECTED_*) |
outlayer secrets set --generate PROTECTED_X:hex32 |
Generate protected secret in TEE |
outlayer secrets list |
List stored secrets (metadata only) |
outlayer secrets delete |
Delete secrets for a profile |
# Set secrets (JSON object, overwrites existing)
outlayer secrets set '{"API_KEY":"sk-...","DB_URL":"postgres://..."}'
outlayer secrets set '{"API_KEY":"sk-..."}' --project alice.near/my-agent
outlayer secrets set '{"API_KEY":"sk-..."}' --wasm-hash abc123... # the row a raw WASM URL run reads under
# A row bound to a GitHub repository can only be deleted:
outlayer secrets delete --repo github.com/user/repo --branch main
# Lock a project's row to one build: only a run of these exact bytes reads it, a rebuild is refused.
# The hash is "Executed binary" in an execution's details. Move it to the next release with `access`.
outlayer secrets set '{"SIGNING_KEY":"..."}' --project alice.near/oracle --build <sha256>
outlayer secrets access --project alice.near/oracle --access whitelist:alice.near --build <new sha256>
# Direct calls only: a call reads the row only when the account that CALLS the contract is one the
# condition names — no other contract in between. Without it, a contract you sign any transaction
# to can relay a call naming your secret into the project it is bound to, under your name.
outlayer secrets set '{"SIGNING_KEY":"..."}' --project alice.near/oracle --direct
outlayer secrets access --project alice.near/oracle --direct --via dao.sputnik-dao.near # and through this DAO
outlayer secrets access --project alice.near/oracle --drop-callers # remove the rule
# Generate protected secrets in TEE (values never visible)
outlayer secrets set --generate PROTECTED_MASTER_KEY:hex32
outlayer secrets set '{"API_KEY":"sk-..."}' --generate PROTECTED_DB:hex64 # mixed
# Access control
outlayer secrets set '{"KEY":"val"}' --access allow-all # everyone who names it
outlayer secrets set '{"KEY":"val"}' --access whitelist:alice.near,bob.near
outlayer secrets set '{"KEY":"val"}' --access whitelist:me.near,agent@2026-10-01T00:00:00Z # a grant that lapses
outlayer secrets access --project me.near/app --profile default --access whitelist:me.near # change who may read; the value stays
# Without --access: a row that exists keeps its condition; a new project row admits only you;
# a new hash-bound row admits everyone.
# Update (merge with existing, preserves all PROTECTED_* variables)
outlayer secrets update '{"NEW_KEY":"val"}' --project alice.near/my-agent
outlayer secrets update --generate PROTECTED_NEW:ed25519
# Generation types: hex16, hex32, hex64, ed25519, ed25519_seed, password, password:N
# List / delete
outlayer secrets list
outlayer secrets delete --project alice.near/my-agent
outlayer secrets delete --profile productionDefault accessor: --project auto-resolved from outlayer.toml if present.
secrets set stores a secret for your own project. set-for-agent stores
one for a custody agent to use with somebody else's connector — the API key
a connector needs on the agent's behalf. It is sealed to the agent's own key,
stored on chain under the agent's name, and readable by that agent alone.
export OUTLAYER_WALLET_KEY=wk_... # the agent's wallet key
# The logged-in account pays the storage, so the agent needs no NEAR
outlayer secrets set-for-agent '{"MAILGUN_KEY":"key-..."}' \
--project connectors.outlayer.near/near-email
# Or let the agent's own wallet pay (it needs ~0.11 NEAR)
outlayer secrets set-for-agent '{"MAILGUN_KEY":"key-..."}' \
--project connectors.outlayer.near/near-email --agent-pays
# Refuse unless the secret lands under the vault you expect
outlayer secrets set-for-agent '{"MAILGUN_KEY":"key-..."}' \
--project connectors.outlayer.near/near-email --vault-id vault.alice.nearThe plaintext never leaves the machine: the key it is sealed to is fetched under the agent's own authentication, and only ciphertext is sent. Nothing is signed or sent until the prepared call has been checked field by field — receiver, method, project, ciphertext, audience, vault and deposit — so a wrong answer becomes a refusal rather than a signature.
Payment keys are required for HTTPS API calls. Created separately (requires USDC top-up).
| Command | Description |
|---|---|
outlayer keys create [--project owner/name]… |
Create a new payment key; --project (repeatable, owner/* for all of one owner's projects) lets it pay only for those projects |
outlayer keys list |
List keys with balances |
outlayer keys balance <nonce> |
Check key balance |
outlayer keys topup <nonce> --usd <amount> |
Top up with the stablecoin (any network). A top-up with NEAR is on the website |
outlayer keys delete <nonce> |
Delete key (refunds storage) |
outlayer keys trial-key [--api-key wk_...] |
Print a custody wallet's nonce-0 key (trial or sponsored); it is derived, so it is read again rather than stored |
A sponsor code (spn_...) puts a subscription on a custody wallet's nonce-0 key, paid by whoever gave you the code. The key is created if the wallet has none; the trial, if claimed, is converted.
outlayer redeem spn_... --api-key wk_... # or OUTLAYER_WALLET_KEY
KEY=$(outlayer redeem spn_...) # stdout is the payment key aloneA code that cannot be redeemed answers sponsor_code_invalid, whatever the reason — ask whoever gave it. sponsor_cannot_top_up means the key already holds more than the code gives. A key carries one sponsor while its grant is live; once it ends, another code can be redeemed — never one this wallet redeemed before. A nonce-0 key issued at random before keys were derived (payment_key_not_recoverable) redeems with --payment-key <owner:0:key>; the answer is the derived key that replaces it.
Trustless agent-to-agent payments via ephemeral intents accounts. Requires a wallet API key (outlayer register or POST /register).
| Command | Description |
|---|---|
outlayer checks create <token> <amount> |
Create a payment check |
outlayer checks batch-create --file <path> |
Batch create checks from JSON file |
outlayer checks claim <check_key> |
Claim a check (full or partial) |
outlayer checks reclaim <check_id> |
Reclaim unclaimed funds (full or partial) |
outlayer checks status <check_id> |
Check status of a payment check |
outlayer checks list |
List your payment checks |
outlayer checks peek <check_key> |
Check balance of a check by key |
# Create a check for 1 USDC with memo and 24h expiry
outlayer checks create 17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1 1000000 \
--memo "Payment for task" --expires-in 86400
# Claim (full)
outlayer checks claim 9f8a7b6c...64-hex-key
# Partial claim (take 0.5 USDC out of 1 USDC)
outlayer checks claim 9f8a7b6c...64-hex-key --amount 500000
# Reclaim (sender takes back)
outlayer checks reclaim 3a2b1c0d-4e5f-6a7b-8c9d-0e1f2a3b4c5d
# Partial reclaim
outlayer checks reclaim 3a2b1c0d-4e5f-6a7b-8c9d-0e1f2a3b4c5d --amount 300000
# Check status
outlayer checks status 3a2b1c0d-4e5f-6a7b-8c9d-0e1f2a3b4c5d
# List unclaimed checks
outlayer checks list --status unclaimed
# Peek at check balance before claiming
outlayer checks peek 9f8a7b6c...64-hex-key
# Batch create from JSON
outlayer checks batch-create --file checks.json
# checks.json format: [{"token":"...","amount":"...","memo":"...","expires_in":86400}, ...]A transfer the solver relay does not confirm in time is not an error. create
prints status: creating — the check_key is printed too, keep it — and
claim / reclaim print status: processing with the request to poll. The
transfer settles on its own; do not run the command again. checks status
shows the check moving on (creating → unclaimed, or failed if the funding
never executed and nothing moved). A batch that stops part way prints the checks
it created and exits with the reason the rest were not.
Upload files to on-chain storage via NEAR transactions (indexed by FastFS).
| Command | Description |
|---|---|
outlayer upload <file> |
Upload file to FastFS |
outlayer upload <file> --receiver <account> |
Custom receiver (default: OutLayer contract) |
outlayer upload <file> --mime-type <type> |
Override MIME type |
outlayer upload ./target/wasm32-wasip2/release/my-agent.wasm
# Uploading to FastFS...
# File: ./target/wasm32-wasip2/release/my-agent.wasm
# Size: 234567 bytes
# SHA256: abcdef...
# Upload complete!
# FastFS URL: https://alice.near.fastfs.io/outlayer.near/abcdef.wasm| Command | Description |
|---|---|
outlayer versions |
List project versions |
outlayer versions activate <key> |
Switch active version |
outlayer versions remove <key> |
Remove a version |
| Command | Description |
|---|---|
outlayer earnings |
View developer earnings |
outlayer earnings withdraw |
Withdraw blockchain earnings |
outlayer earnings history |
View earnings history |
| Command | Description |
|---|---|
outlayer logs |
View execution history |
outlayer logs --nonce 2 --limit 50 |
Specific key, more entries |
outlayer --verbose ... # Verbose output
outlayer --json ... # JSON output
OUTLAYER_NETWORK=testnet outlayer run ... # Override network via envStored at ~/.outlayer/{network}/credentials.json. Requires a NEAR full access key. Private key optionally stored in OS keychain (macOS Keychain, Linux Secret Service).
After login, the active network is saved to ~/.outlayer/default-network. If not set, the CLI auto-detects based on which network has credentials.
outlayer.toml in your project root (created by outlayer create):
[project]
name = "my-agent"
owner = "alice.near"
[build]
target = "wasm32-wasip2"
source = "wasm_url"
[run]
payment_key_nonce = 1| Variable | Description |
|---|---|
OUTLAYER_HOME |
Config directory (default: ~/.outlayer) |
OUTLAYER_NETWORK |
Network: mainnet or testnet |
PAYMENT_KEY |
Payment key for outlayer run (format: owner:nonce:secret) |
OUTLAYER_WALLET_KEY |
Custody wallet API key (wk_...) for checks, redeem and keys trial-key |
Integration tests run against testnet, spend testnet NEAR and take minutes,
so they run only when asked for: set OUTLAYER_LIVE_TESTS=1. Without it every
live test prints SKIP and cargo test stays fast. Requires outlayer login testnet. Run them before a release and after any change to the commands they
cover.
Execution tests auto-detect: if TESTNET_PAYMENT_KEY is set, calls go via HTTPS API; otherwise they use on-chain request_execution (costs ~0.002 NEAR per call).
# Run all tests (on-chain mode — no payment key needed)
OUTLAYER_LIVE_TESTS=1 cargo test --test integration -- --show-output
# With payment key (HTTPS mode — faster, no NEAR cost)
TESTNET_PAYMENT_KEY="owner:nonce:secret" OUTLAYER_LIVE_TESTS=1 cargo test --test integration -- --show-output
# Individual modules
OUTLAYER_LIVE_TESTS=1 cargo test --test integration -- projects --show-output
OUTLAYER_LIVE_TESTS=1 cargo test --test integration -- run --show-output
OUTLAYER_LIVE_TESTS=1 cargo test --test integration -- secrets --show-output
OUTLAYER_LIVE_TESTS=1 cargo test --test integration -- full_flow --show-output--show-output prints test logs (mode, tx hashes, results). Use --nocapture to see logs even for passing tests in real-time.
Full documentation: docs/CLI.md