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

@axon-trading/sdk

v1.2.4

Published

Axon SDK — typed TypeScript client for the local Axon trading daemon. Drive Hyperliquid perp trades, wallets, and policy from AI agents (Claude Code, Claude Desktop, Cursor, Codex, Cline, Continue, Zed, Windsurf, OpenClaw) or any Node.js script. Non-custo

Readme

@axon-trading/sdk

🔌 Typed TypeScript client for the Axon trading daemon. Drive Hyperliquid perp trades, wallets, and policy from AI agents (Claude Code, Claude Desktop, Cursor, Codex, Cline, Continue, Zed, Windsurf, OpenClaw) or any Node.js script. Every function is fully typed, every error has a machine-readable rejection code, and the public surface stays stable across versions.

Lives in browser (the Axon dashboard uses it) and any Node-compatible MCP runtime. Fully typed. ~30 KB unpacked. Zero hidden network calls — only talks to your local daemon at http://127.0.0.1:47890. Non-custodial: the SDK never sees a private key. Signing happens inside the daemon.

✨ What's new in 1.0.0

  • 📦 Strategy typesStrategyManifest, CatalogStrategy, StrategyPricing, StrategyAuthor exposed for marketplace integration. Use these to build catalog browsers, strategy editors, or signature verifiers in your own code.
  • 🛒 Marketplace client methodssignMarketplaceChallenge({ kind, … }) for the daemon-side EIP-712 envelope signing (auth challenges, votes, uploads). Wraps the pending-action ceremony so your code just awaits the signed payload.
  • 💰 x402 / EIP-3009 typesX402Receipt, payment intent shapes for paid-strategy purchase flows. Phase 9.0/9.1 hardening enforces strict validation in the daemon before any signature emits — you get typed errors for every mismatch path.
  • 🔄 Health surface gains updateAvailable — your client can prompt users to upgrade when an outdated daemon version detects a new release on npm.
  • 🛡️ Backwards-compatible — every public type from 0.x / 1.0.0-rc.x is preserved. Major version bump signals that we're committing to public-API stability going forward.

Full changelog: CHANGELOG.md.

Works With

| Runtime / use case | How | |---|---| | Claude Code | Use via @axon-trading/mcp (auto-installed) — or import the SDK directly in a custom script | | Claude Desktop | Same — the MCP adapter wraps this SDK | | Cursor | import { createClientFromEnv } from "@axon-trading/sdk" in a script the agent can run | | Codex | Same — full SDK works inside Codex's Node sandbox | | Cline (VS Code) | Same — drop the SDK into any project Cline can edit | | Continue.dev | Same | | Zed | Same | | Windsurf | Same | | OpenClaw | Adapter at packages/adapters/openclaw/ wraps this SDK | | Custom AI agent | import { createClientFromEnv } from "@axon-trading/sdk" | | LangChain tool | Wrap SDK methods in Tool instances | | Backtesting harness | Read-only methods (getPositions, getOhlcv, getTradeHistory) | | Dashboard / UI | Browser-safe; auto-binds globalThis.fetch | | MCP adapter | Already used internally by @axon-trading/mcp | | Server-side automations | import { AxonClient } from "@axon-trading/sdk" |

Built for: Claude Code • Claude Desktop • Codex • Cursor • Continue • Cline • Zed • Windsurf • OpenClaw • LangChain • LangGraph • AutoGPT • CrewAI • custom Node/browser apps

Perfect For

  • 🤖 AI agent toolchains — exposes every Axon capability as a fully-typed function. Branch on rejection codes, never parse free-form messages.
  • 📊 Backtesting + research — pure read methods (getOhlcv, getTradeHistory, getPositions) with TypeScript types.
  • 🌐 Dashboards and admin UIs — browser-safe; the Axon dashboard itself uses this SDK.
  • 🔄 Trading automations — webhooks, cron jobs, or arbitrage loops that drive the daemon programmatically.
  • 🧪 Integration tests — spin up a demo-mode daemon and use the SDK to verify your agent logic before going live.

Table of Contents

Features

  • 🎯 Fully typed — every method's params + return shapes are TypeScript-typed
  • 🔌 Auto-discoverycreateClientFromEnv() reads ~/.axon/agent.env automatically
  • 🔁 Retry-aware — built-in retry on transient daemon-restart errors
  • 📜 Structured rejections — every venue/policy rejection is a typed RejectionResult with a machine-readable code
  • 🌐 Browser-safe — auto-binds fetch to globalThis to dodge the Window.fetch Illegal invocation trap
  • 🔢 Helper buildersopenPerp({...}), closePerp({...}), etc. produce correctly-shaped intents
  • 📊 SSE streamingstreamEvents() for live audit-log + position updates
  • 🧪 Test-friendly — accepts a custom fetchFn so tests can mock without monkey-patching globals

Prerequisites

  • Node.js ≥ 20 (for SDK consumers in Node) — or any modern browser
  • The Axon daemon running locallynpm install -g @axon-trading/cli && axon
  • TypeScript ≥ 5.0 (recommended; the SDK ships .d.tss)

Installation

npm install @axon-trading/sdk
# OR
pnpm add @axon-trading/sdk
# OR
yarn add @axon-trading/sdk

For the pre-release line:

npm install @axon-trading/sdk@next

Quick Start

import { createClientFromEnv, openPerp } from "@axon-trading/sdk";

// Reads AXON_URL + AXON_TOKEN from env / ~/.axon/agent.env
const client = await createClientFromEnv({ retry: true });

const result = await client.placeIntent(
  openPerp({
    venue: "hyperliquid",
    symbol: "BTC",
    side: "long",
    leverage: 5,
    sizeUsd: 100,
  }),
);

if (!result.ok) {
  // ALWAYS branch on result.code — never parse result.message
  console.error(`Rejected: ${result.code}`);
  if (result.code === "HL_INSUFFICIENT_MARGIN") {
    // Reduce size or deposit more
  }
  return;
}

console.log(`Filled ${result.filled.size} ${result.filled.symbol} @ ${result.filled.avgPrice}`);

Authentication

Axon's local API uses bearer-token auth. Tokens rotate on every daemon boot, so the SDK reads them fresh.

Auto-discovery (recommended)

import { createClientFromEnv } from "@axon-trading/sdk";

// Resolution order:
//   1. process.env.AXON_URL + AXON_TOKEN
//   2. ~/.axon/agent.env (auto-written by daemon every boot)
//   3. Legacy: ~/.axon/session.token + AXON_URL fallback
const client = await createClientFromEnv({ retry: true });

Manual construction

import { AxonClient } from "@axon-trading/sdk";

const client = new AxonClient({
  baseUrl: process.env.AXON_URL ?? "http://127.0.0.1:47890",
  token: process.env.AXON_TOKEN!,
  userAgent: "my-agent/1.0",       // identifies you in the daemon's audit log
  timeoutMs: 15_000,                // default: 15s
});

Container / serverless

Pass env explicitly — auto-discovery requires filesystem access to ~/.axon/agent.env.

const client = new AxonClient({
  baseUrl: process.env.AXON_URL!,
  token: process.env.AXON_TOKEN!,
});

Trading API

placeIntent(intent: Intent): Promise<IntentResult>

The single entry point for trading. Pass any intent built from the helpers below.

Intent helpers

import {
  openPerp,
  closePerp,
  cancelOrder,
  updateLeverage,
} from "@axon-trading/sdk";

openPerp(args)

const intent = openPerp({
  venue: "hyperliquid",     // "hyperliquid" | "lighter"
  symbol: "BTC",             // venue's canonical perp symbol
  side: "long",              // "long" | "short"
  leverage: 5,               // 1..venue-max-leverage
  sizeUsd: 100,              // notional size in USD
  reduceOnly: false,         // optional: only close existing position
  clientId: "my-bot-001",    // optional: idempotency key (16 bytes max for HL)
  limitPrice: 67_500.0,      // optional: limit order; omit for market
});

const result = await client.placeIntent(intent);
// IntentResult success shape:
// {
//   ok: true,
//   intentId: "intent_<uuid>",
//   venue: "hyperliquid",
//   filled: {
//     symbol: "BTC",
//     side: "long",
//     size: 0.0015,         // base units
//     avgPrice: 67_492.5,
//     fee: 0.05,             // USD
//   },
//   txProofUrl: "https://app.hyperliquid.xyz/orders/...",
// }

closePerp(args)

const intent = closePerp({
  venue: "hyperliquid",
  symbol: "ETH",
  sizeBase: 0.5,             // close 0.5 ETH (use the position's size for full close)
  // OR: sizePct: 100 for full close
  clientId: "close-eth-001",
});

const result = await client.placeIntent(intent);

cancelOrder(args)

const intent = cancelOrder({
  venue: "hyperliquid",
  symbol: "BTC",
  orderId: "0x...",          // from a previous open's response, or `getOrders()`
});

updateLeverage(args)

const intent = updateLeverage({
  venue: "hyperliquid",
  symbol: "ETH",
  leverage: 10,
  isCross: false,            // optional; default false (isolated margin)
});

Read API

All read methods return typed results. No signing, no side effects, no policy gates.

client.getBalance(): Promise<Balance>
// { onChainUsdc, hyperliquidMargin, ethGas, totalEquityUsd }

client.getPositions(): Promise<Position[]>
// [{ venue, symbol, side, size, entryPrice, markPrice, unrealizedPnl, leverage, liquidation, ... }]

client.getMarkets(venue?: "hyperliquid" | "lighter"): Promise<Market[]>
// [{ venue, symbol, tickSize, minSizeUsd, maxLeverage, ... }]

client.getTicker(venue, symbol): Promise<Ticker>
// { mark, bid, ask, last, volume24h, fundingRate, ... }

client.getOhlcv(venue, symbol, interval, limit?): Promise<Candle[]>
// [{ ts, open, high, low, close, volume }, ...]
// interval: "1m" | "5m" | "15m" | "1h" | "4h" | "1d"

client.getTradeHistory(opts?: { limit?, symbol?, status?, venue? }): Promise<TradeRow[]>
// Normalized fills + open orders across venues

client.getAuditEvents(opts?: { limit?, kinds?, agentId?, refId? }): Promise<AuditEvents>
// Hash-chained audit log (every intent, rejection, signed action)

client.inspectBridgeBalance(opts?: { ownerAddress? }): Promise<BridgeStatus>
// Cross-references on-chain USDC vs HL credited margin (debug stuck deposits)

client.runDoctor(): Promise<DoctorReport>
// Full system health check

Streaming

const stream = client.streamEvents({ kinds: ["intent_placed", "intent_filled"] });
for await (const event of stream) {
  console.log(event.kind, event.payload);
}
// Send AbortController.signal to stop

Wallet Management

client.listWallets(opts?: { includeHealth? }): Promise<WalletListResult>
// { wallets: [{ id, label, address, kind, isActive, status }], activeWalletId }

client.setActiveWallet(walletId: string): Promise<{ ok: true }>
client.renameWallet(walletId: string, label: string): Promise<{ ok: true }>

client.listAgentBindings(): Promise<AgentBindingsResult>
// { bindings: [{ clientId, walletId, walletLabel }], knownClientIds, defaultWalletId }

client.setAgentBinding({ clientId, walletId }): Promise<{ ok: true }>
client.setDefaultBinding(walletId: string): Promise<{ ok: true }>

Pending Actions (passphrase via browser)

Some operations require the user's master-EOA passphrase. The SDK never collects passphrases. Instead, these methods return a PendingActionResult containing a confirmationUrl — display it to the user; they enter their passphrase in a browser form; you then poll for the result.

client.generateWalletPending(opts?: { label? }): Promise<PendingActionResult>
client.importWalletPending({ mnemonic, label? }): Promise<PendingActionResult>
client.importWalletFromPkPending({ privateKey, label? }): Promise<PendingActionResult>
client.deleteWalletPending(walletId: string): Promise<PendingActionResult>
client.transferUsdcPending({ from, to, amount }): Promise<PendingActionResult>
client.hlDepositPending({ amount }): Promise<PendingActionResult>
client.hlSpotToPerpPending({ amount, reverse? }): Promise<PendingActionResult>
client.approveBuilderPending(opts?: { maxFeeRate? }): Promise<PendingActionResult>
client.killSwitchOffPending(): Promise<PendingActionResult>
client.setModePending(mode: "demo" | "testnet" | "live"): Promise<PendingActionResult>

Polling pattern

const pending = await client.hlDepositPending({ amount: 20 });

console.log(`Open this URL to confirm: ${pending.confirmationUrl}`);
// User opens URL, enters passphrase, submits

const result = await client.pollPendingAction(pending.token, { timeoutMs: 300_000 });

if (!result.ok) {
  if (result.code === "BAD_PASSPHRASE") {
    // Tell user their passphrase was wrong; they can retry on the same page
  } else if (result.code === "EXPIRED") {
    // Token expired (5min default) — re-call hlDepositPending() to get a fresh one
  }
}

The PendingActionResult shape:

{
  pending: true,
  token: "pa_<32hex>",
  confirmationUrl: "http://127.0.0.1:47890/confirm/pa_<32hex>",
  pollUrl: "/v1/pending/pa_<32hex>",
  expiresAt: 1700000300000,
}

Operations

client.killSwitchOn(): Promise<{ ok: true }>
// Agents CAN arm — safety always wins. Cancels every open order, halts new ones.

client.getMode(): Promise<{ running: ModeId, latched: ModeId }>
// running = current process; latched = what next restart will boot into

client.auditVerify(opts?: { sinceMs? }): Promise<AuditVerifyResult>
// Verify the hash chain. Returns { ok: true, events: 1234 } or throws AuditTamperError.

client.listAnchors(limit?: number): Promise<AnchorRow[]>
// On-chain settlement anchors (weekly Merkle-root summaries, hashes anchorable on-chain)

client.settleNow(): Promise<{ ok: boolean, ranSettlement: boolean, txHash?: string }>
// Force a settlement cycle (normally weekly cron-driven)

client.getPolicy(): Promise<PolicyShape>
// Read current policy. AGENTS CANNOT MODIFY — read-only.

Error Handling

Every method either:

  • Returns a typed success result, OR
  • Returns a RejectionResult with a structured code:
type RejectionResult = {
  ok: false;
  code: RejectionCode;       // e.g. "HL_INSUFFICIENT_MARGIN"
  message: string;            // human-readable
  hint?: string;              // optional recovery hint
  field?: string;             // optional field name that was the problem
};

Always branch on code, NEVER parse message. Codes are stable; messages are not.

Common patterns

const result = await client.placeIntent(openPerp({ ... }));

if (!result.ok) {
  switch (result.code) {
    case "HL_INSUFFICIENT_MARGIN":
      // Reduce size or deposit more
      break;
    case "HL_BUILDER_FEE_NOT_APPROVED":
      // Call approveBuilderPending() first
      break;
    case "HL_AGENT_NOT_APPROVED":
      // User: run `axon hl revoke-agent`, then retry
      break;
    case "KEYSTORE_LOCKED":
      // Tell user to unlock via dashboard
      break;
    case "WALLET_BINDING_MISMATCH":
      // Show the bound wallet vs active wallet; offer to rebind
      break;
    case "POLICY_PER_AGENT_CAP":
      // Daily notional cap reached — wait or raise cap
      break;
    case "KILL_SWITCH_DENIED":
      // Tell user to disarm in dashboard
      break;
    default:
      console.error(`Unhandled rejection: ${result.code} — ${result.message}`);
  }
}

Full code reference: docs/REJECTION_CODES.md.

Network-level errors throw AxonError

import { AxonError } from "@axon-trading/sdk";

try {
  await client.getBalance();
} catch (err) {
  if (err instanceof AxonError) {
    // Daemon unreachable, timeout, malformed response, etc.
    // Retry with backoff, OR tell user the daemon isn't running.
    console.error("Daemon not reachable:", err.message);
  } else {
    throw err;
  }
}

Retry pattern

async function withRetry<T>(
  fn: () => Promise<T>,
  maxAttempts: number = 3,
): Promise<T> {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (!(err instanceof AxonError) || attempt === maxAttempts) throw err;
      await new Promise((r) => setTimeout(r, 1000 * attempt));
    }
  }
  throw new Error("unreachable");
}

const balance = await withRetry(() => client.getBalance());

The SDK already does this when constructed via createClientFromEnv({ retry: true }).

Type Definitions

import type {
  Intent,
  IntentResult,
  Balance,
  Position,
  Market,
  Ticker,
  Candle,
  Order,
  Fill,
  TradeRow,
  AuditEvent,
  AuditEvents,
  PendingActionResult,
  RejectionResult,
  RejectionCode,
  WalletKind,
  WalletRow,
  WalletListResult,
  AgentBindingsResult,
  PolicyShape,
  ModeId,
  StreamChannel,
  StreamEvent,
} from "@axon-trading/sdk";

All exported. See dist/types.d.ts in the package for the canonical definitions.

TypeScript Best Practices

Type-narrow on result.ok

const result = await client.placeIntent(openPerp({ ... }));

if (result.ok) {
  // TypeScript knows result.filled is defined here
  const avgPrice: number = result.filled.avgPrice;
} else {
  // TypeScript knows result.code is a RejectionCode union here
  const code: RejectionCode = result.code;
}

Custom type guards

import { IntentResult, RejectionResult } from "@axon-trading/sdk";

function isRejection(result: IntentResult): result is RejectionResult {
  return result.ok === false;
}

const result = await client.placeIntent(intent);
if (isRejection(result)) {
  // ...
}

Strict policy on rejection codes

import { RejectionCode } from "@axon-trading/sdk";

// Compile-time-checked exhaustive switch:
function explainRejection(code: RejectionCode): string {
  switch (code) {
    case "HL_INSUFFICIENT_MARGIN": return "Reduce size or deposit more.";
    case "HL_TICK_SIZE": return "Round price to the venue's tick.";
    case "KEYSTORE_LOCKED": return "Unlock the keystore in the dashboard.";
    // ... add cases. TypeScript will warn about unhandled codes when the
    //     RejectionCode union grows in a future SDK version.
    default: {
      const _exhaustive: never = code;
      return `Unknown rejection: ${code}`;
    }
  }
}

Browser Usage

The SDK is browser-safe — the Axon dashboard itself uses it. Two notes:

  1. The SDK auto-binds globalThis.fetch to window to avoid the TypeError: Illegal invocation trap (Window.fetch needs window as receiver).
  2. Browsers strip the standard User-Agent header (per Fetch spec); the SDK duplicates it as x-axon-client so the daemon can still classify requests.
// In a Vite / Next / etc. browser app:
import { AxonClient } from "@axon-trading/sdk";

const client = new AxonClient({
  baseUrl: "http://127.0.0.1:47890",
  token: localStorage.getItem("axon-token") ?? "",
});

const positions = await client.getPositions();

For dashboard-style apps, prefer the SDK's React-Query helpers (no separate package — just standard useQuery({ queryFn: () => client.getBalance() })).

Advanced Topics

Custom fetchFn (testing)

import { AxonClient } from "@axon-trading/sdk";

const calls: any[] = [];
const fakeFetch: typeof fetch = async (url, init) => {
  calls.push({ url, init });
  return new Response(JSON.stringify({ ok: true, version: "test" }), {
    headers: { "content-type": "application/json" },
  });
};

const client = new AxonClient({
  baseUrl: "http://127.0.0.1:1",
  token: "test-token",
  fetchFn: fakeFetch,
});

await client.getHealth();
console.log(calls[0].url); // http://127.0.0.1:1/v1/health

Custom user-agent

const client = new AxonClient({
  baseUrl: "http://127.0.0.1:47890",
  token: TOKEN,
  userAgent: "my-research-bot/2.1",  // shown in /v1/connections/status + audit log
});

When unset, defaults to @axon-trading/sdk/<version>. Setting a custom UA helps the user (a) see your agent in the dashboard's Agents tab, (b) bind it to a specific wallet, (c) trace its calls in the audit log.

Custom timeout

const client = new AxonClient({
  baseUrl: "...",
  token: "...",
  timeoutMs: 60_000,  // default 15s; bump for slow venue calls
});

Worker-based polling

For long-running bots, use SSE streaming instead of polling:

const stream = client.streamEvents({ kinds: ["intent_filled", "balance_changed"] });

for await (const event of stream) {
  if (event.kind === "intent_filled") {
    // Update internal state, send Discord notification, etc.
  }
}

Troubleshooting

AxonError(DAEMON_UNREACHABLE) (rc.5+)

The SDK's HTTP request hit a closed port — daemon is configured but not running. The error includes details.fix carrying the literal command to relay:

try {
  await client.getBalance();
} catch (err) {
  if (err instanceof AxonError && err.code === "DAEMON_UNREACHABLE") {
    // err.details.fix === "Run `axon` in a terminal to start the daemon. ..."
    console.error("Tell the user:", err.details?.fix);
  }
}

In practice: open a terminal and run axon. If you don't have the CLI installed:

npm install -g @axon-trading/cli@next
axon

AxonError(DAEMON_NOT_INSTALLED) (rc.5+)

createClientFromEnv() couldn't find credentials AND no axon binary on PATH — the user has never installed Axon. The error's details.state distinguishes:

  • state: "no-cli" → install + start: npm install -g @axon-trading/cli@next && axon
  • state: "cli-no-creds" → CLI is installed; just run axon
  • state: "cli-creds-stale" → restart with axon to regenerate agent.env

err.details.fix carries the right command for each state — agents should relay it verbatim.

Legacy AxonError(NETWORK)

Generic fetch failure not recognized by fromFetchFailure. Pre-rc.5 SDK consumers see this for daemon-down scenarios; rc.5+ surfaces DAEMON_UNREACHABLE instead. If you're catching NETWORK, check err.details?.cause for hints — but prefer branching on DAEMON_UNREACHABLE going forward.

UNAUTHORIZED after daemon restart

The bearer token rotated. The SDK auto-retries when constructed via createClientFromEnv({ retry: true }). If you've cached the token manually, re-read ~/.axon/agent.env or restart your client.

KEYSTORE_LOCKED on every call

The daemon is running but locked. Tell the user to open the dashboard at http://127.0.0.1:47890 and enter their passphrase. Agents cannot unlock — by design.

Browser: TypeError: Illegal invocation

You're constructing the client without the auto-bind. Use either createClientFromEnv() OR construct via new AxonClient({ ... }) without overriding fetchFn — the constructor handles the bind for you.

If you must pass a custom fetchFn in a browser:

const client = new AxonClient({
  baseUrl: "...",
  token: "...",
  fetchFn: window.fetch.bind(window), // explicit bind
});

Stale data in long-running bots

Read methods don't cache. If you see stale balances after a trade, the venue's API is the bottleneck — Hyperliquid takes ~500ms to reflect a fill. Add a small delay:

await client.placeIntent(openPerp({ ... }));
await new Promise(r => setTimeout(r, 1000));
const balance = await client.getBalance(); // now reflects the new fill

FAQ

Do I need to install @axon-trading/cli to use this?

Yes — the SDK talks to the local daemon, which is shipped in the CLI package. Run axon to start it.

Can I use this in serverless?

Yes, but only if your serverless environment can reach the local daemon. Common pattern: run the daemon on a VPS, set AXON_HOST=0.0.0.0 (with AXON_ALLOW_NETWORK_EXPOSURE=1), and have your serverless function point at that VPS. Note: doing so exposes the daemon to the internet — strongly recommended to put a reverse proxy with rate-limiting + IP allowlist in front.

Does the SDK support paper trading?

Yes — start the daemon in demo mode (axon --demo or no flag). All trades are synthesized; balances are local-only. Same SDK calls, same response shapes.

Why are pending actions returned as URLs instead of just signing?

Because the SDK never collects passphrases. The browser confirmation pattern keeps the passphrase off the LLM transcript and out of the SDK's call stack. The user's keystore unlock state lives only in daemon memory.

How do I detect when the daemon restarts?

AxonError with a cause of ECONNREFUSED or repeated UNAUTHORIZED rejections. Or use streamEvents() — when the connection drops, you know.

Can I run the SDK in a Cloudflare Worker / Vercel Edge / Deno?

The SDK is ESM + uses standard fetch. Runtime compatibility is mostly good. Caveat: those edge runtimes can't read ~/.axon/agent.env, so always pass baseUrl + token explicitly.

Does this support both Hyperliquid and Lighter?

The intent API is venue-agnostic. Hyperliquid is wired in v1.0; Lighter is on the v1.1 roadmap with the adapter scaffolded. Use getMarkets("lighter") to see if it's live in your version.

License

Proprietary. © 2026 Strykr Labs. All rights reserved. See LICENSE for the full proprietary notice and TRADEMARKS.md for trademark policy. Licensing inquiries: [email protected].


Source: https://github.com/Strykr-Labs/Axon-Agent-Trading Docs: https://github.com/Strykr-Labs/Axon-Agent-Trading/tree/main/docs Companion packages: @axon-trading/cli · @axon-trading/mcp