01 · Quickstart

From zero to your first running agent in about 5 minutes.

Prerequisites

DependencyRequirementNotes
Node>=22.19.0pi’s engines constraint; production images use node:24-bookworm-slim. Stick with Node at runtime (Bun is only used for the toolchain).
pnpm9.x (packageManager: [email protected])workspace monorepo.
pi config directory~/.pi/agent existsRun pi once and log in so that auth.json / settings.json are generated. Or provide a provider key via environment variables (see below).

Never installed pi? First run npm i -g @earendil-works/pi-coding-agent (or follow its docs), then run pi and log in once.

Install & Run (Development Mode)

pnpm install
pnpm dev          # next dev — http://localhost:3000

Open the browser and enter a source in the agent source picker, in one of three forms:

  • A directory containing index.ts → runs your custom agent (custom mode);
  • Any directory → general CLI mode (pi --mode rpc);
  • A git source → resolved, then same as above.

Pick One from examples/ to Get Started

The repo’s examples/ directory ships several ready-to-point-at examples, organized by capability in the examples index. For your first run, we recommend either of these two introductory examples:

ExampleBest forNotes
examples/hello-agentYour first runA self-contained, minimal custom agent that exposes a single echo tool and does not load system tools or on-disk skills.
examples/minimal-agentSeeing the leanest entryA skeleton with only the required fields of defineAgent(), handy for modeling your own entry file.

For more examples organized by capability (attachments, AIGC, Web UI extensions, etc.), see the examples index.

Run the Example Agent in 5 Minutes

The following uses the minimal example examples/hello-agent:

// examples/hello-agent/index.ts (excerpt)
import { defineAgent } from "@blksails/pi-web-agent-kit";
import { defineTool } from "@earendil-works/pi-coding-agent";
import { Type } from "@earendil-works/pi-ai";
 
const echo = defineTool({
  name: "echo",
  label: "Echo",
  description: "Echo the provided text back to the caller.",
  parameters: Type.Object({ text: Type.String() }),
  async execute(_id, params) {
    return { content: [{ type: "text", text: params.text }], details: undefined };
  },
});
 
export default defineAgent({
  // model omitted → inherits the default provider/model from ~/.pi/agent/settings.json
  systemPrompt: "You are hello-agent, a minimal pi-web example agent.",
  customTools: [echo],
});

The above is an excerpt. The real examples/hello-agent/index.ts:1 also sets noTools: "builtin" and skills: () => ({ skills: [], ... }), making the example self-contained — it exposes only the custom echo tool and loads neither system built-in tools nor disk-discovered skills. The meaning of these two switches is covered in 07 · Custom Agent Development.

Steps:

  1. After pnpm dev starts, open http://localhost:3000
  2. Enter the absolute path to examples/hello-agent in the picker (the picker requires an absolute path; or set PI_WEB_DEFAULT_SOURCE, see below)
  3. Enter the session and send a message → expected: you see a streaming reply
  4. Make it call the tool: send “use the echo tool to echo hello” (or a similar instruction) → expected: an echo tool card appears in the session

No reply / authentication error? Most likely the default provider/model has no valid key. First use the stub agent under “Offline Quick Verification” below to get the chain working; for authentication issues, see 18 · Troubleshooting / FAQ.

hello-agent deliberately omits model, letting it inherit the default provider/model from your pi login, so it works out of the box. To pin the model, add model: { provider, modelId }, but that provider must have valid authentication.

Configuration (Optional)

Credentials and defaults come from ~/.pi/agent by default (if you’ve logged in to pi, no environment keys are needed). To override, copy .env.local.example to .env.local. The most common ones:

# .env.local
PI_WEB_DEFAULT_SOURCE=/abs/path/to/examples/hello-agent  # default source for the picker
PI_WEB_DEFAULT_CWD=/abs/path/to/workdir                  # default working directory for sessions
PI_WEB_DEFAULT_PROVIDER=openrouter                       # force the provider (otherwise from settings.json)
PI_WEB_DEFAULT_MODEL=anthropic/claude-sonnet-4.6         # force the model (value must match the provider)

For the complete set of variables, see 05 · Configuration Reference.

Offline Quick Verification (No Model Quota Consumed)

You can verify the full chain without an LLM key (using a deterministic stub agent):

PI_WEB_STUB_AGENT=1 pnpm dev
# or run the offline Node-level streaming e2e:
pnpm e2e:node

Common Scripts at a Glance

CommandPurpose
pnpm devDev server (next dev, :3000)
pnpm build / pnpm startProduction build / start
pnpm testTests for all workspace packages
pnpm test:appApp-level vitest
pnpm e2ePlaywright browser e2e
pnpm e2e:nodeOffline Node-level streaming e2e (stub agent)
pnpm typecheckTypecheck for all packages + app
pnpm build:cli / pnpm start:cliBuild / start the global CLI (standalone, see 14 · CLI)

Common First-Time Issues

  • Don’t run pnpm build during dev — it pollutes the shared .next and causes webpack 500s. CLI/e2e builds use isolated directories (NEXT_DIST_DIR=.next-cli / .next-e2e).
  • Changed an injected route / config domain but the route didn’t take effect — the handler singleton is pinned on globalThis, and hot reload does not refresh new routes, so you need to restart dev.
  • For more, see 18 · Troubleshooting / FAQ.

Next Steps