Build with the Claude Code plugin

One session doing everything is the slow way to build on Pithy. It designs the data model, writes the Worker, builds the client and reads build logs, on one model, in one context. The pithy plugin for Claude Code splits that work across a team: a server, a web client, a mobile client and a runner, each on the model you choose. When it finds something the kit cannot do, it files the issue.

Install it

You need the pithy CLI first, from Install. Then, inside Claude Code:

/plugin marketplace add pithy-sh/pithy#release
/plugin install pithy@pithy

#release is deliberate. The marketplace is the kit’s own repository, and its default branch runs ahead of npm between releases. A plugin read from it would name commands your installed pithy does not have yet. The release branch moves only when the kit is published, so the plugin you install names exactly the commands your CLI has.

Install from one source. Either pithy@pithy, from this marketplace, or pithy@synced, from Anthropic’s plugin directory. Not both: each loads its own copy, so every agent and skill would appear twice.

Building a game? pithy-games adds game design, a Unity client and playtests with simulated players, and installs pithy with it. Build a game with the Claude Code plugin covers it.

/plugin install pithy-games@pithy

Keep it current

The plugin’s version is the pithy CLI’s version, so an update arrives once per release and never between. Claude Code keeps your cached copy until that version moves.

Claude Code does not auto-update a third-party marketplace by default. To turn it on, run /plugin, open Marketplaces, choose pithy, then Enable auto-update. To update by hand:

/plugin marketplace update pithy

Upgrade the CLI at the same time. A plugin newer than your CLI will reach for commands it does not have.

The team

AgentDefaultJob
Main sessionOpus, high. Set it with /model and /effortCapabilities, data model, auth flows, your users’ agents, which clients. The decisions that are expensive to get wrong
serverSonnet, mediumThe Worker: pithy.config.ts, capabilities, app routes, migrations, and pithy contract. A route’s power gate, and, when the design has them, mcp() beside auth() and the routes it makes tools
client-webSonnet, mediumA React app in the same Worker: pithy ui add react, @pithy-sh/vite, @pithy-sh/ui-react, the kit’s TypeScript clients. Cookie sessions with CSRF, or bearer. With mcp composed, the agent consent and connected-applications screens
client-mobileSonnet, mediumThe Expo app pithy ui add react-native scaffolds into an apps/<name>/ of its own, for the app stores: the kit’s bearer session with the token in secure device storage, device headers at sign-in, native Apple and Google sign-in, and a one-time-code handoff for every other provider. With mcp composed, the agent consent and connected-applications screens
runnerHaiku, low. Bash and Read onlyRuns pithy dev, the tests, typecheck and builds, and deploys an environment you approved. Returns a summary, never raw logs

Web and mobile are two agents because they authenticate two ways. A browser holds a cookie session or a bearer token in memory; a phone holds its session token in its Keychain or Keystore. One agent holding both would mix them.

The runner cannot edit anything. It holds Bash and Read and nothing else, so the cheapest model on the team is never the one changing your code.

Choose each agent’s model

Every agent’s model and effort are plugin settings: server_model, server_effort, client_web_model, client_web_effort, client_mobile_model, client_mobile_effort, runner_model and runner_effort, with the defaults above. Change them with /plugin, or from a shell. An option you leave out keeps its value:

echo '{"server_model": "opus", "server_effort": "high"}' | claude plugin configure pithy@pithy --values-stdin

/new-app and /deploy pass your choice on every agent they dispatch, and it outranks the agent’s own default. An agent the main session reaches for on its own, outside those skills, runs on its own default. A plugin cannot put a setting into an agent’s definition, and it cannot set the main session’s model either, so that one is yours to set.

The skills

/new-app asks what pithy init asks — web, mobile or both — then scaffolds the project with pithy init --target, adding --react-native for mobile or both so the Expo app is scaffolded too, adds the capabilities, and brings in only the agents the answer needs. A mobile project gets no web agent, and a web project gets no mobile one. Once the server has composed the capabilities, the mobile agent runs pithy ui add react-native on that app to add the screens for them.

/app-design settles the capabilities, the data model and the auth flows before any code. It runs in the main session, one question at a time, because those are the decisions a cheaper model should not make. It also asks whether your app’s own users should connect their AI agents to it, and recommends no unless you name a use. On a yes it settles who may connect one, which routes become tools with each one’s permanent operation name and effect, reads first, and the power each needs, and its summary carries that as a tool table the server agent builds from. Those screens are web screens, so agents need a web front end even for a mobile-only app.

/deploy takes the app to staging or production, and connects the dashboard. Below is what it asks and what it never does.

/operate lets the session administer one deployed environment, staging unless you say otherwise, through pithy mcp connect. Its tools are your Worker’s own admin routes, served on your machine, and your Worker audits every call as an agent’s. It is not your app’s own /mcp endpoint, which /app-design settles.

  • It grants the reads first. manifest:read plus only the reads you need. Never --scope all, and never a scope that writes, sends, charges, deletes or touches a credential on the first grant.
  • You run the connect. It hands you ! pithy mcp connect … with every scope named, because the command registers a credential under your sign-in. Then restart Claude Code, or run /mcp.
  • A read needs no question. Anything else needs your yes, for that one call. It reads each tool’s kind from its MCP annotations, never from its name, and a yes is never for the next call or a loop.
  • It widens the grant only on your yes, naming each scope, with pithy mcp connect --update.
  • pithy mcp status is its to run. pithy mcp disconnect is yours.

/report-kit-gap files what the kit cannot do against pithy-sh/pithy:

  • It searches the open issues first. A match gets a comment, not a duplicate.
  • It fills the bug or feature form, with pithy --version, pithy doctor --json and the plugins that were active.
  • Its repro is written fresh. Never your code, and never a secret.
  • It files with gh only on your explicit yes. Without gh, it hands you a prefilled issue link instead.
  • It leaves a comment at the workaround naming the issue, so the workaround is found and removed when the fix ships.

Deploy, and connect the dashboard

Ask for a deploy in any session, days into a build or on the first: /deploy, or just say so. The team checks your Cloudflare credentials with pithy doctor, shows what pithy provision --dry-run would create on your account, and asks. On your yes the runner provisions, migrates and deploys that one environment, and reports each Worker’s address.

  • A yes is for one environment. A yes to staging is not a yes to production.
  • Production takes a phrase you type. yes, i really want to provision prod. The team passes it on exactly as typed and never writes it itself. A run that exits 5 stops the team and comes back to you.
  • Then the dashboard. After a staging or production deploy with no connection, it offers to connect the Pithy dashboard, and asks you what the connection is for. Your answer is recorded as its purpose, in your words. On your yes the main session runs pithy dashboard connect itself, not the runner, so the sign-in address and short code reach you while it waits. You approve the connection in your browser.
  • The dashboard or an agent, never both. An environment holds one connection. Connect the dashboard and /operate cannot connect there, so the team says so before it offers, and points you at /operate if you want the session to run that environment instead.
  • Connecting names you. The connection records who authorized it from your pithy cloudflare connect session, so it is refused under an account token, and the team says so rather than retrying.

It never runs pithy remove or a rollback. Those stay yours.

The agents build against the contract

Every client is built against the Worker’s OpenAPI document, which pithy contract writes to apps/<worker>/openapi.json, and against asyncapi.json beside it when the Worker serves a socket. The server agent keeps both current, and the client agents read them rather than guessing a route or a frame. A client in a language Pithy ships no client for generates its calls from the same file.

What it builds on

The AGENTS.md block pithy init writes, the documentation server pithy docs connect adds, pithy mcp for administering a deployed environment, and pithy schema --json. The plugin organizes the work; those are still how each agent learns and reaches the kit.

Three MCP servers, and each does one thing:

ServerWho connectsWhat it serves
pithy.sh/mcpYour session, through pithy docs connectPithy’s documentation
pithy mcpYour session, through pithy mcp connect and /operateYour deployed Worker’s admin routes, for one environment, on your machine
Your app’s own /mcpYour app’s users’ agentsThe routes your design made tools, as the user who connected. /app-design asks whether you want one

Outside Claude Code

The agents and skills drive the pithy CLI through a shell. Where a shell is not available, as on claude.ai, the skills that run commands cannot run them.

ESC