From a10aa4c6058ae93be8e5febf0c8d0eb44926ec12 Mon Sep 17 00:00:00 2001 From: vvillait88 Date: Sat, 3 Oct 2026 15:28:48 -0700 Subject: [PATCH 1/2] Remove the unlock guidance: agent-guide, README and the integration notes describe the passphrase as env-only --- README.md | 10 ++++------ package.json | 2 +- src/commands/agent-guide.ts | 9 ++++----- tests/integration/README.md | 6 ++---- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d42e560..cd0ddde 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ agentscore-pay pay POST https://merchant.example/api --chain tempo -d '...' --ma ## Agents (scripting) -For LLM tool-loop agents, run `agentscore-pay agent-guide` (add `--json` for parseable output). It prints the structured how-to: golden path (init → discover → balance → check → dry-run → pay), testnet path, funding, auxiliary commands (`unlock`, `limits`, `whoami`, `history`), pitfalls, and exit-code branching. The same notes also surface in `agentscore-pay --help` for `check` and `pay`. +For LLM tool-loop agents, run `agentscore-pay agent-guide` (add `--json` for parseable output). It prints the structured how-to: golden path (init → discover → balance → check → dry-run → pay), testnet path, funding, auxiliary commands (`limits`, `whoami`, `history`), pitfalls, and exit-code branching. The same notes also surface in `agentscore-pay --help` for `check` and `pay`. ### Output formats @@ -281,7 +281,6 @@ Each row below is a subcommand of `agentscore-pay`, invoke as `agentscore-pay \| unset \| path` | Read/write `~/.agentscore/config.json` (e.g. `config set preferred_chains tempo,base`) | | `discover [--search q] [--chain c] [--max-price N] [--limit N] [--protocol x402\|mpp\|both]` | List paid services from the x402 Bazaar (Coinbase) and MPP services directory (Tempo). Both queried in parallel by default. | -| `unlock [--for 15m] \| --clear` | Cache passphrase to `~/.agentscore/.unlock` (mode 0600) for a bounded TTL, skip per-call prompts during a session | | `revoke --chain c --token --spender [--network n]` | Send `approve(spender, 0)` on EVM (base/tempo). Requires native gas. | ### Identity commands @@ -419,15 +418,14 @@ AGENTSCORE_PAY_HOME=~/.agentscore-test agentscore-pay pay --network testnet ... ## Unlocking the keystore -Three ways to satisfy the passphrase prompt, in precedence order: +Two ways to satisfy the passphrase prompt, in precedence order: | Mechanism | Best for | Persistence | |---|---|---| | `AGENTSCORE_PAY_PASSPHRASE=` env var | Containers, CI, serverless, daemons, any non-interactive agent | Lifetime of the process / shell session | -| `agentscore-pay unlock --for 1h` | Interactive shell session where you'll run multiple commands | Cached in `~/.agentscore/.unlock` (mode `0600`) until TTL expires (max 8h); `unlock --clear` wipes early | | Per-call interactive prompt | First-time setup, one-off commands | None, never written | -**Env var wins** when set: it produces no on-disk artifact and is the right primitive for every agent context (CI secrets, container env, K8s secrets, Lambda config, MCP host config). When env vars aren't controllable (e.g. an interactive Claude Code session running locally), `unlock` is the fallback. +**Env var wins** when set: it produces no on-disk artifact and is the right primitive for every agent context (CI secrets, container env, K8s secrets, Lambda config, MCP host config). There is no on-disk passphrase cache: it would hold the passphrase in cleartext beside the keystores it unlocks. **For agent authors**: prefer env var. Read it from your secret store at agent startup; don't bake it into the agent's prompt or memory. Pay's `agent-guide` command (`agentscore-pay agent-guide`) explains the precedence in its own structured output. @@ -481,7 +479,7 @@ agentscore-pay fund-estimate https://agents.example.com/purchase \ For **interactive humans**: any 8+ char passphrase you'll remember is fine, the scrypt-256-GCM combination is robust against offline brute force at typical human-passphrase entropy levels. -For **autonomous agents**: the passphrase usually lives in `AGENTSCORE_PAY_PASSPHRASE` (env var) or `~/.agentscore/.unlock` (file). Both are filesystem/process-readable to anyone with shell access as that user, so the passphrase isn't really a separate trust boundary, it's primarily protecting the keystore against *theft of the on-disk file alone*. A long, random passphrase makes the file useless if exfiltrated: +For **autonomous agents**: the passphrase usually lives in `AGENTSCORE_PAY_PASSPHRASE` (env var), which is process-readable to anyone with shell access as that user, so the passphrase isn't really a separate trust boundary, it's primarily protecting the keystore against *theft of the on-disk file alone*. A long, random passphrase makes the file useless if exfiltrated: ```sh # generate a 32-byte (256-bit) random passphrase diff --git a/package.json b/package.json index 3cd9a90..555c17e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@agent-score/pay", - "version": "0.6.2", + "version": "0.6.3", "description": "CLI wallet for one-shell-command agent payments across x402 (Base) and MPP (Tempo, Solana)", "type": "module", "main": "./dist/index.js", diff --git a/src/commands/agent-guide.ts b/src/commands/agent-guide.ts index 75cb722..38f707a 100644 --- a/src/commands/agent-guide.ts +++ b/src/commands/agent-guide.ts @@ -196,12 +196,11 @@ const GUIDE: AgentGuide = { ], }, { - step: 'Skip the passphrase prompt with `unlock` (when env var is not an option)', - why: 'Each pay/wallet call decrypts the keystore and normally prompts for the passphrase. Agents can either set AGENTSCORE_PAY_PASSPHRASE in the env, or — when env vars are not controllable — run `unlock --for ` once to cache the passphrase to ~/.agentscore/.unlock for a bounded duration (max 8h).', - command_example: 'agentscore-pay unlock --for 1h', + step: 'Supply the passphrase through AGENTSCORE_PAY_PASSPHRASE', + why: 'Each pay/wallet call decrypts the keystore and otherwise prompts for the passphrase, which an agent cannot answer. Set AGENTSCORE_PAY_PASSPHRASE in the environment from your secret store at startup: it leaves no on-disk artifact. There is no passphrase cache: it would hold the passphrase in cleartext beside the keystores it unlocks.', + command_example: 'AGENTSCORE_PAY_PASSPHRASE=... agentscore-pay pay POST -d \'{}\' --max-spend 5', notes: [ - 'Use `agentscore-pay unlock --clear` when finished to wipe the cache early.', - 'AGENTSCORE_PAY_PASSPHRASE in env always wins over the cache and produces no on-disk artifact — prefer it in CI or any ephemeral execution context.', + 'Read it from a secret store (CI secrets, container env, MCP host config); never put it in the agent prompt or memory.', ], }, { diff --git a/tests/integration/README.md b/tests/integration/README.md index f05b81c..14134d2 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -20,10 +20,8 @@ can run them on a best-effort basis. - Base Sepolia USDC: https://faucet.circle.com/ - Solana Devnet USDC: https://faucet.circle.com/ -- Tempo testnet USDC.e: contact Tempo team +- Tempo testnet: `agentscore-pay fund --chain tempo --network testnet` mints test stablecoins directly ## What's covered -- `tests/integration/balance.test.ts` — reads USDC balance on Base Sepolia and Solana Devnet -- (future) `tests/integration/pay.test.ts` — completes a real 402 payment round-trip - against an x402 base demo endpoint and an MPP `solana/charge` demo endpoint on Solana Devnet +- `tests/integration/balance.test.ts` reads USDC balance on Base Sepolia and Solana Devnet From 38e1994bb788377ce1874736f05a6b56430079f8 Mon Sep 17 00:00:00 2001 From: vvillait88 Date: Sat, 3 Oct 2026 15:30:10 -0700 Subject: [PATCH 2/2] No em-dashes in user-facing strings or docs --- .claude/CLAUDE.md | 30 ++++++------ CONTRIBUTING.md | 2 +- SECURITY.md | 4 +- src/aip/agent-key.ts | 14 +++--- src/aip/http-signature.ts | 2 +- src/aip/mint.ts | 6 +-- src/chains/solana.ts | 2 +- src/chains/tempo.ts | 2 +- src/cli.ts | 62 ++++++++++++------------ src/commands/agent-guide.ts | 96 ++++++++++++++++++------------------- src/commands/check.ts | 2 +- src/commands/fund.ts | 2 +- src/commands/identity.ts | 4 +- src/commands/passport.ts | 4 +- src/commands/pay.ts | 32 ++++++------- src/commands/qr.ts | 2 +- src/commands/send.ts | 2 +- src/commands/wallet.ts | 2 +- src/faucets.ts | 2 +- src/headers.ts | 2 +- src/onramp.ts | 4 +- src/passport/attach.ts | 14 +++--- src/passport/auth.ts | 10 ++-- src/passport/bootstrap.ts | 4 +- src/rail-hints.ts | 10 ++-- src/selection.ts | 2 +- src/url-security.ts | 12 ++--- 27 files changed, 165 insertions(+), 165 deletions(-) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index ef74712..2512fa3 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -4,7 +4,7 @@ CLI wallet for one-shell-command agent payments across x402 (Base) and MPP (Temp ## Purpose -One shell command for shell-tool LLM agents to pay any 402/MPP merchant. POST body preserved through the round-trip; agent never sees a private key on the wire. Works with any 402-gated merchant — AgentScore-gated or not. +One shell command for shell-tool LLM agents to pay any 402/MPP merchant. POST body preserved through the round-trip; agent never sees a private key on the wire. Works with any 402-gated merchant, AgentScore-gated or not. ## Architecture @@ -24,16 +24,16 @@ Single-package TypeScript CLI published to npm. Runnable via `npx @agent-score/p | `src/commands/wallet.ts` | `wallet create/import/address/list/remove/export/show-mnemonic` | | `src/commands/balance.ts` | `balance` across chains | | `src/commands/qr.ts` | `qr` with optional amount | -| `src/commands/fund.ts` | `fund` — receive QR + balance polling (default); `--via stripe-onramp` mints a Stripe Crypto Onramp session (base/solana mainnet only); `--quote-only` returns the Stripe price preview without minting. Tempo testnet uses programmatic mint via tempo_fundAddress. | -| `src/onramp.ts` | API client for the AgentScore Crypto Onramp endpoints (POST /v1/onramp/sessions + POST /v1/onramp/quotes). Sends X-Client-Id + the stored passport operator_token in the body — no merchant API key required. | -| `src/commands/pay.ts` | `pay ` — routes to `@x402/fetch` (base) or `mppx/client` (tempo, solana via `@solana/mpp/client`). `--identity auto\|operator\|wallet` selects the identity to present (`operator` uses the stored passport operator_token; `wallet` uses the wallet address; `auto` is the default passport/wallet path). | +| `src/commands/fund.ts` | `fund`, receive QR + balance polling (default); `--via stripe-onramp` mints a Stripe Crypto Onramp session (base/solana mainnet only); `--quote-only` returns the Stripe price preview without minting. Tempo testnet uses programmatic mint via tempo_fundAddress. | +| `src/onramp.ts` | API client for the AgentScore Crypto Onramp endpoints (POST /v1/onramp/sessions + POST /v1/onramp/quotes). Sends X-Client-Id + the stored passport operator_token in the body, no merchant API key required. | +| `src/commands/pay.ts` | `pay `, routes to `@x402/fetch` (base) or `mppx/client` (tempo, solana via `@solana/mpp/client`). `--identity auto\|operator\|wallet` selects the identity to present (`operator` uses the stored passport operator_token; `wallet` uses the wallet address; `auto` is the default passport/wallet path). | | `src/commands/identity.ts` | `assess`, `sessions create/get`, `credentials create/list/revoke`, `associate-wallet` (wraps `@agent-score/sdk`) | -| `src/commands/send.ts` | `send --chain --to --amount [--asset usdc\|native]` — raw transfer (no merchant / 402). Default `--asset usdc` (ERC20 transfer on EVM / SPL transferChecked + idempotent ATA on Solana). `--asset native` sends ETH/TEMPO/SOL via viem sendTransaction (EVM) or `getTransferSolInstruction` (Solana). EVM transfers confirm the on-chain receipt (`src/chains/evm-confirm.ts`) and surface a reverted tx as `transfer_reverted` instead of returning a hash for a tx that never settled. Note Tempo pays the network fee in the stablecoin itself, so a full-balance USDC send reverts (no headroom for the fee); leave a little `--amount` headroom. Works on mainnet + testnet (`--network testnet`). | -| `src/commands/passport.ts` | `passport login/status/logout` — AgentScore Passport (buyer-side identity); stores opc_ at `~/.agentscore/passport.json`, auto-attached on `agentscore-pay ` settle leg | +| `src/commands/send.ts` | `send --chain --to --amount [--asset usdc\|native]`, raw transfer (no merchant / 402). Default `--asset usdc` (ERC20 transfer on EVM / SPL transferChecked + idempotent ATA on Solana). `--asset native` sends ETH/TEMPO/SOL via viem sendTransaction (EVM) or `getTransferSolInstruction` (Solana). EVM transfers confirm the on-chain receipt (`src/chains/evm-confirm.ts`) and surface a reverted tx as `transfer_reverted` instead of returning a hash for a tx that never settled. Note Tempo pays the network fee in the stablecoin itself, so a full-balance USDC send reverts (no headroom for the fee); leave a little `--amount` headroom. Works on mainnet + testnet (`--network testnet`). | +| `src/commands/passport.ts` | `passport login/status/logout`, AgentScore Passport (buyer-side identity); stores opc_ at `~/.agentscore/passport.json`, auto-attached on `agentscore-pay ` settle leg | | `src/passport/{auth,storage,attach}.ts` | Passport login flow (mint+poll), conf-style local keystore, X-Operator-Token attach decision tree | | `src/progress.ts` | stderr-only structured progress events (stdout belongs to incur) | | `tests/` | Vitest unit tests | -| `dist/` | tsup output — ESM only with shebang banner | +| `dist/` | tsup output, ESM only with shebang banner | ## Chain-to-protocol routing @@ -45,12 +45,12 @@ Both paths preserve POST bodies through the 402 round-trip. The CLI's passphrase ## Tooling -- **Bun** — package manager. Use `bun install`, `bun run