This repository builds apps where the AI agent and UI are equal partners:
everything the UI can do, the agent can do through the same SQL data and action
surface. Keep this file small. Put detailed workflows in .agents/skills/* and
read the relevant skill before changing that area.
- Scale effort to the task. A small, well-specified change is a short read, the edit, and the existing checks — not a codebase survey, unrequested tests, or browser automation. Save deep exploration for ambiguous or cross-cutting work.
- Stay on the current git branch. Never create, switch, delete, reset, rebase, stash, or otherwise move branches unless the user explicitly asks for that exact branch operation in the current task.
- Never add
Co-Authored-Byor other agent attribution to commits. - PRs use the current branch unless the user explicitly requests a new branch. PRs are ready for review by default, not drafts, unless requested.
- Never use
[codex],codex, or similar agent labels in user-visible GitHub metadata unless explicitly requested. - On every response, consider whether the chat title still matches the work.
- Use sub-agents liberally for complex independent work when Agent Teams are available; keep the main thread focused on orchestration.
- When adding package dependencies or framework integrations, verify the current
latest version first with
npm view/pnpm viewor current docs. Do not rely on remembered versions. - A
catch, default, or coercion that returns a value callers cannot distinguish from success is a bug, not a guard. "Absent" and "unreadable" must be different values; a truncated run is not a completed one; a dropped payload is not an empty one. Six weeks of repeat user reports traced back to this one habit — each layer coerced a failure into a clean value, so every layer above it reported something confidently wrong and nobody, including us, could see it. Prefer a loud, typed failure over a plausible-looking normal state. - Before adding a condition to a function that already stacks several special cases, stop: that shape is how the same bug ships twice. Fix the boundary that made the special case necessary, and delete the ones it subsumes.
- Write code that reads like the surrounding code: match its comment density, naming, and idiom. When you do comment, comment a constraint the code cannot show — a non-obvious trap a future change would otherwise reintroduce — not what the next line does, why your change is correct, or where it came from.
- When changing docs under
packages/core/docs/content, update the matching localized docs underpackages/core/docs/content/locales/*when the source meaning changes. If translations cannot be updated in the same change, call out the specific locales that need follow-up; reviewers should flag docs changes that only update one language.
Every final response must end with a three-line status block:
---
⠀
🟢 Actual concise status sentenceThe words after the icon are a short, task-specific status written for this
response; never use the placeholder text Brief status literally. Use 🟢
when the requested coding/work unit is finished on the current branch, even if
routine commit/PR/deploy/CI remains. Use 🟡 when non-routine work or a manual
step is still pending. Use 🔴 only when blocked on user input.
- Data lives in SQL via Drizzle by default. Explicit Local File Mode artifacts
declared through
agent-native.jsonmay use repo files as the source of truth, but app state, auth, settings, and hosted/collaborative mode still use SQL. Keep schemas provider-agnostic. - Keep app and template database code dialect-agnostic. Never call adapter-only
methods such as libSQL/SQLite
run(),all(), orget(), or PostgreSQL-only client APIs. Use Drizzle's shared query builder for normal reads and writes andgetDbExec().execute()for reviewed portable raw SQL; keep dialect branching inside core database helpers. - Actions are the single source of truth. Define app operations in
actions/withdefineAction; the agent calls them as tools and the frontend calls the shared action surface throughuseActionQuery/useActionMutation. - Client code imports named helpers, hooks, or client modules instead of
hand-writing REST calls to framework routes or template
/api/*routes. If a browser workflow needs a route and no helper exists, add the helper first and teach that method in docs/skills instead of teaching rawfetch. - Before adding any custom API or Nitro route for app data, inspect existing
actions first. Reuse or extend the action surface instead of creating REST
wrappers, pass-through endpoints, or duplicate CRUD routes that re-export
actions. If you are about to write a handler under
server/routes/api/, or middleware to guard one, stop and write an action instead. The only exceptions are uploads, streaming, inbound webhooks, OAuth callbacks, public unauthenticated URLs, and non-JSON responses. Existing template/api/*CRUD is a grandfathered baseline being migrated, not a pattern to copy;guard:no-action-twin-routesfails on new ones. - For provider integrations used in ad hoc analysis, querying, reporting, or
cross-source research, prefer the shared
provider-api-catalog,provider-api-docs, andprovider-api-requestaction pattern from@agent-native/core/provider-apiinstead of hardcoding one action per provider endpoint/filter. This is a framework tenet: first-class actions are ergonomic shortcuts, not artificial capability limits. When the upstream API can express an endpoint, filter, pagination mode, or payload, agents should have a safe way to call it directly through the provider API substrate. If an app stores provider credentials on resource/share rows, add a scoped resolver that preserves those access checks before exposing raw provider requests. - Treat Clay as a credentialed GTM provider API, not as a messaging channel.
Hosted access uses
CLAY_PUBLIC_API_KEYthrough the provider API substrate; the optional local Clay CLI/MCP plugin has a separate browser-login session and must not be required, auto-installed, or vendored by default. Its public repository currently declares no license. Use n8n and Zapier as automation/workflow or remote MCP connections rather than provider presets. - For composable workspace workflows, prefer many focused headless or small-UI
mini-apps that discover and call each other over A2A instead of one oversized
app. Pass artifact ids, URLs, and bounded summaries between apps instead of
pasting large provider dumps through prompts. Read
composable-mini-appsbefore designing cross-app orchestration. - All AI work goes through the agent chat. UIs do not call LLMs directly.
- Application state belongs in SQL
application_stateso the agent can know the current navigation, selection, and focused object. - Polling keeps UIs in sync through
useDbSync()and/_agent-native/poll. - The agent can modify app code; design UI and data flows with that in mind.
Every feature must touch the four areas when applicable: UI, actions, skills or instructions, and application state.
- Plan's
/route is the Ask Plan chat surface. Use it for product and code questions backed by visual plans, merged PR recaps, and visual answers. - For historical product questions like "what shipped last week", "when did this
API change", or "what did that UI look like", call
search-pr-recapsfirst. The default scope is merged pull requests only. Include unmerged PR recaps only when the user explicitly asks for unmerged or in-progress work. - After finding a recap, call
get-visual-planand inspect structured blocks:wireframe,diagram,api-endpoint,openapi-spec,data-model,diff,file-tree,tabs, andannotated-code. - For live code questions like "what is the API spec for this", "what does this
look like now", or "what is the schema model for x", use
visual-answerafter inspecting the real code through the local repo, the Plan bridge, or GitHub. - Before generating or updating visual content, call
get-plan-blocksorlist-plan-components. Custom components become chat-visible only after they are registered in the normalized schema, shared/server registry, and browser registry.
- Schema changes must be additive. Never drop, rename, truncate, or destructively alter tables or columns in migrations or startup code.
- SQL stores structured app state, metadata, references, and searchable text. Do
not store large raw payloads — files, images, videos, audio, PDFs, ZIPs,
screenshots, session replay chunks, thumbnails,
data:URLs, or base64 file bodies — in SQL tables,application_state,settings, orresources. Use configured file/blob storage (uploadFile,putPrivateBlob, provider object storage) and persist only URLs, ids, or opaque handles. In hosted or persistent DB mode, fail closed with setup guidance instead of falling back to SQL blobs. - Never use
drizzle-kit pushagainst production databases. - Tables with
ownableColumns()require scoped reads and writes throughaccessFilter,resolveAccess, orassertAccess. Custom Nitro routes must establish request context before querying ownable data. - Never hardcode API keys, tokens, webhook URLs, signing secrets, private Builder/internal data, customer data, or credential-looking literals in source, docs, tests, fixtures, screenshots, prompts, or generated extension/app content. Use obviously fake placeholders in examples.
- Do not copy provider tokens into apps when a workspace integration grant can be used. Vault/secrets own secret values; apps own app-specific readers and interpretation.
- A credential key gets exactly one resolver, and every runtime path goes
through it. Grep the key name before reading it; if a
resolveXConfigor connector already exists, call it rather than readingprocess.envagain elsewhere. A second env-only path does not leak — it splits the app in two, so the settings UI reports the integration as configured while the feature fails claiming the env var is unset, and the error names the wrong cause. Shared helpers take the caller's email as a parameter; only entrypoints decide identity. Runnpx agent-native doctor --only no-env-credentialsfrom the app directory before finishing a credential change. See thesecretsskill. resolveCredentialsearches exactly one organization, so it cannot read a shared key for a caller with no org (cron, CLI) or one synced under a different org. Swappingprocess.envfor it looks like a fix and changes nothing; the doctor guard does not catch this form. For workspace-wide keys use a resolver that also sweeps the caller's memberships and a designated vault org. See thesecretsskill.- Never create an organization, repoint a user's
active-org-id, or migrate a roster/identity list into a new org on your own initiative. Vault credentials are per-organization, so a second org orphans every key synced under the first and surfaces as a missing-key error elsewhere. One org per workspace is the intended pattern: add members to the existing org, and stop and get an explicit yes before doing otherwise. See theauthenticationskill. - Use the
security,storing-data,sharing,portability, andintegration-webhooksskills for implementation details.
- TypeScript everywhere. Do not add
.jsor.mjssource files. - Run oxfmt on modified source files.
- Use shadcn/ui primitives for standard controls and dialogs. Do not build custom dropdowns/popovers/modals with absolute positioning.
- Use Tabler Icons for UI icons. Do not use emojis as first-party icons.
- No browser
alert,confirm, orprompt; use shadcn dialogs. - Agent prompt inputs must use the shared composer stack:
AgentComposerFrame,PromptComposer, andTiptapComposer. - Background agents must use the core run-manager / agent-teams infrastructure unless working on the existing local Code exception.
- Logged-in app pages can be CSR. Public/SEO pages must SSR real content.
- Every SSR HTML and React Router
.dataresponse is one impersonal, public shell, hard-cached at the CDN for every visitor. Never addprivate,no-store,Vary: Cookie, session/cookie reads, or auth branches to the SSR path — personalization is client-side after load. Enforced byguard:ssr-cache-shellandssr-handler.spec.ts; do not weaken either. - UIs should be optimistic by default: update cache and navigate immediately, roll back on error, and avoid click-blocking spinners except for destructive or irreversible operations.
- Keep template UX clean and progressively disclosed. Do not solve feedback by adding always-visible controls unless that is clearly the main workflow.
- Use the
frontend-design,shadcn-ui,client-side-routing,native-navigation,real-time-sync, anddelegate-to-agentskills for details.
- Publishable package source changes in
packages/core,packages/dispatch,packages/scheduling, orpackages/pinpointneed a.changeset/*.md. - Do not manually bump package versions; changesets handle versions on merge.
- The public template allow-list is controlled by
packages/shared-app-config/templates.tsplus mirrored CLI/docs surfaces. Hidden templates must not appear in public catalogs unless they are explicitly unhidden first. - When you ship a user-facing change to a template app (new capability, visible
improvement, or behavior-affecting fix), record it from that app with
agent-native changelog add "<one user-facing sentence>" --type <added|improved|fixed>. This writes a changeset-style pending entry underchangelog/;changelog releaserolls pending entries into the app'sCHANGELOG.md, which renders in the command menu (Cmd+K → "What's new") and settings. Skip refactors, tooling, and tests. See thechangelogskill.
Extensions are sandboxed Alpine.js mini-apps stored in SQL. When the user asks
to create or edit an extension/widget/dashboard/calculator/mini-app, use the
extension actions and extensionData instead of source changes. Extensions can
call appAction for app actions/data, dbQuery, dbExec, appFetch for
allowed framework endpoints, and extensionFetch for external APIs from the
iframe bridge. Use the extensions skill for the full rules.
.agents/skills/ holds the deep guidance, one directory per skill, each with a
description naming when to read it. Read the matching skill before changing
that area — most encode a decision the surrounding code cannot show. Prefer
searching the skill directory over guessing from nearby code.
Two are entry points rather than area guides:
adding-a-feature— the four-area checklist every feature must satisfy.writing-agent-instructions— read before editing anyAGENTS.md,SKILL.md, or tool/action description, including this file.