About new-agent
A development skill for adding capabilities to a Boring app. It explains how to define agents, tools, jobs, chats, views, and pages, expose them through the manifest, and verify changes.
Key features
- 01Define agents and output contracts
- 02Add sandbox or server tools
- 03Configure jobs and chats
- 04Register views and pages
- 05Run tests and verification
Use cases
- 01Add an agent capability to an app
- 02Expose a tool for the hub
- 03Build a view tied to data
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ hachej/ boring-stack --skill new-agentAfter installing, type/new-agentin Claude Code to confirm it loaded.
Details
From the project READMEAdd a capability to a Boring app
An app is a capability provider (hachej/boring-app). Every capability folder is
optional; boring.json declares what the hub may use. Add a definition; add
it to boring.json only if the hub must be able to call it. An undeclared
definition is internal: it works inside the app and is absent from the manifest.
Which capability
| The need | Create | Declare in boring.json exposes |
|---|---|---|
| One model call with a contract | agents/<name>/agent.md (+ rules.md, tool.json) | agents.<name>: "<one line>" if the hub calls it |
| Several agents with a lifecycle (a result produced from parts) | agents/<name>/JOB.md + index.mjs (plan, collect) | jobs.<name> |
| A chat with history over one agent | agents/<name>/CHAT.md (+ optional index.mjs context) | chats.<name> |
| A pure function an agent or the hub calls | tools/<name>/tool.json (runtime: sandbox) + tools/<name>/index.js | tools.<name>: { runtime, description } |
| A function that needs the database, the network or a secret | tools/<name>/tool.json (runtime: server) + server/src/tools/<name>.ts | tools.<name> |
| A component bound to data that the hub can frame | web/src/views/<name>/index.tsx (+ register it in web/src/main.tsx) | views.<name>: { shows, description } |
| The app's own screen | web/src/pages/<name>/index.tsx | pages.<name> |
An agent alone suffices for most features. Add a job only when the feature
coordinates several agents with a lifecycle, a chat only when people talk to
the agent over turns. Names are unique across agents/.
An agent
agents/<name>/
agent.md front matter + system prompt (the body)
rules.md the owner's rules, read-only in Settings; they change by pull request
tool.json only when output: tool: { name, description, input: JSON schema } (the output schema)
index.mjs optional: buildMessage(input), validate(output), asText(output); then the agent needs server/
agent.md front matter: name (the folder), title, description, model
(openai-codex/<model>), effort, max_tokens, output (tool or
markdown), helper_tools: [<tool names>] (only declared tools), inputs:
(name: { type, description, required }).
- Declarative (no
index.mjs): the message is the rules and the inputs; a markdown output must be non-empty, a tool output must carrytool.json's required fields. The hub can run it from the files alone. - With code:
validate(output)is the contract the runtime applies before anything is stored (APP-B4); refuse withfail("…")fromagents/_shared/validate.mjs, a message addressed to the model. - Fake models (
server/src/fake-models.ts) answer markdown agents; add a scripted reply for a tool agent, or its tests cannot run. - A Cloudflare app (
project.mdruntime: cloudflare) does not run the agent runtime: its agents stay declarative and the hub runs them. Noindex.mjson an agent or chat, no job;verify checkrefuses them.
A tool
- Sandbox:
tools/<name>/index.jsdefinesfunction run(input, ops), plain JavaScript with no import, no Node or network API, and only theops.<name>itstool.jsonlists underoperations.verify checkrefuses anything else. - Server:
server/src/tools/<name>.tsexportshandler(input, { db }); validate the input with zod, andawaitevery query (the same code runs on SQLite and on D1). On a Cloudflare app it uses no Node API (theworker-portablerule). tool.json:description,runtime,inputandoutputJSON schemas.
Data, routes, the web
- A table:
server/src/db/schema.ts, thennpm run db:generate, commitserver/drizzle/(neverdrizzle-kit push). A write that edits names the revision it read (APP-B3,server/src/routes/memories.tsis the example). - A route:
server/src/routes/<name>.ts(Hono +zValidator), mounted inserver/src/app.ts. - The web reaches the server only through
web/src/lib/api.ts(web/src/lib/model.tsholds the calls).
Tests and verification
- Unit (
npm test): the route and the tool through the app (test/unit/app.test.mjs), an agent's contract when it has code. - End-to-end (
test/e2e/journey.spec.mjs) when a person sees something new. node scripts/verify.mjs check, then drive it with the verify-app skill.- The feature map: the area file in
docs/verify/for what a person can do.
Never
- Expose something by accident: declare it, or keep it internal.
- Call a model outside the runtime, or give a sandbox tool an import.
- Edit
vendor/.