.agents/skills/adding-a-feature/SKILL.md
The four-area checklist every new feature must complete. Use when adding any feature, integration, or capability to ensure the agent and UI stay in parity.
npx skillsauth add BuilderIO/agent-native adding-a-featureInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Every new feature MUST update all four areas. Skipping any one breaks the agent-native contract — the agent and UI must always be equal partners.
Agent-native apps are defined by parity: everything the UI can do, the agent can do, and vice versa. A feature that only has UI is invisible to the agent. A feature that only has scripts is invisible to the user. A feature without app-state sync means the agent is blind to what the user is doing.
When you add a new feature, work through these four areas in order:
Build the user-facing interface — a page, component, dialog, or route. Use useActionQuery and useActionMutation from @agent-native/core/client to call actions for data fetching and mutations — you rarely need custom /api/ routes.
Create an action in actions/ using defineAction. This serves double duty: the agent calls it as a tool, and the framework auto-exposes it as an HTTP endpoint at /_agent-native/actions/:name for the UI to call. Set http: { method: "GET" } for read actions, leave default for writes, or set http: false for agent-only actions like navigate and view-screen.
Update AGENTS.md and/or create a skill in .agents/skills/ if the feature introduces patterns the agent needs to know. At minimum, add the new actions to the action table in the template's AGENTS.md.
Expose navigation and selection state so the agent knows what the user is looking at. Write to the navigation app-state key on route changes. Update the view-screen action to fetch relevant data for the new feature. Add a navigate command if the agent needs to open the new view.
| Area | What to build |
| --------------- | ---------------------------------------------------------------------------------------- |
| UI | Compose panel with tabs, to/cc/bcc fields, body editor. Use useActionQuery/useActionMutation for data. |
| Action | manage-draft action (create/update/delete drafts), send-email action |
| Skills/AGENTS | Document compose state shape, draft lifecycle, action args in AGENTS.md |
| App-state sync | compose-{id} keys for each draft tab, navigation includes compose state |
| Area | What to build |
| --------------- | ---------------------------------------------------------------------------------------- |
| UI | Form builder page with drag-and-drop fields, preview, settings. Use useActionQuery for lists. |
| Action | create-form action, update-form action, list-forms action (GET) |
| Skills/AGENTS | Document form schema shape, field types, validation rules in AGENTS.md |
| App-state sync | navigation includes { view: "form-builder", formId: "..." }, view-screen fetches form data |
| Area | What to build |
| --------------- | ---------------------------------------------------------------------------------------- |
| UI | New chart component, chart type selector in dashboard |
| Action | create-chart or update-dashboard action that sets chart type and config |
| Skills/AGENTS | Document supported chart types, config options, data requirements |
| App-state sync | navigation includes selected chart/dashboard, view-screen returns chart config |
Templates are single-page apps with client-side routing. The app shell (AgentSidebar + top-level nav) MUST persist across navigation — it is mounted once, either in root.tsx around <Outlet /> or via a pathless _app.tsx layout route that all authed routes nest under.
Never wrap each new route in its own <AppLayout> / <Layout>. That causes React to unmount the entire app shell on every navigation, reloading the agent sidebar and destroying in-progress work.
<AppLayout> in root.tsx — just render page content in your new route file, nothing else.app/routes/_app.tsx (pathless layout) — name your new route _app.<segment>.tsx to inherit the shell, or bare <segment>.tsx for public routes that should NOT have the shell.useParams() / useLocation(). Don't pass it as a prop through every route file.See the "Client-Side Routing" section in the root CLAUDE.md for full details.
<AppLayout> wrappers — Every route file wraps its content in <AppLayout> or <Layout>. React sees a different component at the outlet on each nav and unmounts the whole shell, causing the agent sidebar to reload on every click. Mount the shell once above <Outlet /> (root.tsx or _app.tsx pathless layout)./api/ routes for operations that actions already handle. Actions are auto-exposed as HTTP endpoints — use useActionQuery/useActionMutation instead.After completing all four areas, verify:
pnpm action view-screen show the relevant state when the user is using the feature?navigate action?defineAction and the http option (area 2 in detail)tools
Public booking flow — the state machine, animations, and URL/app-state sync.
tools
Trigger-based automations — reminders, follow-ups, webhooks — across the booking lifecycle.
tools
Team event types, round-robin assignment, collective bookings, host weights, and no-show calibration.
development
The pure `computeAvailableSlots` function — inputs, outputs, invariants, and debugging guide.