Skip to main content

Nava Claw

An autonomous AI agent that trades on-chain, remembers what it learns, and runs on a schedule. Built for crypto traders, DeFi degens, and anyone who wants an agent that can actually do things, sign transactions, execute swaps, manage positions, and grow smarter over time.

Nava-Claw is a TypeScript monorepo that ships as a single server: plug in a model provider, point it at a chain, give it skills, and let it run.

Overview

What You Get

  • Multi-chain execution. Protocol-specific execution skills (e.g., verified-swap for Uniswap) handle calldata generation, Nava verification, and broadcast internally. Add a new protocol by creating a skill, no code changes required.
  • Nava verification. Every on-chain action passes through the Nava arbiter before execution. Safety rails you don’t have to think about.
  • Skills on demand. Drop a SKILL.md file into ./skills/ and the agent learns a new capability on the fly. Skills are listed in a compact catalog; the agent reads them via cat when needed, not injected into the prompt. Hot-reloaded, no restart needed.
  • Cron and heartbeat. Schedule recurring jobs with cron expressions. Skills can declare their own schedules in frontmatter.
  • Memory. Typed memory tool with search, recall, and observe actions. Backed by Postgres + pgvector for persistent semantic search, or zero-config in-memory mode for development. Memory is accessed on demand, not injected into every prompt.
  • Channels. Talk to your agent via Telegram or Slack. Channel plugins are composable and easy to extend.
  • Any model. Claude, GPT, Gemini, Ollama, OpenRouter. Swap providers without changing your agent config.

Architecture

nava-claw/
├── apps/
│ └── server/ @nava-claw/server HTTP server, boot sequence, graceful shutdown
├── packages/
│ ├── shared/ @nava-claw/shared Logging (tslog), common utilities
│ ├── config/ @nava-claw/config Config loader, validation, execution context
│ ├── models/ @nava-claw/models Multi-provider discovery (OpenAI, Anthropic, Google, Ollama, etc.)
│ ├── memory/ @nava-claw/memory Postgres + pgvector search, cron store, in-memory fallback
│ ├── skills/ @nava-claw/skills Skill loader, watcher, frontmatter parsing
│ ├── channels/ @nava-claw/channels Channel plugins (Telegram, Slack), routing, delivery
│ ├── pipeline/ @nava-claw/pipeline Command queue, agent runner, text chunking
│ ├── heartbeat/ @nava-claw/heartbeat Cron tool, scheduled skills, heartbeat runner
│ ├── tools/ @nava-claw/tools Payload store, MCP client, tool assembly
│ └── trading/ @nava-claw/trading Generic sign + execute pipeline, Nava verification
└── skills/ Skill definitions (SKILL.md files)

Data flow: Inbound message (channel) enters the pipeline (model call, tools) and produces an outbound reply (channel). The heartbeat triggers jobs on cron schedules. On-chain execution is handled by protocol-specific skills that bundle calldata generation, Nava verification, and broadcast into self-contained scripts. Skills are read on demand via bash. Memory is queried via the memory tool.

Setup

Prerequisites

  • Node.js 22+ (nvm install 22)
  • pnpm (npm install -g pnpm)
  • Foundry (optional, for on-chain reads via cast-read)
  • Docker (optional, for Postgres persistence; omit DATABASE_URL for in-memory mode)

Quick Start

The fastest path is the interactive setup wizard, which handles deps, builds, provider config, channels, skills, and generates config.json + .env for you.

Claude Code

git clone --recursive git@github.com:navalabs-dev/nava-claw.git && cd nava-claw

Open a Claude Code session and run:

/setup

Cursor

Open the project in Cursor and ask:

Set up nava-claw

Cursor picks up the setup rule automatically.

Manual

git clone --recursive git@github.com:navalabs-dev/nava-claw.git && cd nava-claw
pnpm install && pnpm build
cp .env.example .env # Fill in your API keys and secrets
# Create config.json (see Configuration)
pnpm --filter @nava-claw/server start

The server starts on http://localhost:4747. Health check at /health.

Docker (with Postgres Persistence)

cp .env.example .env   # Fill in your API keys
# Create config.json (see Configuration)
docker compose up

This starts Postgres (pgvector) + the app. Memory, cron jobs, and sessions persist across restarts. To run without persistence, just omit DATABASE_URL from .env and run the server directly.

Development

pnpm build          # Build all packages (TypeScript project references)
pnpm check # Type-check without emitting
pnpm test # Run all tests (Vitest)
pnpm clean # Clean build artifacts

API Endpoints

MethodPathDescription
GET/healthHealth check ({ status: "ok", uptime })
GET/readyReadiness probe (503 if not ready)

Configuration

Nava-Claw uses two config sources: secrets in .env and everything else in config.json.

Environment Variables

See .env.example for the full list. Key ones:

VariableRequiredDescription
ANTHROPIC_API_KEYAt least one provider keyAnthropic API key
OPENAI_API_KEYAt least one provider keyOpenAI API key
TELEGRAM_BOT_TOKENIf using TelegramBot token from @BotFather
SLACK_BOT_TOKENIf using SlackBot token from Slack app
PRIVATE_KEYIf tradingHex-encoded private key for signing
WALLET_ADDRESSIf tradingCorresponding wallet address
RPC_URLIf tradingChain RPC endpoint
UNISWAP_API_KEYIf using UniswapFrom https://hub.uniswap.org
NAVA_API_KEYIf tradingNava arbiter API key
DATABASE_URLFor persistencePostgres connection string (omit for in-memory)
EXECUTION_MODENodirect (default) or dry-run
PORTNo (default: 4747)HTTP server port
LOG_LEVELNo (default: info)debug, info, warn, error

config.json

{
"port": 4747,
"agents": [
{
"id": "default",
"name": "Nava",
"provider": "anthropic",
"model": "claude-sonnet-4-6",
"identity": "You are Nava, an autonomous trading agent..."
}
],
"providers": {
"anthropic": {
"baseUrl": "https://api.anthropic.com",
"apiKey": { "env": "ANTHROPIC_API_KEY" },
"api": "anthropic-messages",
"models": [
{ "id": "claude-sonnet-4-6", "name": "Sonnet 4.6", "contextWindow": 1000000, "supportsToolUse": true }
]
}
},
"channels": {
"telegram": {
"enabled": true,
"accounts": {
"default": { "botToken": { "env": "TELEGRAM_BOT_TOKEN" } }
}
}
},
"chain": { "id": 42161, "name": "Arbitrum One" },
"tools": {
"bash": {
"enabled": true,
"allow": {
"commands": ["curl", "cast-read", "cat", "jq", "grep", "head", "echo"],
"paths": ["./skills"]
}
},
"typed": true
}
}

Secrets use the { "env": "VAR_NAME" } pattern. Never hardcode keys in config.

Supported Chains

ChainIDNotes
Ethereum Mainnet1Highest liquidity, higher gas
Base8453Coinbase L2, low fees, growing DeFi
Arbitrum One42161Fast, low cost, most common for Uniswap
Polygon137Uniswap + Polymarket
Hyperliquid999Perpetuals and spot trading
Sepolia11155111Testnet, no real funds

Writing Skills

Skills are markdown files that teach the agent new behaviors. Drop a SKILL.md into ./skills/<name>/ and it’s live on the next heartbeat cycle.

Directory Structure

skills/
core/ Auto-enabled (cast-read, testnet, mcporter)
reference/ Supplementary docs (Uniswap Trading API, Uniswap driver)

Skill Format

---
name: my-strategy
description: My custom trading strategy
tags: trading
schedule: "0 */2 * * *" # Optional: runs every 2 hours
---

# My Strategy

Describe what the agent should do...

How Skills Work

  • Skills are listed in a compact catalog; the agent reads them via cat when needed, not injected into the prompt.
  • Hot-reloaded, no restart needed.
  • Skills can declare their own schedules in frontmatter using cron expressions.
  • The heartbeat runner triggers scheduled skills on their cron schedule.
  • Protocol-specific execution skills (e.g., verified-swap for Uniswap) bundle calldata generation, Nava verification, and broadcast into self-contained scripts.

Channels

Talk to your Nava-Claw agent via Telegram or Slack. Channel plugins are composable and easy to extend.

Telegram

  1. Create a bot via @BotFather and get the bot token.
  2. Set TELEGRAM_BOT_TOKEN in .env.
  3. Enable in config.json:
{
"channels": {
"telegram": {
"enabled": true,
"accounts": {
"default": { "botToken": { "env": "TELEGRAM_BOT_TOKEN" } }
}
}
}
}

Slack

  1. Create a Slack app and get the bot token.
  2. Set SLACK_BOT_TOKEN in .env.
  3. Enable in config.json:
{
"channels": {
"slack": {
"enabled": true,
"accounts": {
"default": { "botToken": { "env": "SLACK_BOT_TOKEN" } }
}
}
}
}