# Agent guidance — {{name}} (role-gating API)

- Invoke the CLI as `pnpm mesh <cmd>` or (cwd-independent) `pnpm exec mesh <cmd>`.
  Operations are `mesh` commands, never raw `aws`/`pulumi`/`kubectl`.
- This app is **role-gating**: authorization is a coarse-role check on the
  caller's Zitadel project roles, enforced in-process. There is NO SpiceDB — do
  not add one (the `AppAuthzPointer` guard fails the deploy if you do).
- Authorization vocabulary lives ONLY in `api/src/schema.ts` (`coarseRoles`).
  Routes enforce it with `m.requireRole("<role>")` — never hand-roll role checks.
  The same `coarseRoles` become the app's Zitadel project roles in `index.ts`.
- **Two non-negotiables for role-gating apps (already wired — keep them):**
  1. `api/package.json` build MUST be `esm-bundle …`, not `tsc` — plain `tsc`
     ships bare `@mesh-tech/*` imports the container can't resolve.
  2. `index.ts` MUST pass `opsHubMetadata: compileOpsHubMetadata(schema)` to
     `AppAuthzPointer` — the pointer publishes the blob at the conventional
     path itself; do NOT add a separate `mesh.exports.Export`. Without it the
     Hub create-key wizard 409s (`METADATA_UNPUBLISHED`).
- Machine/API-key callers carry roles under the project-id-keyed Zitadel claim;
  `authn.ts` passes `projectId` to `zitadelJwtScheme` so it reads the right key.
- Pattern skills for authn/authz ship inside those packages (TanStack Intent
  discovers them after `pnpm install`).
