AGENTS.md · pizza-bot-app/pizza-bot
AGENTS.md from pizza-bot-app/pizza-bot: 244 lines covering The one-line mental model, Layering discipline (don't break these), Where things live (for the…
Template by pizza-bot-app
Install
Works with Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code. Read the repository before you give any tool access to your data.
curl -fsSL https://raw.githubusercontent.com/pizza-bot-app/pizza-bot/main/AGENTS.md -o AGENTS.md
Read it and adapt it to your project before use.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: documentation
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
What's in it
An AGENTS.md file: instructions coding agents (Codex, Cursor, Copilot, Gemini CLI and others) read before working in a repo.
- For
- Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code
- Length
- 244 lines
- File
AGENTS.md
Sections
- The one-line mental model
- Layering discipline (don't break these)
- Where things live (for the common asks)
- Testing
- Windows: constraints the suite has to respect
- Verify in the browser, not just tests
- Comments
- Conventions
- Git workflow
First lines (shown under the repo's Apache-2.0 license)
# AGENTS.md
Guidance for working in this repo. Start with [README.md](README.md) (layout +
how to run) and [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) (seams, event model,
design decisions) — this file is the operational overlay, not a duplicate.
## The one-line mental model
A stateful agentic inbox running one runtime (DeepAgents/LangGraph). The runtime
emits native
`@langchain/protocol` `ProtocolEvent` frames via `streamEvents(v3)`; every
frontend consumes them through the `@langchain/langgraph-sdk`
`Client`/`ThreadStream`/`StreamController` over HTTP/SSE. The seam is that
**protocol + SDK projection** boundary; keep React coupling outside it.
## Layering discipline (don't break these)
- `packages/core` is **nearly pure** — no `node:*`, no DOM, no `deepagents` /
`@langchain/langgraph`, no `ai` — but it MAY import `@langchain/core` model/agent
**types** (`BaseChatModel`), because the app is coupled to LangGraph by design
and the model seam is honestly typed, not laundered through `unknown`. Core also
owns the pure protocol/wire types (`protocol-types.ts`). The framework-agnostic
message/thread-slice projection helpers live in `apps/web/src/projection` — the
only consumer is the web app, so they sit beside it rather than in a shared
package. The eslint layering rule enforces core's purity.
- `packages/plugin-api` is the public, browser-safe plugin contract — no
`node:*`, LangChain, runtime, or UI imports. `packages/plugin-sdk` owns the
Node-bound filesystem loader, materializers, MCP clients, and contribution
registries. The eslint layering rule enforces plugin-api's purity.
- **`packages/runtime-langgraph` is the ONLY production package that imports
`deepagents` — the graph engine.** The `tests/langgraph-compat` workspace is a
test-only exception because it pins DeepAgents' public exports. If the
DeepAgents API churns, the runtime blast radius must stay one package. In
production, two narrow, deliberate exceptions touch
`@langchain/langgraph` WITHOUT the engine: `packages/storage` imports its
`InMemoryStore` (a checkpoint-store primitive, kept out of runtime-langgraph
because it's Node-bound), and `apps/api-server` imports `ProtocolEvent` as a
TYPE only (the wire event). The conformance workspace may import upstream
types for tests. The eslint layering guards enforce the core/ui purity +
frontend rules; the `deepagents` "only" invariant is a convention, not
lint-enforced.
- The frontend (`apps/web`) never imports a runtime or a model
binding. It MAY import the transport SDK (`@langchain/langgraph-sdk`) — that's
the wire — but never the runtime graph engine.
- The api-server assembles the concrete runtime through
`createPizzaBotAgent` (`packages/runtime-langgraph`). Core knows only the
minimal structural `AgentHandle` (`core/src/agent-run.ts`) the concrete agent
satisfies (state read/write; the streaming method `streamProtocol` lives on
the concrete `LangGraphAgent`, since its `ProtocolEvent`s can't be named
without a `@langchain/langgraph` import). The runtime is stateful and
checkpointer-backed.
## Where things live (for the common asks)
- **Runtime → protocol stream** (LangGraph → `ProtocolEvent` frames):
`runtime-langgraph/src/stream-protocol.ts` holds `streamProtocolEvents` +
`toLangGraphInput`; `index.ts`'s `LangGraphAgent.streamProtocol()` is the thin
driver over it and the only streaming path. Native v3 correlation is
reassembled client-side by the SDK `StreamController`. The offline conformance
guard is `tests/langgraph-compat/protocol-stream-conformance.test.ts`.
- **The protocol/wire types**: `packages/core/src/protocol-types.ts`
(`NormalizedMessage`, `ThreadStateValues`, HITL vocab, `ErrorCode`, `RunStatus`,
`PROTOCOL_VERSION`, and wire schemas).
- **Runtime factory + agent handle**: `runtime-langgraph`'s `index.ts` exports
`createPizzaBotAgent(systemPrompt, deps)` returning a `LangGraphAgent`; the run data
types + the structural `AgentHandle` it satisfies live in
`packages/core/src/agent-run.ts`.
- **Server composition root** (wires the runtime factory + storage + model):
`apps/api-server` (`agent-host.ts` is the assembly; `index.ts` serves it). The
in-process run registry is `ProtocolRunManager` (`protocol-run-manager.ts` —
buffers frames per run, fans out to observers with `since`-based replay,
cancels via `AbortSignal`); the SDK-facing wire is `routes-protocol.ts` (4
Agent-Protocol endpoints: `POST /threads/:id/commands`, `POST
/threads/:id/runs/:run_id/cancel` — what the SDK's `stop()` calls — `POST
/threads/:id/stream/events`, `GET /threads/:id/state`).
- **Message/thread projection** (SDK projections → feed messages/cards): the
pure helpers in `apps/web/src/projection` (`messages.ts` =
`messagesToUI`/interrupt overlays/hydrate helpers, `thread-slice.ts` =
`ThreadSlice`/`StreamStatus`). The web binds via
`apps/web/src/protocol-stream-store.ts` (a headless SDK `StreamController` per
thread) behind the thin `use-thread-slice.ts` hook;
`components/ActivityRail.tsx` renders delegated work in the Activity panel.
- **Model providers**: `packages/inference-providers` (one adapter per provider
under `src/providers/`, with flat files except for Bedrock's multi-file shim in
`src/providers/bedrock/`).
- **Agent definition**: `packages/core/src/agent.ts` (`pizzaBotSystemPrompt` + the
single `PIZZA_BOT_AGENT` orchestrator). Capabilities come from skills under
`skills/<id>/SKILL.md`, projected into delegatable subagents by
`resolveSkillSubagents` and seeded into run state by `buildSkillSeed` /
`withSkillSeed` (`runtime-langgraph/src/index.ts`).
## Testing
- **`npm test` is the supported entrypoint** — it runs the license-generator
tests, then `turbo run test --concurrency=2`; the cap is deliberate (uncapped,
the parallel vitest+esbuild workers can exhaust file descriptors / memory and
fail en masse). CI runs the same command.
- For a tight iteration loop, run one workspace directly:
`npx vitest run --dir packages/<pkg>` (or `--dir apps/web`).
- Typecheck a package with `npx tsc --noEmit -p <path>/tsconfig.json`, or the
whole graph with `npm run typecheck`. Lint with `npm run lint`
(typescript-eslint flat config).
## Windows: constraints the suite has to respect
`npm test` is green on Windows. Five platform differences shape how these tests
are written — keep them in mind when adding assertions or temp-dir cleanup:
- **Two `realpath`s that disagree.** `fs.realpathSync` is Node's JS implementation
and preserves 8.3 short names, which is what `os.tmpdir()` yields on CI
(`C:\Users\RUNNER~1\...`); `fs/promises` `realpath` and `realpathSync.native`
call libuv and expand them. Never compare paths canonicalized by different ones
— a containment check across the two silently fails on Windows only.
- **No POSIX mode bits.** Windows `chmod` only toggles the read-only bit, so
`0o700`/`0o600` assertions can never hold. Gate them on
`process.platform !== "win32"` (see `packages/logging` `file-store.test.ts` and
`packages/storage` `app-db.test.ts`).
- **Symlinks need elevation.** `symlink()` throws `EPERM` without Developer Mode,
so symlink-behavior tests use `it.skipIf(process.platform === "win32")`.
- **CRLF checkouts.** `core.autocrlf` yields CRLF and the repo has no
`.gitattributes`, so never assert an exact `\n` against on-disk repo content —
match `\r?\n`. Production parsers already tolerate both (e.g.
`plugin-sdk/frontmatter.ts`).
- **Deleting a directory races the OS.** Windows keeps directory/file handles open
briefly after a child process exits, so `rmSync` in an `afterAll` throws `EPERM`
even though the owning process is gone. Always pass `maxRetries`/`retryDelay`
(see `apps/desktop-shell` `sidecar.test.ts`). This surfaces under full-suite
load and usually *not* in an isolated run, so reproduce with `npm test`.
`npm install` does not need MSVC — see CONTRIBUTING's setup note for how
`allowScripts` denies `better-sqlite3`'s implicit `node-gyp rebuild`, which
would otherwise be both mandatory (node-gyp fails at *configure* without a
toolchain) and unused (prebuilt binaries ship for every platform). Electron 44
has no `postinstall`; `index.js` downloads the binary lazily on first launch.
## Verify in the browser, not just tests
For frontend/runtime-seam work, passing unit tests are necessary but not
sufficient — tests inject fakes and have missed real cross-environment bugs.
Actually run it. Fastest loop for a runtime-side change: a small `tsx` script that
drives `createPizzaBotAgent(systemPrompt, deps).then(a => a.streamProtocol(input, opts))`
against live Bedrock and inspects the emitted `ProtocolEvent` frames (needs
`AWS_REGION` + Bedrock creds). For UI work,
launch the app per `docs/RUNNING.md` and drive it. Delete throwaway probe scripts
when done.
When driving the protocol endpoints by hand, two contracts trip people up:
- `POST /threads/:id/commands` expects `{id, method, params}` (`run.start`,
`input.respond`, …). A body that is not a JSON object returns `400
invalid_argument`; an unrecognized method returns `422 unknown_command`. The
only empty `204` is `run.stop`'s acknowledgement, whether it stopped a run or
found none.
- `POST /threads/:id/stream/events` filters by `channels`, and an empty/absent
array *silently* matches no frames (`frameMatchesFilter`), which looks like a
broken server. Name them explicitly:
`values`, `messages`, `updates`, `lifecycle`, `tools`, `tasks`, `input`, `custom`.
`apps/api-server` needs `PIZZA_ALLOWED_ORIGINS` set to the web origin when ViteSignals
- Stars
- 520
- Forks
- 55
- Open issues
- 17
- Last commit (this folder)
- Oct 5, 2026 (23 days ago)
- Last release
- Oct 2, 2026 (26 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- Apache-2.0
- Repository
- github.com/pizza-bot-app/pizza-bot
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from pizza-bot-app
Cite this page
AGENTS.md · pizza-bot-app/pizza-bot. Agent Mart. https://agentmart.dev/templates/pizza-bot-app-pizza-bot-agents-md (last updated 2026-10-24)