npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@towns-labs/wallet

v7.3.1

Published

Your keys. Your account. No signup. No login. Just run it.

Downloads

434

Readme

tw — Towns Wallet CLI

Your keys. Your account. No signup. No login. Just run it.

tw is a local-first CLI for managing smart accounts, session keys, and on-chain permissions on Towns Protocol. It works for humans at the terminal and for agents over --json or --mcp.

bunx @towns-labs/wallet --help

Quick Start

Create an account and send USDC in under a minute:

# 1. Create a local account (interactive password prompt)
tw account create --profile main

# 2. Fund it
tw address --qr --amount 100

# 3. Send USDC
tw account send 10 vitalik.eth

No custody service. No API key. Everything runs locally with encrypted keystores.


How It Works

tw manages a local keystore that holds your root key and session keys. Your root key creates and controls your on-chain smart account. Session keys are scoped signers — they can send transactions through the Towns relayer without exposing your root key.

~/.config/towns/tw/profiles/<env>/<profile>/default.keystore.json
~/.config/towns/tw/profiles/<env>/<profile>/sessions/<session-name>.json

For agents, the session daemon keeps decrypted keys in memory for a bounded duration so automated workflows can sign without prompting for a password on every call.


Commands

Account

account create — Create a new account

tw account create --profile agent

Resume a previously interrupted flow:

tw account create --resume --profile agent

Non-interactive (stdin password + JSON):

echo "my-password" | tw account create --password-stdin --json

Use an explicit keystore path:

tw account create --keystore-path ~/.config/towns/tw/profiles/prod/team/default.keystore.json

account status — Check readiness

tw account status --profile agent --json

account balance — Check USDC balance

tw account balance --profile agent
tw account balance --profile agent --chain polygon

account address — Print root address

tw account address --profile agent

account send — Send USDC

tw account send 1 0x1111111111111111111111111111111111111111
tw account send 2.5 vitalik.eth --chain base
tw account send 10 treasury --chain polygon --json

Use a specific local session (without changing active session):

tw account send 1 0x... --profile agent --session worker-2

Use a portable session file (no root keystore required):

tw account send 1 0x... --chain base --session-file ./worker-1.session.json

--session and --session-file are mutually exclusive.

account swap — Swap tokens on the same chain

Powered by relay.link. Interactive confirmation by default.

tw account swap --from ETH --to USDC --amount 0.1 --chain base
tw account swap --from USDC --to ETH --amount 50 --chain base --yes --json

account bridge — Bridge tokens cross-chain

tw account bridge --token USDC --amount 100 --to-chain polygon
tw account bridge --token ETH --amount 0.5 --to-chain base --recipient 0x... --yes --json

account delegate — Delegate on additional chains

If your account was created on Base and you need it on Polygon:

echo "my-password" | tw account delegate --chain polygon --profile agent --password-stdin

account history — Relayer call history

tw account history --profile agent
tw account history --address 0x... --limit 10 --offset 20
tw account history --chain base,polygon --json

--limit defaults to 20 (max 100). offset + limit must be <= 1000.

account export — Export metadata or private keys

tw account export --profile agent --json
tw account export --profile agent --show-private

account nonce — Read account nonce

tw account nonce --profile agent

account update password — Rotate keystore password

tw account update password --profile agent
printf "old\nnew\n" | tw account update password --current-password-stdin --new-password-stdin --json

Address

tw address is a top-level shortcut for showing your funding address with optional payment helpers.

tw address
tw address --link --amount 100
tw address --qr --amount 100

Custom token:

tw address --token 0x... --amount 1 --decimals 18 --link

Session Keys

Session keys are scoped signers that can act on behalf of your account without exposing the root key.

session create — Create and authorize a session key

echo "my-password" | tw session create worker-1 --profile agent --password-stdin --json

Create and activate immediately:

echo "my-password" | tw session create worker-2 --profile agent --activate --password-stdin

Grant full wildcard access:

echo "my-password" | tw session create worker-admin --profile agent --full-access --password-stdin

--full-access is mutually exclusive with --target, --selector, --spend-limit, --spend-limit-raw, and --spend-period. Omitting both --target and --selector uses wildcard call permissions by default.

Resume an interrupted flow:

echo "my-password" | tw session create worker-1 --profile agent --resume --password-stdin --json

Create a session and initialize agent messaging in one step:

echo "my-password" | tw session create alice --profile agent --agent --password-stdin

session list — List local sessions

tw session list --profile agent --json
tw session list --profile agent --on-chain --json

session rotate — Rotate the active session

echo "my-password" | tw session rotate --profile agent --password-stdin --json
echo "my-password" | tw session rotate --profile agent --new-name worker-3 --password-stdin
echo "my-password" | tw session rotate --profile agent --resume --password-stdin --json

session revoke — Revoke a session on-chain

echo "my-password" | tw session revoke worker-1 --profile agent --password-stdin --json
echo "my-password" | tw session revoke worker-2 --profile agent --force --password-stdin
echo "my-password" | tw session revoke worker-2 --profile agent --resume --password-stdin --json

Agent sessions require --force and clean up local channel bindings as part of revocation.

session export — Export as portable file

TW_PASSWORD="my-password" TW_EXPORT_PASSWORD="export-password" \
  tw session export worker-1 --profile agent --output ./worker-1.session.json

Or via stdin:

echo "export-password" | tw session export worker-1 --profile agent \
  --output ./worker-1.session.json --export-password-stdin

session import — Import a portable session

tw session import ./worker-1.session.json --profile worker-1

Creates a session-only profile that can execute account send but cannot run manager commands requiring a root keystore.


Session Daemon

The daemon holds decrypted session keys in memory so automated workflows can sign without re-entering passwords.

session start — Start the daemon

tw session start --json
tw session start --foreground --json

Idempotent — if already running, returns the active pid/socket.

session unlock — Load a key into daemon memory

echo "my-password" | tw session unlock worker-1 --profile agent --password-stdin --duration 15m --json

Key material stays in daemon memory only; encrypted files remain unchanged.

session lock — Remove a key from daemon memory

tw session lock worker-1 --json

session status — Check daemon health

tw session status --json

session stop — Shut down the daemon

tw session stop --json

Permissions

Fine-grained on-chain permission rules for session keys.

permissions list — List keys and their permissions

tw permissions list --profile agent --json

permissions show — Show rules for a specific key

tw permissions show agent-key --profile agent --json
tw permissions show --key-hash 0xaaa... --profile agent --json

permissions grant — Grant a permission rule

Wildcard call permission:

echo "my-password" | tw permissions grant agent-key --type call --target any --selector any --profile agent --password-stdin --json

Daily USDC spend limit:

echo "my-password" | tw permissions grant agent-key --type spend --token USDC --spend-limit 100 --period day --profile agent --password-stdin --json

Use --spend-limit-raw for base units instead of human amounts.

permissions revoke — Revoke permission rules

Revoke a single rule:

echo "my-password" | tw permissions revoke agent-key --rule call:0x...:0xa9059cbb --profile agent --password-stdin --json

Revoke all rules for a key:

echo "my-password" | tw permissions revoke agent-key --all --profile agent --password-stdin --json

Escrow

USDC escrow: lock funds as buyer with a seller and oracle; settle (oracle signs) or refund after deadline.

escrow create — Create a new USDC escrow

tw escrow create 50 0x1111111111111111111111111111111111111111 \
  --oracle 0x2222222222222222222222222222222222222222 --deadline 24h
tw escrow create 100 0x... --oracle 0x... --deadline 2d --chain base --env prod --json
  • Amount and seller are positional; oracle and deadline are required options.
  • Deadline: relative (1h, 2d, 30m, 1w) or unix timestamp. After deadline, anyone can call escrow refund.
  • Optional salt (hex, up to 12 bytes) for unique escrow IDs on repeated orders.
  • Uses session key (daemon or direct) to sign; supports --session-file like account send.

escrow status — Check on-chain status

tw escrow status 0x<64 hex chars> --env prod
tw escrow status 0x... --chain base --json

Escrow ID must be the full 32-byte hex (0x + 64 hex chars), e.g. from escrow create output.

escrow settle — Settle (release USDC to seller)

Oracle signs a settlement; any account can submit the signed settlement via relayer.

TW_ORACLE_PRIVATE_KEY=0x... tw escrow settle 0x<escrowId> \
  --settlement-id 0x<orderId> --oracle 0x2222... --profile agent

Or with pre-signed signature (oracle signs offline):

tw escrow settle 0x<escrowId> --settlement-id 0x... --oracle 0x... --signature 0x... --profile agent

Settlement ID is the bytes32 order ID used at creation (see create output or escrow status).

escrow refund — Refund to buyer after deadline

Permissionless: after the escrow deadline, anyone can trigger refund to the buyer.

tw escrow refund 0x<escrowId> --profile agent
tw escrow refund 0x<escrowId> --env prod --json

Contacts

Store recipient aliases so you never have to copy-paste addresses.

~/.config/towns/tw/contacts.json
tw contacts add vitalik vitalik.eth
tw contacts add treasury 0x1111111111111111111111111111111111111111
tw contacts list --json
tw contacts show vitalik --json
tw contacts update vitalik 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
tw contacts rename vitalik vitalik-main
tw contacts remove vitalik-main

Export and import:

tw contacts export --json
tw contacts import ./contacts.json --json
tw contacts import ./contacts.json --force --json

Import returns importedCount, skippedInvalidCount, skippedConflictCount, and overwrittenCount.

Send via alias:

tw account send 10 vitalik

ENS safety: if ENS re-resolves to a different address than stored, send aborts and requires tw contacts update.


Agents

Agents are session-key-backed Towns identities with their own encryption device and named channel bindings. Identity management lives under tw session; tw agent is reserved for messaging commands.

~/.config/towns/tw/profiles/<env>/<profile>/sessions/<name>.json
~/.config/towns/tw/profiles/<env>/<profile>/agent-channels.json

session create --agent / agent init / session list

TW_PASSWORD="my-password" tw session create alice --profile agent --agent
TW_PASSWORD="my-password" tw session create bob --profile agent
TW_PASSWORD="my-password" tw agent init bob --profile agent
TW_PASSWORD="my-password" tw session list --profile agent --json

tw session list includes a kind field (session or agent). Revoke agent identities with tw session revoke <name> --force.

Migration note: legacy agent-<name>.json files are no longer loaded. Rename them to <name>.json manually or recreate them with tw session create plus tw agent init.

agent connect — Create or bind a named channel

First side creates the channel and returns the shared secret:

TW_PASSWORD="my-password" tw agent connect --from alice --channel art --to bob --profile agent

Second side binds using that secret:

TW_PASSWORD="my-password" tw agent connect --from bob --channel art --secret "<shared-secret>" --to alice --profile agent

agent send — Send a message

To a named channel:

TW_PASSWORD="my-password" tw agent send --from alice --channel art "hello from alice" --profile agent

To a raw stream ID:

TW_PASSWORD="my-password" tw agent send --from alice 77aaa... "debug message" --profile agent

agent listen — Listen for messages

TW_PASSWORD="my-password" tw agent listen --from bob --channel art --profile agent
TW_PASSWORD="my-password" tw agent listen --from bob --stream 77aaa... --profile agent

Messages arrive as NDJSON:

{
  "type": "message",
  "streamId": "77...",
  "senderId": "0x...",
  "eventId": "0x...",
  "timestamp": 1709654400,
  "content": "hello from alice"
}

agent channels — Inspect bindings

TW_PASSWORD="my-password" tw agent channels --from alice --profile agent --json

Agent Quickstart

# Create profile + two agent sessions
tw account create --profile agent
TW_PASSWORD="pw" tw session create alice --profile agent --agent
TW_PASSWORD="pw" tw session create bob --profile agent
TW_PASSWORD="pw" tw agent init bob --profile agent

# Alice creates a channel → copy the returned secret
TW_PASSWORD="pw" tw agent connect --from alice --channel art --to bob --profile agent

# Bob binds with that secret
TW_PASSWORD="pw" tw agent connect --from bob --channel art --secret "<secret>" --to alice --profile agent

# Terminal 1: listen
TW_PASSWORD="pw" tw agent listen --from bob --channel art --profile agent

# Terminal 2: send
TW_PASSWORD="pw" tw agent send --from alice --channel art "hello" --profile agent

Smoke test:

cd packages/wallet
TW_PASSWORD="my-password" bun run smoke:agent

Agent & Automation Integration

Every command supports --json for machine-readable output. Treat JSON output schemas as the stable contract.

tw <command> --json

Password Automation

Use TW_PASSWORD to skip interactive prompts:

TW_PASSWORD="my-password" tw session list --profile agent --json

Or pipe via stdin for commands that accept --password-stdin:

echo "my-password" | tw session rotate --profile agent --password-stdin --json

Discovery

tw --help              # All commands
tw account send --help # Command-specific help
tw --llms              # Machine-readable command manifest
tw --mcp               # Run as MCP server
tw --version           # Version