This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Bun-based TypeScript monorepo for use-agently, a CLI tool for the Agently platform — a decentralized marketplace for AI agents using ERC-8004 and the x402 payment protocol. The CLI manages local EVM wallets, discovers agents, and communicates with them via the A2A (Agent-to-Agent) protocol.
# Install dependencies
bun install
# Build all packages (compiles to standalone binary via bun build --compile)
bun run build
# Run the CLI in development mode
bun run --filter use-agently dev
# Format code
bun run format
# Run tests
bun run testAll top-level commands use Turborepo (turbo) to orchestrate across packages.
packages/localhost-aixyz is the local testing infrastructure for the CLI. It is a private aixyz agent that serves a free A2A endpoint at http://localhost:3000 so you can test use-agently a2a without hitting production agents or spending real funds.
# Terminal 1 — start the local agent (requires OPENAI_API_KEY in packages/localhost-aixyz/.env.local)
bun run --filter localhost-aixyz dev
# Terminal 2 — send a message via the CLI
use-agently a2a send --uri http://localhost:3000 -m "Hello!"The agent exposes a free endpoint (accepts: { scheme: "free" }), so no wallet balance is needed. Set OPENAI_API_KEY in packages/localhost-aixyz/.env.local before starting the dev server.
Always use this agent when developing or testing changes to use-agently to maintain conformity and ensure every change is exercised end-to-end.
- Monorepo: Bun workspaces with
packages/*layout, Turborepo for task orchestration packages/localhost-aixyz: Local development agent (private, not published)aixyz.config.ts— Agent metadata and skillsapp/agent.ts— Free A2A endpoint (accepts: { scheme: "free" }) with echo toolapp/tools/echo.ts— Simple echo tool for testing
packages/use-agently-sdk(@use-agently/sdk): The SDK package (published to npm)client.ts—unstable_Clienttype,createClient(), fetch wrappers (dry-run, payment)agently.ts— Agently platform API (search,getAgentfor ERC-8004 resolution)a2a.ts— A2A protocol:sendMessage,sendMessageStream,getAgentCard, URL resolutionmcp.ts— MCP protocol:listMcpTools,callMcpTool, URL resolutionwallets/— Wallet interface and implementations (EVM private key)utils/— Chain config, transaction mode types
packages/use-agently: The CLI packagesrc/bin.ts— Executable entry point (#!/usr/bin/env bun)src/cli.ts— Commander.js program setup, registers all commandssrc/config.ts— Config persistence at~/.use-agently/config.json(load, save, backup)src/client.ts— CreatesdefaultClientviacreateClient()with CLI user-agent; all CLI commands use this clientsrc/commands/— One file per CLI command (init, whoami, balance, search, a2a)- Build output:
build/use-agently(standalone binary viabun build --compile)
The SDK is structured in three layers: client, platform, and protocol. All new SDK work must follow this layering.
unstable_Client is the low-level primitive. It holds a configured fetch (with User-Agent, etc.) and nothing else. It does not bundle protocol logic. Create one via createClient({ userAgent }).
const client = createClient({ userAgent: "my-app:1.0" });The CLI creates a single defaultClient in src/client.ts and passes it through to all SDK calls.
The Agently API layer (api.use-agently.com). Provides search(client, options) and getAgent(client, id) for agent discovery and ERC-8004 metadata resolution. All functions take unstable_Client as the first argument.
Each protocol file owns its own URL resolution and communication logic. Protocol functions take unstable_Client as the first argument.
- A2A (
a2a.ts):sendMessage(client, uri, message, options?),sendMessageStream(client, uri, message, options?),getAgentCard(client, uri),createA2AClient(client, uri, fetchImpl) - MCP (
mcp.ts):listMcpTools(uri, options?),callMcpTool(uri, tool, args?, options?)
-
unstable_Clientis always the first parameter — every SDK function that makes network requests takesclient: unstable_Clientas its first argument. This provides the configuredfetch. Never use barefetchorclientFetchin protocol-level code. -
Protocol-level URL resolution — each protocol handles its own URI → URL mapping. A2A has
getAgentCardURL()(appends/.well-known/agent-card.json). MCP hasresolveMcpUrl(). The client layer does not resolve URLs. -
ERC-8004 resolution via
getAgent()— ERC-8004 URIs (eip155:...) are resolved throughgetAgent(client, id)fromagently.ts. Each protocol finds its service entry by name (e.g.,services.find(s => s.name === "a2a")). No shortname resolution — URIs are either HTTP(S) URLs or ERC-8004 CAIP-19 IDs. -
Transaction mode via
options.mode— payment behavior is controlled byoptions?: { mode?: TransactionMode }.DryRunTransaction(default) intercepts 402s and throwsDryRunPaymentRequired.PayTransaction(wallet)wraps fetch with x402 payment. The resolved fetch is derived fromclient.fetchviaresolveFetchForTransaction(mode, client.fetch). -
Don't export internal constants — things like the User-Agent string are internal to the SDK. Tests should assert behavior (e.g.,
toMatch("@use-agently/sdk:")) not exact values. -
SDK tests SDK, CLI tests CLI — SDK tests exercise SDK functions directly (e.g.,
sendMessage,createA2AClient). CLI tests exercise the CLI surface viacli.parseAsync. Never test SDK-level concerns (payment flows, client creation) in CLI test files. -
Inline option types — prefer inline types for simple option bags:
options?: { mode?: TransactionMode }rather than separate named interfaces, unless the type is reused across multiple functions.
The wallet system is designed for extensibility. Wallet interface requires type, address, and getX402Schemes(). New wallet types are added by creating an implementation and registering it in the loadWallet() factory switch. Config stores { wallet: { type: "evm-private-key", ...fields } }.
- commander — CLI command framework
- viem — EVM wallet generation, account management, on-chain reads
- @x402/fetch + @x402/evm — Wraps fetch to auto-handle 402 Payment Required via x402 protocol
- @a2a-js/sdk — A2A protocol client (agent card resolution, JSON-RPC/REST transport)
- Runtime/Package Manager: Bun (>= 1.3.0)
- Build: Turborepo orchestrates tasks; Bun compiler creates standalone executables
- Formatting: Prettier (printWidth: 120), enforced via pre-commit hook (husky + lint-staged)
- CI: GitHub Actions runs build, test, and format check on PRs
npm publishing is triggered by GitHub releases. Version is extracted from git tags (v1.0.0 format). Tags containing .beta or similar publish with next dist-tag.
use-agently is built for AI agents as first-class users. Every new feature should be designed with this in mind:
- Non-interactive by default — all commands must work without a TTY; no interactive prompts unless an explicit
--interactiveflag is provided - Self-describing —
use-agently --helpanduse-agently <command> --helpare the authoritative reference;use-agently doctoris the go-to health check - Machine-readable output — prefer structured output (exit codes, predictable stdout) so agents can parse results without screen-scraping
- When in doubt, ask: "Would an AI agent love to use this?"
This section is the authoritative design plan for the use-agently CLI command surface. All new commands must follow these conventions.
Commands are grouped into four categories. New commands must be placed in one of these categories:
| Category | Purpose |
|---|---|
| Lifecycle & Health | Setup, diagnostics, identity, and wallet balance |
| Discovery | Browsing the Agently marketplace for agents, tools, and skills |
| Operations | Configuration, wallet management, and CLI updates |
| Protocols | Direct protocol invocations (A2A, MCP, ERC-8004, HTTP) |
Commands that have subcommands use a space separator: <command> <subcommand>.
use-agently a2a send --uri "uri"
use-agently a2a card --uri "uri"
use-agently mcp tools --uri "uri"
use-agently mcp call --tool "tool" --args "args" --uri "uri"
use-agently # Default: print available commands (same as --help)
use-agently help # Print available commands
use-agently doctor # Run environment and configuration health checks
use-agently whoami # Show current wallet type and address
use-agently balance # Show on-chain wallet balanceuse-agently search # List all agents on the marketplace (no query = browse all)
use-agently search [query] # Search the marketplace
use-agently search [query] --protocol a2a,mcp,web # Filter by protocol(s)use-agently init # Initialize a wallet and config
use-agently update # Update the CLI to the latest versionuse-agently erc-8004 --uri "uri" # Resolve an ERC-8004 agent URI
use-agently a2a send --uri "uri/url" -m "message" # Send a message via A2A protocol
use-agently a2a card --uri "uri/url" # Fetch and display the A2A agent card
use-agently mcp tools --uri "uri/url" # List tools on an MCP server
use-agently mcp call --tool "tool" --args "args" --uri "uri/url" # Call a tool on an MCP server
use-agently web get <url> # HTTP GET with x402 payment support
use-agently web post <url> # HTTP POST with x402 payment support
use-agently web put <url> # HTTP PUT with x402 payment support
use-agently web patch <url> # HTTP PATCH with x402 payment support
use-agently web delete <url> # HTTP DELETE with x402 payment support-
No TTY assumed — every command must work in a non-interactive, non-TTY environment (scripts, CI, agent pipelines). Never prompt for input.
-
2-attempt error recovery — if a command fails due to bad input, the error message must include enough information (expected type, shape, example) that the caller can succeed on the second attempt. A third attempt required is a design failure.
Example of a good error:
Error: <agent-uri> must be a URL (e.g. https://use-agently.com/echo-agent/) or a short name resolvable on Agently (e.g. echo-agent). -
Self-describing —
use-agently,use-agently -h,use-agently help, anduse-agently --helpmust all print the same top-level help output listing available commands by category. -
Include examples in help — every command's
--helpoutput should include at least one concrete usage example so agents can use it without guessing argument shapes. -
Structured output — use exit codes to signal success/failure. For
--output json, emit valid JSON to stdout so agents can parse results. -
Space subcommand convention — use
command subcommand(space separator) for protocol variants. Do not use colon separators.
When CLI commands, features, or behavior change, always update these files to keep them in sync:
README.md— Project README (install, quick start, command reference, how it works)CLAUDE.md/AGENTS.md— Development guidance and CLI design specification (keep in sync)skills/use-agently/SKILL.md— General skill reference for AI agents; keep it focused on discovery (doctor,--help) rather than enumerating every flag