Developers
Start building
AI/AI rules

AI rules

Rules for AI coding tools working on a Poltura app or theme. The same text ships as AGENTS.md and as a Cursor rule.

On this page
AGENTS.mdCursor rule

These rules are for AI coding tools working on a Poltura app or theme. The full documentation index is at https://developers.poltura.com/llms.txt, and every page is also available as Markdown by adding .md to its address.

Always

  • Read the matching docs page before writing code, through its .md address.
  • Use only the public packages: @poltura/app-sdk, @poltura/app-ui, @poltura/app-contracts, @poltura/cli and @poltura/theme-sdk. Never import other @poltura/* packages and never reach a store's database.
  • Do not invent APIs. If a name is not in the docs or in the package's types, it does not exist.
  • Before you say the work is done, run poltura check in the app or theme directory and fix every error it reports. Each finding names the rule and says what to change. Use poltura check --json to read the result.

Apps

  • An app is poltura.app.json plus its sources. Scaffold one with poltura app create <dir> --template native or --template hosted.
  • After every change run poltura app build and poltura app validate, and fix every error before moving on. Before finishing, run poltura check: it adds the permission, agent entry and code rule checks.
  • Parse input where it enters your code: no unknown parameters or return types, no dictionaries of unknown, any or object, no runtime typeof on unparsed values, and a // SAFETY: comment on every type assertion.
  • Declare the fewest permissions the app needs. Each permission needs a purpose of 8 to 280 characters that a merchant understands, because merchants read it before they approve.
  • Declare storefront blocks and their settings once, with defineBlock from @poltura/app-sdk/elements, in the file elements names. A worker reads the merchant's values with useSettings().
  • A worker file starts with import '@poltura/app-ui/worker', renders with startUiWorker(<Root />) from @poltura/app-ui/worker-runtime, and draws only with the primitives of @poltura/app-ui/admin (admin targets) or @poltura/app-ui/storefront (storefront targets).
  • Workers cannot fetch your server or the App API. They call your backend through useAction(actionId), and the backend verifies the request with createActionHandler from @poltura/app-sdk/actions.
  • Installation access tokens stay on your server. Never send one to a worker, an iframe or the browser.
  • Call the App API with PolturaClient from @poltura/app-sdk. Lists are cursor pages (limit up to 100, then nextCursor). Every write carries an Idempotency-Key. Money is { amount: "49.99", currency: "EUR" } in major units; never multiply by 100.
  • Verify every webhook with createWebhookVerifier from @poltura/app-sdk/webhooks before reading its body. Deliveries are retried, so handling one twice must be harmless.
  • Publish with poltura app publish --api "$POLTURA_API" --token "$POLTURA_APP_TOKEN", with appId in poltura.app.json or --app. The token is a developer token (pltd_ for CI, or a personal pltu_) from Developer apps. Never commit a token.

Themes

  • A theme is TSX and JSON, edited in the store's theme code editor. Saves go to the theme's draft; publishing is a separate step.
  • Import Poltura APIs from @poltura/theme-sdk/<module> (there is no root import). Besides that a theme may import its own files, React and a fixed set of UI libraries the theme check names; anything else is refused.
  • Write one section per file, src/sections/<type>.tsx, and one block per file, src/blocks/<type>.tsx, declared with defineSection or defineBlock from @poltura/theme-sdk/elements. The type is kebab-case, matches the file name and stays fixed once merchants use it; rename with renamedFrom.
  • A section's component receives attrs. Spread them onto exactly one root element and merge classes with cn(attrs.className, ...) from @poltura/theme-sdk/ui. Without that, the merchant's style controls do nothing.
  • Settings are field.* builders with a label and a default. Read them from the typed settings prop, and use EditableText for text merchants edit in place.
  • Draw prices with the price parts and format any other amount with useFormat().money(). Never format money by hand.
  • Theme code renders on the server for every shopper of the store: no per-shopper state and no clock reads at module scope, and no window or document outside effects.
  • Default copy has no em dashes and no middle dots.
  • In the code editor the theme check runs on every save. Fix every problem it reports before publishing.
  • Working on a theme in files, run poltura check before finishing; it runs the theme check and the code rules.
Last updated