scaffold-agent
v0.1.12
Published
Interactive CLI to scaffold monorepo projects for onchain AI agents
Maintainers
Readme
scaffold-agent
Interactive CLI to scaffold monorepo projects for onchain AI agents.
AI / agent tools: see AGENTS.md (shared instructions). Claude Code uses CLAUDE.md (imports AGENTS.md). Cursor skill: .cursor/skills/scaffold-agent/.
Prerequisites
- Node.js and npm — for
npx scaffold-agent@latestand the generated workspace. - just — installed separately (not an npm dependency). Generated repos use a root
justfileforjust chain,just deploy,just start, etc. See installation (e.g.brew install just, or a prebuilt binary).
Without just, you can still run the underlying npm run / npx scripts from the generated README.md, but the docs and defaults assume just is on your PATH.
Basic flow
Typical path when you picked Foundry or Hardhat and want a local node on http://127.0.0.1:8545:
Scaffold the monorepo
npx scaffold-agent@latest # or create `my-agent/` directly (skips the project name prompt): npx scaffold-agent@latest my-agentEnter the project (replace
my-agentwith the folder name you chose)cd my-agentRun the local chain — use a second terminal; the node must be up before
just fund/just deploy.just chainFund the deployer (and optional agent address from
.env)just fundDeploy contracts and refresh generated ABI types
just deployStart the app
just startOpen the UI — Next.js / Vite dev server is usually http://localhost:3000.
If you skipped a chain in the wizard, omit steps 3–5 and point scaffold.config.ts (and RPC env vars) at the network you use, then just deploy / just start as your project README describes. If npm install didn’t run during scaffold, run it once at the repo root before just start. Python (A2A) projects follow the same just commands where applicable; see the generated README.
Usage
Published on npm as scaffold-agent. The CLI binary is also scaffold-agent.
npx scaffold-agent@latest
npx scaffold-agent@latest my-agent # creates ./my-agent (skips project name prompt)(@latest is the default dist-tag — you can omit it.)
CLI flags: Run scaffold-agent --help / -h for the full list (every wizard step has a flag; unknown options error). --version / -V. Optional argument: project-name — directory to create (same rules as the interactive prompt: letters, numbers, -, _), or use --project <name>.
Non-interactive / automation: --non-interactive / -y runs with no prompts. Set --env-password when --secrets is oneclaw or encrypted (min 6 characters). Omitted choices use documented defaults in --help (e.g. Foundry + Next.js + 1Claw Shroud token billing). Use --skip-npm-install and --skip-auto-fund to match the env vars below.
After the project is written, the CLI runs npm install at the monorepo root (workspaces install all packages). Set SCAFFOLD_SKIP_NPM_INSTALL=1 or --skip-npm-install to skip (e.g. offline or you use another package manager).
The wizard walks through:
- Project name — directory to create (skipped if you pass it as the first argument, e.g.
scaffold-agent my-agent) - Secrets management — 1Claw (HSM-backed vault), encrypted secrets file, or plain
.env - Agent identity — generate an Ethereum wallet for your agent
- Ampersend SDK — optional; adds
@ampersend_ai/ampersend-sdk+AMPERSEND.md(docs.ampersend.ai, GitHub) - LLM Provider — 1Claw, Gemini, OpenAI, or Anthropic
- Chain framework — Foundry, Hardhat, or none
- App framework — Next.js, Vite, or Python (Google A2A)
At the end it displays QR codes for the Deployer and Agent addresses. If you picked a chain, the CLI also runs scripts/fund-deployer.mjs (same as just fund). Order matters: auto-fund only succeeds if a node is already listening on RPC_URL (default http://127.0.0.1:8545). Most people run just chain first, then scaffold in another terminal—or run just fund after cd into the project. Set SCAFFOLD_SKIP_AUTO_FUND=1 or --skip-auto-fund to skip. just generate tries the same auto-fund when you create a deployer.
What gets created
my-agent/
├── justfile # just chain / deploy / start / generate
├── scripts/
│ ├── secrets-crypto.mjs # encrypt/decrypt .env.secrets.encrypted
│ ├── with-secrets.mjs # prompt password, run deploy/start with env
│ ├── secret-add.mjs # just env / enc / vault / reown
│ ├── deploy-foundry.mjs # or deploy-hardhat.mjs
│ ├── generate-abi-types.mjs # auto-gen TypeScript from contract ABIs
│ ├── generate-deployer.mjs # create deployer wallet if missing (+ auto-fund if RPC up)
│ └── fund-deployer.mjs # fund DEPLOYER + optional AGENT from local acct #0
├── packages/
│ ├── foundry/ # or hardhat/ (Solidity contracts)
│ └── nextjs/ # or vite/ or python/ (frontend / agent)
│ ├── app/
│ │ ├── page.tsx # shadcn chat UI
│ │ ├── identity/page.tsx # ERC-8004 / Agent0 identity + register
│ │ ├── debug/page.tsx # deployed contracts (Next only)
│ │ └── api/
│ │ ├── chat/route.ts # LLM streaming API
│ │ └── agent0/lookup/route.ts # server-side registry search
│ ├── components/ui/ # shadcn Button, Input
│ ├── contracts/ # auto-generated ABI types
│ └── ...
├── .env # non-sensitive config (gitignored)
├── .env.secrets.encrypted # AES-256-GCM encrypted API keys & private keys (gitignored)
├── .gitignore
├── package.json # monorepo root
└── README.mdCommands (via just)
| Command | Description |
| ----------------------- | ---------------------------------------------------------------------------------------- |
| just chain | Start local blockchain (Foundry/Hardhat) |
| just fund | Fund DEPLOYER_ADDRESS + optional AGENT_ADDRESS (100 ETH each from account #0) |
| just deploy | Deploy contracts & auto-gen ABIs (prompts for secrets password if encrypted) |
| just start | Start frontend or agent (same) |
| just accounts | Show QR codes for DEPLOYER_ADDRESS + agent address (repo-root .env) |
| just balances | Native balance on all chains in network-definitions (deployer + agent; rpcOverrides) |
| just generate | Generate deployer wallet (password prompt if encrypted) |
| just env KEY VALUE | Upsert repo-root .env (e.g. NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID) |
| just enc KEY VALUE | Update .env.secrets.encrypted (password prompt) |
| just vault PATH VALUE | Store a secret in the 1Claw vault (wraps with-secrets) |
| just reown PROJECT_ID | WalletConnect Cloud id → .env (Next: NEXT_PUBLIC_…, Vite: VITE_…) |
ABI type generation
just deploy automatically parses compiled contract artifacts and generates
deployedContracts.ts — the same pattern used by
Scaffold-ETH 2. This gives you
type-safe contract addresses and ABIs in your frontend code.
Next.js apps also get /debug (bug icon in the header): read-only view of deployed addresses and ABI, similar to Scaffold-ETH 2 Debug Contracts.
Route loading & frontend performance
Next.js: app/loading.tsx plus per-route loading.tsx under /identity, /balances, /debug, /ens show a header + card skeleton as soon as you navigate, while the route’s JavaScript loads (especially noticeable in dev). npm run dev uses next dev --turbo. next.config.js sets experimental.optimizePackageImports: ["lucide-react"] so icon imports tree-shake instead of pulling the whole package. Wagmi’s React Query client uses 30s staleTime to reduce background refetching.
Vite: /identity, /ens, and /balances are loaded with React.lazy and a shared PageLoading skeleton so those chunks download only when you open those routes (home Chat stays eager).
UX / a11y (both stacks): Skip to main content link (keyboard), visible :focus-visible rings on interactive controls, chat role landmarks and context-aware error hints (Gemini quota vs 1Claw vs generic env), local faucet uses an in-app toast instead of window.alert, Balances explains when no ERC-20 tokens are configured for the chain.
1Claw IDs programmatically
With your user ONECLAW_API_KEY you can call the same REST API the CLI uses:
POST /v1/auth/api-key-token→ Bearer tokenGET /v1/vaults→ vault UUIDs (ONECLAW_VAULT_ID)GET /v1/agents→ agent UUIDs (ONECLAW_AGENT_ID)
Scaffolded 1Claw projects include just list-1claw (runs scripts/list-1claw-ids.mjs under with-secrets when needed) and just sync-1claw-env to write the first listed vault + agent UUIDs into repo-root .env.
Agent API keys (ONECLAW_AGENT_API_KEY / ocv_…) are not returned by list endpoints — only when you create an agent (POST /v1/agents, as in setupOneClaw) or rotate via @1claw/sdk client.agents.rotateKey(id).
1Claw integration
When you choose 1Claw (1claw.xyz), the CLI:
- Authenticates with your
ONECLAW_API_KEY - Creates a vault for the project and writes
ONECLAW_VAULT_IDinto.envwhen you enter the API key during setup and vault creation succeeds. If you skip the key (“add later”) or setup fails,ONECLAW_VAULT_IDstays blank — then runjust sync-1claw-env(with your key loaded) orjust list-1clawand paste IDs (or copy from the dashboard). - Stores the deployer private key at
private-keys/deployerin the vault (not on disk) - If agent identity is generated, stores it at
private-keys/agentand registers the agent - If you pick Gemini, OpenAI, or Anthropic as the LLM, the CLI can store that
provider’s API key in the vault as
llm-api-key(optional — you can add it later in the dashboard) - If you pick 1Claw as the LLM, chat uses Shroud. During setup the CLI registers a 1Claw agent (unless you already get one from generating an on-chain agent wallet) and writes
ONECLAW_AGENT_ID+ONECLAW_AGENT_API_KEYto your env when vault creation succeeds — you don’t need to paste them manually. The Shroud agent UUID is not your EthereumAGENT_ADDRESS. With vault BYOK, setONECLAW_VAULT_IDtoo or Shroud’svault://…header is invalid. You choose an upstream provider (OpenAI, Google/Gemini, Anthropic, …); Shroud proxies to it. The CLI asks how upstream LLM usage is paid:- LLM Token Billing on 1claw.xyz — set
SHROUD_BILLING_MODE=token_billing; no provider key. - Your own API key — set
SHROUD_BILLING_MODE=provider_api_key. With 1Claw secrets, the key can live in the vault atapi-keys/openai,api-keys/gemini, etc. (the chat route sendsvault://…asX-Shroud-Api-Key). Without 1Claw vault, useSHROUD_PROVIDER_API_KEYin.env.
- LLM Token Billing on 1claw.xyz — set
LLM providers
| Choice | Auth / keys | Notes |
| ------------------------------------------------------ | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1Claw (LLM) | .env: agent + SHROUD_LLM_PROVIDER, SHROUD_BILLING_MODE | Shroud; optional SHROUD_BASE_URL, SHROUD_DEFAULT_MODEL. If BYOK + vault: SHROUD_PROVIDER_VAULT_PATH / api-keys/…; if BYOK + no vault: SHROUD_PROVIDER_API_KEY |
| Gemini / OpenAI / Anthropic + 1Claw secrets | Vault: llm-api-key | Fetched by the app’s chat route (not Shroud path) |
| Gemini / OpenAI / Anthropic + no 1Claw secrets | .env provider env vars | CLI can prompt to fill .env |
All chat routes use the Vercel AI SDK for streaming. Shroud + Google/Gemini upstream: if SHROUD_BILLING_MODE=token_billing, chat uses Shroud for Gemini (no Google API key in your app) so 1Claw token billing can apply — enable billing for the agent on 1claw.xyz. If a key is present (SHROUD_PROVIDER_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, or vault api-keys/google with ONECLAW_VAULT_ID), the route prefers the direct Google Generative AI API (better compatibility than some Shroud↔Gemini paths). With SHROUD_BILLING_MODE=provider_api_key and no Google key resolvable, the route returns 503 (BYOK required for that mode). Direct Google API default is gemini-2.5-flash (GOOGLE_GENERATIVE_AI_MODEL). Shroud path default for Gemini is gemini-2.0-flash (SHROUD_DEFAULT_MODEL) — token billing uses Stripe’s AI gateway, and unsupported model ids can return 404 with Stripe doc links in the error body. The generated chat route sends X-Shroud-Model (per Shroud docs) as well as the JSON model field so the gateway picks the right id. See Gemini rate limits for BYOK. Set SHROUD_DISABLE_GEMINI_DIRECT=1 to always use Shroud POST …/chat/completions even when a Google key exists. Other Shroud upstreams use minimal non-streaming Shroud + createDataStreamResponse / formatDataStreamPart (or pipeDataStreamToResponse on Vite). Do not send Authorization: Bearer … to Shroud — use X-Shroud-Agent-Key. Optional: SHROUD_STREAM_CHUNK_CHARS (default 40) for non-Gemini Shroud chunking.
Development
npm install
npm run build # compile with tsup
npm run dev # watch mode
npm start # run locallyPublishing to npm
Package name: scaffold-agent (unscoped). Listing: npmjs.com/package/scaffold-agent.
Manual publish — any npm user with rights to the scaffold-agent package name:
npm login
npm run build
npm publish --tag latestOptional: npm publish --provenance --tag latest if you use npm provenance from your environment.
Acknowledgements
This project builds on ideas and tooling from the Ethereum builder community:
- Scaffold-ETH 2 / scaffold-eth/scaffold-eth-2 — monorepo patterns, RainbowKit/wagmi/viem stack, and UX inspiration for onchain apps.
- BuidlGuidl — education and builder tooling for the ecosystem.
- Burner wallet — local dev wallet UX via burner-connector (Scaffold-ETH / BuidlGuidl–style), used when the generated app targets localhost.
License
MIT — see LICENSE in the repo.
