| name | create-use-agently-cli |
| description | Create a new CLI command for the use-agently CLI. Use this skill when implementing a new command, subcommand, or protocol handler in the packages/use-agently package following the CLI design specification. |
| license | MIT |
| metadata | {"package":"use-agently","runtime":"bun","framework":"commander"} |
Create a use-agently CLI Command
When to Use
Use this skill when:
- Adding a new top-level command (e.g.
marketplace, wallets, update)
- Adding a subcommand using the colon-separator pattern (e.g.
a2a:card, marketplace:agents)
- Adding a shorthand alias for an existing command (e.g.
m → marketplace)
- Implementing a new protocol handler (A2A, MCP, ERC-8004, HTTP)
Command Taxonomy
Every command belongs to one of four categories. Place new commands in the correct category:
| Category | Purpose | Examples |
|---|
| Lifecycle & Health | Setup, diagnostics, identity, balance | doctor, whoami, balance, init |
| Discovery | Browse the Agently marketplace | search, view |
| Operations | Config, wallets, updates | config, wallets, update |
| Protocols | Protocol invocations | a2a, a2a:card, mcp, erc-8004, web:get |
Full Command Reference
use-agently
use-agently help
use-agently doctor
use-agently whoami
use-agently balance
use-agently search
use-agently search -q "query"
use-agently search --protocol a2a
use-agently view --uri <uri>
use-agently init
use-agently config
use-agently update
use-agently wallets
use-agently erc-8004 "uri"
use-agently a2a "uri/url"
use-agently a2a:card "uri/url"
use-agently mcp "uri/url"
use-agently web "url"
use-agently web:get "url"
use-agently web:put "url"
Instructions
1. Create the command file
Each command lives in its own file at packages/use-agently/src/commands/<name>.ts.
import { Command } from "commander";
import { loadConfig } from "../config.js";
export const myCommand = new Command("my-command")
.description("One-line description of what this command does.")
.argument("<uri>", "The agent URI or URL to target (e.g. echo-agent or https://use-agently.com/echo-agent/)")
.option("--rpc <url>", "Custom RPC URL")
.option("-o, --output <format>", "Output format (text, json)", "text")
.addHelpText(
"after",
`
Examples:
$ use-agently my-command echo-agent
$ use-agently my-command https://use-agently.com/echo-agent/ --output json
`,
)
.action(async (uri, options) => {
const config = await loadConfig();
});
2. Register the command in cli.ts
Open packages/use-agently/src/cli.ts and add the import and addCommand call:
import { myCommand } from "./commands/my-command.js";
cli.addCommand(myCommand);
3. Subcommands (colon-separator pattern)
Subcommands use the colon separator and are registered as separate Commander.js commands named "parent:sub":
import { Command } from "commander";
export const marketplaceAgentsCommand = new Command("marketplace:agents")
.alias("m:agents")
.description("Search agents on the Agently marketplace.")
.argument("[query]", 'Search query (e.g. "code assistant")')
.addHelpText(
"after",
`
Examples:
$ use-agently marketplace:agents "code assistant"
$ use-agently m:agents "translator"
`,
)
.action(async (query, options) => {
});
Register both the parent and subcommand:
cli.addCommand(marketplaceCommand);
cli.addCommand(marketplaceAgentsCommand);
4. Shorthand aliases
Add .alias() to the command definition for shorthands:
export const marketplaceCommand = new Command("marketplace").alias("m").description("Browse the Agently marketplace.");
5. Write tests
Create packages/use-agently/src/commands/<name>.test.ts. Follow the same pattern as existing tests:
import { describe, it, expect } from "bun:test";
import { myCommand } from "./my-command.js";
describe("my-command", () => {
it("should ...", async () => {
});
});
Run the tests for the package:
bun run test --filter use-agently
Design Rules (Required for Every Command)
-
No TTY assumed — never use interactive prompts. Every command must work in scripts, CI, and agent pipelines without a terminal.
-
2-attempt error recovery — error messages must include the expected type, shape, and an example so the caller can succeed on the second attempt. A third attempt required is a design failure.
Good error message:
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, -h, help, and --help all print the same top-level help listing commands by category.
-
Examples in --help — use .addHelpText("after", ...) to include at least one concrete usage example for every command.
-
Structured output — use exit codes to signal success/failure. Support --output json emitting valid JSON to stdout.
-
Colon subcommand naming — register colon subcommands as "command:subcommand" in Commander.js. Never nest subcommands using .command() chaining.
Common Patterns
Loading config and wallet
import { loadConfig } from "../config.js";
import { loadWallet } from "../wallets/wallet.js";
const config = await loadConfig();
const wallet = await loadWallet(config);
RPC URL fallback
.option("--rpc <url>", "Custom RPC URL")
.action(async (options) => {
const config = await loadConfig();
const rpcUrl = options.rpc ?? config.rpcUrl;
});
JSON output
.action(async (options) => {
const result = { address: wallet.address };
if (options.output === "json") {
console.log(JSON.stringify(result));
} else {
console.log(`Address: ${result.address}`);
}
});
Error with recovery hint
if (!isValidUri(uri)) {
console.error(
`Error: <uri> must be a URL (e.g. https://use-agently.com/echo-agent/) or a short agent name (e.g. echo-agent).`,
);
process.exit(1);
}
File Layout
packages/use-agently/
src/
cli.ts # Register all commands here
commands/
<name>.ts # One file per command
<name>.test.ts # Matching test file
config.ts # Config load/save
client.ts # x402 fetch + A2A client factory
wallets/
wallet.ts # Wallet interface + loadWallet()
evm-private-key.ts # EVM private key implementation
Common Edge Cases
- Colon in command name — Commander.js accepts
"a2a:card" as a command name. Do not use nested .command() chaining for subcommands.
- Missing wallet — catch errors from
loadWallet() and print a recovery hint: "Run 'use-agently init' to create a wallet.".
- No config file —
loadConfig() returns defaults when no config file exists; never throw on missing config.
- Non-zero exit on failure — always call
process.exit(1) on errors so agent pipelines can detect failures.