# Hand-authored feature → package recipes.
# Package/skill ids must exist in the generated catalog (validated by sync + tests).
# Add a recipe when a discoverable product ask should route to @eristack/*.

recipes:
  - id: money-amounts
    title: Prices, tax, discounts, and totals
    priority: 10
    triggers:
      - price
      - prices
      - money
      - currency
      - tax
      - discount
      - discounts
      - markup
      - percent
      - percentage
      - totals
      - amount
      - amounts
    rationale: >
      Use @eristack/money for immutable currency-safe amounts. Never use JS
      number literals for money — prefer Money.of("19.99", "USD").
    packages:
      - name: "@eristack/money"
        skills:
          - money-amounts
        role: primary

  - id: money-ledger
    title: Invoices, payment splits, FX, and ledger rounding
    priority: 20
    triggers:
      - invoice
      - invoices
      - ledger
      - allocate
      - allocation
      - split
      - splits
      - payment split
      - fx
      - exchange rate
      - multi-currency
      - rounding
      - serialize money
    rationale: >
      Round at ledger boundaries, allocate without losing cents, convert with
      app-supplied FX rates, and serialize amounts as decimal strings. For SQL
      columns and HTTP validation load money-adapters (drizzle.md / rest.md / zod.md).
    packages:
      - name: "@eristack/money"
        skills:
          - money-ledger
          - money-amounts
        role: primary

  - id: money-persist
    title: Store money in SQL and validate API bodies
    priority: 18
    triggers:
      - store money
      - persist money
      - drizzle money
      - filter by amount
      - money schema
      - zod money
    rationale: >
      Use @eristack/money/drizzle (docs/drizzle.md) for SQL columns; ./rest or ./zod
      for wire MoneyJSON; ./express or ./nest for HTTP. Hub: docs/adapters.md.
    packages:
      - name: "@eristack/money"
        skills:
          - money-adapters
          - money-ledger
        role: primary

  - id: timestamp-instant
    title: Transaction dates and posted-at times
    priority: 14
    triggers:
      - transaction date
      - transaction_date
      - posted at
      - posted_at
      - occurred at
      - occurred_at
      - business date
    rationale: >
      Use @eristack/timestamp instant mode: UTC instant + IANA timezone for local
      transaction_date labels. Not raw Date or server timezone.
    packages:
      - name: "@eristack/timestamp"
        skills:
          - timestamp-core
        role: primary

  - id: timestamp-wall
    title: Due dates, appointments, and local schedules
    priority: 15
    triggers:
      - due date
      - due_at
      - scheduled
      - scheduled at
      - appointment
      - local midnight
      - dst
      - timezone schedule
    rationale: >
      Use @eristack/timestamp wall mode for local wall-clock intent (DST-safe).
      Convert to UTC only via wallToInstantOnce for single occurrences.
    packages:
      - name: "@eristack/timestamp"
        skills:
          - timestamp-core
        role: primary

  - id: timestamp-persist
    title: Store timestamps in SQL and validate API bodies
    priority: 17
    triggers:
      - store timestamp
      - persist timestamp
      - drizzle timestamp
      - timestamptz
      - posted_at column
      - due_at column
      - timestamp schema
      - zod timestamp
      - parse postedAt
    rationale: >
      Use @eristack/timestamp/drizzle (docs/drizzle.md) for instant/wall SQL columns;
      ./rest or ./zod for TimestampJSON; ./express or ./nest for HTTP. Hub: docs/adapters.md.
    packages:
      - name: "@eristack/timestamp"
        skills:
          - timestamp-adapters
          - timestamp-core
        role: primary

  - id: line-pricing-qups
    title: Line quantity, unit price, discounts, and tax
    priority: 12
    triggers:
      - qups
      - quantity
      - unit price
      - subtotal
      - line total
      - line discount
      - surcharge
      - discount percent
      - goods receipt line
      - order line
      - invoice line
      - truth mode
      - source of truth
      - qups truth
      - amount only
      - flat amount
      - shared currency line
      - applyCellPatch
      - cell patch
      - spreadsheet cell edit
    rationale: >
      Use @eristack/qups calculateLine/patchLine for quantity/unit-price/subtotal
      (exact ratio when UP+S), modifiers, and tax — same math in TanStack Form and
      on the BE. Import QUPS_TRUTH_MODES and isQupsTruthMode — do not copy the three
      truth strings; qupsRolesFor(truth) for required SoT fields. Flat amount +
      row currency: createAmountOnlyFieldValidators from @eristack/money/react (not
      nested MoneyJSON). Inject qupsLineColumns into detail tables; withQupsColumns
      for inserts. See qups stores.md + money drizzle.md.
    packages:
      - name: "@eristack/qups"
        skills:
          - qups-core
          - qups-line
          - qups-adapters
        role: primary
      - name: "@eristack/money"
        skills:
          - money-amounts
          - money-ledger
          - money-adapters
        role: supporting

  - id: jwt-auth-sessions
    title: Login, JWT access, and refresh sessions
    priority: 10
    triggers:
      - login
      - logout
      - auth
      - authentication
      - jwt
      - access token
      - refresh token
      - session
      - sessions
      - password
      - credentials
      - sign in
      - sign-in
    rationale: >
      Use @eristack/jwt-auth for JWT access + opaque refresh with rotation.
      Credentials are a child of your app users table — do not invent a second users model.
    packages:
      - name: "@eristack/jwt-auth"
        skills:
          - jwt-auth-core
        role: primary

  - id: jwt-auth-adapters
    title: Wire auth to Drizzle, HTTP, and React
    priority: 30
    triggers:
      - auth adapter
      - auth express
      - auth nest
      - auth drizzle
      - auth react
      - jwt router
      - require auth
      - auth guard
    rationale: >
      Persist refresh tokens and credentials with Drizzle; expose headless
      REST/Express/Nest/client/React shells. Prefer examples/* patterns.
    packages:
      - name: "@eristack/jwt-auth"
        skills:
          - jwt-auth-adapters
          - jwt-auth-core
        role: primary

  - id: doc-number-sequences
    title: Document and invoice numbers
    priority: 10
    triggers:
      - document number
      - document numbers
      - doc number
      - invoice number
      - invoice numbers
      - sequential number
      - sequence
      - sequences
      - number format
      - period reset
      - yearly reset
    rationale: >
      Use @eristack/doc-number for token patterns ({YYYY}/{SEQ:n}), period
      resets, and atomic sequence allocation.
    packages:
      - name: "@eristack/doc-number"
        skills:
          - doc-number-core
        role: primary

  - id: doc-number-adapters
    title: Persist and configure document-number formats
    priority: 30
    triggers:
      - format store
      - doc number adapter
      - doc number express
      - doc number nest
      - doc number react
      - format crud
    rationale: >
      Drizzle FormatStore/SequenceStore plus REST/Express/Nest/client/React
      format-config shells. App injects db + createDocNumber instance.
    packages:
      - name: "@eristack/doc-number"
        skills:
          - doc-number-adapters
          - doc-number-core
        role: primary

  - id: data-grid-lists
    title: Dynamic list filters, search, sort, and pagination
    priority: 10
    triggers:
      - data grid
      - datagrid
      - table filter
      - table filters
      - list filter
      - advanced filter
      - search string
      - multi sort
      - pagination
      - offset pagination
      - cursor pagination
      - query string filter
      - sort price
      - filter price
      - decimal column
      - money column
      - unit price list
      - compareDecimalStrings
      - wall date filter
      - transaction_date filter
      - compareWallValues
      - decimal string
    rationale: >
      Use @eristack/data-grid for schema-aware list queries. For decimal money
      columns (unitPrice, amounts as strings) set schema type decimal or money —
      applyInMemory sort/filter without Number(). Use type number only for true
      numeric columns (qty counts). Prefer advanced filters and search mode as
      separate modes. Skip data-grid on tiny household registers (~20 rows) — Query + table only.
    packages:
      - name: "@eristack/data-grid"
        skills:
          - data-grid-core
          - data-grid-adapters
        role: primary

  - id: erp-app-core
    title: ERP-ish app with auth, money, and numbering
    priority: 8
    triggers:
      - invoicing app
      - billing app
      - commerce backend
      - order management
    rationale: >
      Auth + money + numbering without the full document-lines spine: load
      @eristack/ai-knowledge#package-relationships first, then jwt-auth, money,
      doc-number, data-grid core skills. For header + QUPS lines use #document-lines-erp instead.
    canonicalSkills:
      - "@eristack/ai-knowledge#package-relationships"
    packages:
      - name: "@eristack/jwt-auth"
        skills:
          - jwt-auth-core
          - jwt-auth-adapters
        role: primary
      - name: "@eristack/money"
        skills:
          - money-amounts
          - money-ledger
        role: primary
      - name: "@eristack/doc-number"
        skills:
          - doc-number-core
          - doc-number-adapters
        role: primary
      - name: "@eristack/data-grid"
        skills:
          - data-grid-core
        role: supporting

  - id: erp-feedback-busy
    title: Busy lock, confirm-run sequence, and error disposition
    priority: 13
    triggers:
      - busy lock
      - shell inert
      - confirm then save
      - error catalog
      - error disposition
      - toast error message
      - feedback sequence
    rationale: >
      Platform seams: @eristack/feedback createBusy/runFeedbackSequence for confirm→run→toast;
      @eristack/backseat/express createErrorCatalog for HTTP + client disposition. Load feedback-core
      and #http-errors — not a second mapHandlerError.
    packages:
      - name: "@eristack/feedback"
        skills:
          - feedback-core
        role: primary
      - name: "@eristack/backseat"
        skills:
          - backseat-core
        role: supporting

  - id: epoch-cache-invalidation
    title: Data-version epochs for cache invalidation
    priority: 14
    triggers:
      - cache invalidation
      - stale cache
      - refetch data
      - use cache
      - data version
      - epoch
      - optimistic cache
      - tanstack query invalidate
      - bumpMany
    rationale: >
      Use @eristack/epoch for headless per-scope version counters: bump after mutations,
      resolveCachePolicy returns use-cache vs refetch for TanStack Query; useEpochInvalidation(scope, queryKey, { exact: true }) binds a detail query without prefix refetch. Drizzle default;
      client/react/express/backseat adapters. Read docs/getting-started.md only.
    packages:
      - name: "@eristack/epoch"
        skills:
          - epoch-core
          - epoch-adapters
        role: primary

  - id: oauth-sso-google-oidc
    title: Sign in with Google, OIDC, or OAuth provider API
    priority: 16
    triggers:
      - sign in with google
      - google oauth
      - microsoft login
      - entra id
      - github login
      - sign in with apple
      - facebook login
      - linkedin login
      - okta login
      - auth0 login
      - keycloak login
      - slack login
      - discord login
      - oidc login
      - oauth2 client
      - pkce
      - authorization server
      - oauth provider
      - partner api tokens
      - sso login
    rationale: >
      Use @eristack/oauth for IdP login — preset drivers (Google, Microsoft, GitHub, Apple,
      Okta, Auth0, Keycloak, …) in docs/drivers.md — PKCE, Drizzle pending logins, then
      @eristack/jwt-auth issueTokens. Use /provider for third-party clients. Load
      oauth-client-core (drivers.md) + oauth-provider-core only when needed.
    packages:
      - name: "@eristack/oauth"
        skills:
          - oauth-client-core
        role: primary
      - name: "@eristack/jwt-auth"
        skills:
          - jwt-auth-core
        role: companion

  - id: comms-email-sms-whatsapp
    title: Transactional email, SMS, and WhatsApp
    priority: 15
    triggers:
      - send email
      - transactional email
      - sendgrid
      - postmark
      - mailgun
      - resend
      - twilio
      - send sms
      - whatsapp message
      - otp sms
      - notification email
      - magic link email
    rationale: >
      Use @eristack/comms for idempotent outbound messaging — SendGrid/Postmark/Mailgun/Resend email,
      Twilio/Vonage SMS, Twilio/Meta WhatsApp. Drizzle delivery log; Express send + webhooks.
      Load comms-core + comms-adapters; docs/vendors.md for driver pick. Pair with jwt-auth
      for magic-link session minting, not message transport.
    packages:
      - name: "@eristack/comms"
        skills:
          - comms-core
          - comms-adapters
        role: primary

  - id: payment-gateway-stripe-xendit
    title: Stripe, Xendit, and payment intents
    priority: 17
    triggers:
      - stripe
      - xendit
      - payment intent
      - payment gateway
      - checkout webhook
      - capture payment
      - online payment
    rationale: >
      Use @eristack/payment-manager for intents, webhooks, and Drizzle history with
      Stripe/Xendit drivers. Amounts via @eristack/money; saved cards via payment-instrument.
      Load payment-manager-core + payment-manager-adapters — docs/getting-started.md only.
    packages:
      - name: "@eristack/payment-manager"
        skills:
          - payment-manager-core
          - payment-manager-adapters
        role: primary
      - name: "@eristack/payment-instrument"
        skills:
          - payment-instrument-core
        role: companion
      - name: "@eristack/money"
        skills:
          - money-amounts
        role: companion

  - id: payment-instrument-token
    title: Saved cards and payment method tokens
    priority: 16
    triggers:
      - saved card
      - payment method
      - credit card token
      - debit card
      - store card
      - card on file
      - pci token
    rationale: >
      Use @eristack/payment-instrument for token-safe display + gateway refs in Postgres.
      Never store PAN/CVV. Load payment-instrument-core; pair with payment-manager-core
      when wiring Stripe/Xendit checkout.
    packages:
      - name: "@eristack/payment-instrument"
        skills:
          - payment-instrument-core
        role: primary

  - id: unlocode-ports
    title: UN/LOCODE ports and trade locations
    priority: 15
    triggers:
      - unlocode
      - locode
      - port code
      - port of loading
      - port of discharge
      - pol pod
      - bill of lading port
      - forwarding port
    rationale: >
      Use @eristack/unlocode with @eristack/iso-3166 for five-character locodes on
      B/L and logistics docs. Load unlocode-core — docs/getting-started.md only.
    packages:
      - name: "@eristack/unlocode"
        skills:
          - unlocode-core
        role: primary
      - name: "@eristack/iso-3166"
        skills:
          - iso-3166-core
        role: supporting

  - id: country-codes-iso-3166
    title: Country codes and ISO 3166 validation
    priority: 15
    triggers:
      - country code
      - iso 3166
      - iso country
      - alpha-2
      - alpha-3
      - subdivision code
      - region code
      - validate country
    rationale: >
      Use @eristack/iso-3166 for assigned ISO 3166-1 alpha-2/alpha-3 and ISO 3166-2
      subdivision format. Pair with @eristack/address for postal shape. Load
      iso-3166-core — docs/getting-started.md only.
    packages:
      - name: "@eristack/iso-3166"
        skills:
          - iso-3166-core
        role: primary

  - id: indonesia-admin-divisions
    title: Indonesia administrative division codes
    priority: 15
    triggers:
      - indonesia province
      - indonesia regency
      - kabupaten
      - kecamatan
      - desa
      - kelurahan
      - kode wilayah
      - wilayah administrasi
      - admin division indonesia
      - indonesia village code
      - rw rt indonesia
      - dusun
    rationale: >
      Use @eristack/id-wilayah for official 2/4/7/10-digit admin codes, bundled
      village registry, and English unit kinds through hamlet/community block/neighborhood.
      Pair with iso-3166 for country ID. Load id-wilayah-core — getting-started only.
    packages:
      - name: "@eristack/id-wilayah"
        skills:
          - id-wilayah-core
        role: primary
      - name: "@eristack/iso-3166"
        skills:
          - iso-3166-core
        role: supporting

  - id: file-upload-s3
    title: File uploads, S3, and presigned URLs
    priority: 16
    triggers:
      - file upload
      - upload file
      - s3 upload
      - presigned url
      - presign
      - object storage
      - attachment
      - file manager
      - blob storage
      - avatar upload
      - image preview
      - presigned download
      - inline file url
      - content disposition
      - img src s3
    rationale: >
      Use @eristack/file-manager for S3 presigned browser PUT, server uploads,
      FileRef JSON or fileId on Drizzle rows, and Express /files routes.
      resolveDownloadUrl(fileId) is inline by default (img/iframe/video); pass
      downloadFilename only for Save-as attachment. Load file-manager-core then
      file-manager-adapters — docs/getting-started.md only.
    packages:
      - name: "@eristack/file-manager"
        skills:
          - file-manager-core
          - file-manager-adapters
        role: primary

  - id: package-relationships-map
    title: Package dependency map and load order
    priority: 4
    triggers:
      - package dependencies
      - package relationships
      - eristack dependency graph
      - debottleneck
      - which package owns
      - compose erp stack
    rationale: >
      Load @eristack/ai-knowledge#package-relationships and read knowledge/package-relationships.md
      only — layers, peers, ERP vs HTTP vs ledger stacks, Horizon A bootstrap. Use before
      wiring many @eristack/* packages or when recipes overlap.
    canonicalSkills:
      - "@eristack/ai-knowledge#package-relationships"
    packages:
      - name: "@eristack/backseat"
        skills:
          - backseat-core
        role: supporting

  - id: eristack-upgrade
    title: Upgrade @eristack dependencies
    priority: 6
    triggers:
      - upgrade eristack
      - bump eristack
      - update @eristack
      - new version
      - changelog
      - outdated packages
      - what changed
      - migration guide
      - semver peer
    rationale: >
      Consumer upgrades: load @eristack/ai-knowledge#upgrading-eristack and read knowledge/upgrading.md
      only (full Backseat matrix, peers, Changesets). pnpm outdated '@eristack/*', site /{slug}/changelog.
      Do not open per-package docs/backseat.md for upgrade scope.
    packages:
      - name: "@eristack/backseat"
        skills:
          - backseat-core
        role: primary

  - id: backseat-mock-backend
    title: Frontend mock REST backend for prototypes
    priority: 8
    triggers:
      - mock api
      - fake backend
      - frontend backend
      - prototype api
      - storybook api
      - msw alternative
      - json-server browser
      - in-browser api
      - backseat
      - indexeddb api
      - store atomic
      - atomic transaction backseat
      - listRoutes
    rationale: >
      Browser prototypes: load @eristack/ai-knowledge#upgrading-eristack and read knowledge/upgrading.md
      §3 only (full spine matrix, bootstrap, peers). @eristack/backseat engine + eleven ./backseat
      adapters. Optional peer ^0.1.0. Not production — Drizzle + HTTP for real apps. Alpha infra —
      see repo roadmap/horizon.md.
    packages:
      - name: "@eristack/backseat"
        skills:
          - backseat-core
        role: primary
      - name: "@eristack/jwt-auth"
        skills:
          - jwt-auth-adapters
        role: supporting
      - name: "@eristack/doc-number"
        skills:
          - doc-number-adapters
        role: supporting

  - id: backseat-then-backend
    title: Backseat-first ERP mockup, then derive backend
    priority: 7
    triggers:
      - backseat first
      - mockup then backend
      - derive backend
      - horizon a
      - horizon b
      - job order erp
      - cost sheet erp
      - forwarding erp
      - document erp mockup
      - service erp prototype
      - erp mockup
      - clickable prototype erp
    rationale: >
      Document/cost-sheet ERPs: load @eristack/ai-knowledge#backseat-then-backend
      and read knowledge/backseat-then-backend.md only. Horizon A — Backseat +
      qups + money + doc-number + data-grid wall lists + rbac/abac/pbac + epoch.
      Horizon B — same paths on Drizzle/Express (upgrading-eristack §3). Do not
      default to stock-movement, valuations, or financial-ledger for job/invoice products.
    canonicalSkills:
      - "@eristack/ai-knowledge#backseat-then-backend"
    packages:
      - name: "@eristack/backseat"
        skills:
          - backseat-core
        role: primary
      - name: "@eristack/qups"
        skills:
          - qups-line
        role: supporting
      - name: "@eristack/data-grid"
        skills:
          - data-grid-core
        role: supporting
      - name: "@eristack/jwt-auth"
        skills:
          - jwt-auth-adapters
        role: supporting

  - id: tiga-sekawan-3ss-adopt
    title: Adopt 3ss platform seams in a document-lines consumer app
    priority: 20
    triggers:
      - tiga sekawan adoption
      - 3ss consumer
      - platform seams adopt
      - replace busy.tsx eristack
    rationale: >
      After business-libs 3ss release — load @eristack/ai-knowledge#tiga-sekawan-3ss-adoption only.
      Maps rows A1–B11 to packages and consumer file paths; no new library work.
    canonicalSkills:
      - "@eristack/ai-knowledge#tiga-sekawan-3ss-adoption"
    packages: []

  - id: erp-collection-declaration
    title: ERP collection manifest for Backseat and Drizzle (Horizon B)
    priority: 21
    triggers:
      - collection declaration
      - defineErpCollection
      - backseat drizzle same collection
      - routes snapshot mirror
      - horizon b collection
    rationale: >
      defineErpCollection + #collection-declaration-horizon-b + @eristack/backseat/testing
      mirror smoke. Codegen later.
    canonicalSkills:
      - "@eristack/ai-knowledge#collection-declaration-horizon-b"
    packages:
      - name: "@eristack/drizzle"
        skills:
          - drizzle-core
        role: primary
      - name: "@eristack/backseat"
        skills:
          - backseat-core
        role: supporting

  - id: drizzle-open-app-database
    title: Open Drizzle once at app compose (sqlite or Postgres)
    priority: 19
    triggers:
      - open drizzle
      - createAppDatabase
      - APP_DB_DIALECT
      - drizzle app boot
      - database url postgres pool
    rationale: >
      openDrizzle + @eristack/drizzle/schema spine/columns + #drizzle-app-database.
      Table packages never open pools.
    canonicalSkills:
      - "@eristack/ai-knowledge#drizzle-app-database"
      - "@eristack/drizzle#drizzle-core"
    packages:
      - name: "@eristack/drizzle"
        skills:
          - drizzle-core
        role: primary
      - name: "@eristack/drizzle-kit-helpers"
        skills:
          - drizzle-kit-helpers-core
        role: supporting

  - id: print-layout-default-document
    title: Print layout company default vs frozen document mask
    priority: 18
    triggers:
      - print settings
      - print layout
      - shipment fields on invoice
      - ar print
      - print tax codes
      - frozen print mask
    rationale: >
      app-owned company print singleton + nullable document mask. Load
      @eristack/ai-knowledge#print-layout-default and knowledge/print-layout-default-vs-document.md only.
    canonicalSkills:
      - "@eristack/ai-knowledge#print-layout-default"
    packages: []

  - id: document-lines-erp
    title: Document-with-lines ERP (job, cost sheet, invoice)
    priority: 7
    triggers:
      - document with lines
      - document lines erp
      - job order
      - cost sheet
      - forwarding
      - freight
      - shipment
      - bill of lading
      - commercial invoice
      - service erp
      - logistics erp
      - partner master
    rationale: >
      Header + QUPS lines products: load @eristack/ai-knowledge#document-lines-erp
      and read knowledge/document-lines-erp.md only. qups + money + doc-number +
      data-grid + pbac + backseat — not stock-movement/valuations/financial-ledger.
      Partner/product masters app-owned — do not invent @eristack/feature-* packages.
    canonicalSkills:
      - "@eristack/ai-knowledge#document-lines-erp"
    packages:
      - name: "@eristack/qups"
        skills:
          - qups-line
        role: primary
      - name: "@eristack/pbac"
        skills:
          - pbac-core
        role: primary
      - name: "@eristack/doc-number"
        skills:
          - doc-number-core
        role: supporting
      - name: "@eristack/data-grid"
        skills:
          - data-grid-core
        role: supporting
      - name: "@eristack/backseat"
        skills:
          - backseat-core
        role: supporting

  - id: optimistic-document-version
    title: Optimistic document version (expectedVersion)
    priority: 10
    triggers:
      - optimistic locking
      - expected version
      - conflict version
      - concurrent edit
      - document version
      - write conflict
      - 409 version
    rationale: >
      ERP aggregates: load @eristack/ai-knowledge#optimistic-document-version
      and read knowledge/optimistic-document-version.md. version + expectedVersion
      on PATCH; 409 CONFLICT_VERSION via @eristack/backseat jsonError — distinct from epoch.
    canonicalSkills:
      - "@eristack/ai-knowledge#optimistic-document-version"
    packages:
      - name: "@eristack/backseat"
        skills:
          - backseat-core
        role: primary

  - id: http-errors
    title: HTTP 409 error envelope (version, policy, epoch)
    priority: 11
    triggers:
      - "409"
      - policy denied
      - stale epoch
      - json error
      - error envelope
      - version conflict
      - business policy denied
    rationale: >
      Unified JSON error canon: CONFLICT_VERSION, POLICY_DENIED, BUSINESS_POLICY_DENIED,
      STALE_EPOCH. Load @eristack/ai-knowledge#http-errors and knowledge/http-errors.md.
      Backseat jsonError/versionConflict; Express mapDomainError; distinct from epoch vs document version.
    canonicalSkills:
      - "@eristack/ai-knowledge#http-errors"
    packages:
      - name: "@eristack/backseat"
        skills:
          - backseat-core
        role: primary
      - name: "@eristack/epoch"
        skills:
          - epoch-core
        role: supporting

  - id: multitab-workspace
    title: Multi-document ERP tab workspace
    priority: 9
    triggers:
      - multitab
      - multi tab
      - document tabs
      - erp tabs
      - tab workspace
      - workspace tabs
      - open in tab
      - browser tabs erp
    rationale: >
      Use @eristack/multitab for headless ERP tab chrome: pathname-keyed route tabs,
      /new/{uuid} placeholders, adjacent insert, localStorage persistence, closeGuard,
      and MultitabRouterProvider for TanStack Router (URL is source of truth). App owns
      tab bar UI and keyboard shortcuts. Alpha infra — see repo roadmap/horizon.md.
    packages:
      - name: "@eristack/multitab"
        skills:
          - multitab-core
        role: primary

  - id: structured-logging
    title: JSON-lines request logging
    priority: 10
    triggers:
      - logger
      - logging
      - structured log
      - json log
      - request id log
      - vercel logs
      - log drain
    rationale: >
      Use @eristack/logger for JSON-lines server logging with injectable requestId,
      userId, and tenantId context. Express: createLoggerMiddleware. Nest:
      LoggerModule.forRoot + LoggingInterceptor. Alpha infra — see repo roadmap/horizon.md.
    packages:
      - name: "@eristack/logger"
        skills:
          - logger-core
        role: primary

  - id: declarative-rest-routes
    title: Declarative REST route shell
    priority: 10
    triggers:
      - rest routes
      - declarative rest
      - openapi emit
      - express route table
      - nest route module
    rationale: >
      Use @eristack/rest to define HTTP routes as data, mount on Express or Nest,
      and emit minimal OpenAPI 3.1 paths. Compose with jwt-auth guards and
      data-grid list handlers in app modules.
    packages:
      - name: "@eristack/rest"
        skills:
          - rest-core
        role: primary

  - id: access-control-stack
    title: Roles, attribute limits, and document policies
    priority: 12
    triggers:
      - rbac
      - abac
      - pbac
      - role based
      - roles
      - permissions
      - permission
      - access control
      - authorization
      - can user
      - attribute policy
      - business policy
      - goods receipt limit
      - book value limit
      - documents.transitions
      - assignmentPairMatch
      - document transition
    rationale: >
      Use @eristack/rbac for boolean role permissions, @eristack/abac for
      attribute policies (e.g. max book value), and @eristack/pbac for document
      software policies (e.g. PO outstanding > 0). Pair with jwt-auth for identity.
    packages:
      - name: "@eristack/rbac"
        skills:
          - rbac-core
          - rbac-adapters
        role: primary
      - name: "@eristack/abac"
        skills:
          - abac-core
          - abac-adapters
        role: primary
      - name: "@eristack/pbac"
        skills:
          - pbac-core
          - pbac-adapters
        role: primary
      - name: "@eristack/jwt-auth"
        skills:
          - jwt-auth-core
        role: supporting

  - id: document-status-transitions
    title: Preset ERP document status graphs
    priority: 14
    triggers:
      - status transition
      - publication workflow
      - journal post void
      - document status preset
      - doc-transitions
      - publicationGraph
      - journalGraph
    rationale: >
      Load @eristack/doc-transitions#doc-transitions-core for preset status
      graphs wired to @eristack/pbac documents.transitions() — not copy-paste tables.
    packages:
      - name: "@eristack/doc-transitions"
        skills:
          - doc-transitions-core
        role: primary
      - name: "@eristack/pbac"
        skills:
          - pbac-core
        role: supporting

  - id: opinion-http
    title: Opinionated ERP HTTP document routes
    priority: 15
    triggers:
      - opinion http
      - patch action route
      - erp rest canon
      - document api scaffold
      - PATCH /:id/:action
    rationale: >
      Use @eristack/opinion for the canonical document REST map (options,
      data-grid, CRUD, PATCH /:id/:action) mounted via @eristack/rest.
    packages:
      - name: "@eristack/opinion"
        skills:
          - opinion-core
        role: primary
      - name: "@eristack/rest"
        skills:
          - rest-core
        role: supporting
      - name: "@eristack/doc-transitions"
        skills:
          - doc-transitions-core
        role: supporting

  - id: uom-quantity-conversion
    title: Unit of measure conversion for inventory qty
    priority: 16
    triggers:
      - uom
      - unit of measure
      - convert kg
      - inventory uom
      - stock uom
      - receive uom
      - alternate uom
    rationale: >
      Load @eristack/uom#uom-core for string qty + fixed-ratio conversion (kg/g/L/pcs)
      before qups or stock-movement — not float math or hand-rolled factors.
    packages:
      - name: "@eristack/uom"
        skills:
          - uom-core
        role: primary

  - id: percent-rates-basis-points
    title: Tax and discount rates as ratios or basis points
    priority: 17
    triggers:
      - basis points
      - bps
      - tax rate
      - discount rate
      - markup rate
      - ratio string
    rationale: >
      Load @eristack/percent#percent-core for ratio/bps parsing and percentOf on strings;
      round with @eristack/money at ledger boundaries.
    packages:
      - name: "@eristack/percent"
        skills:
          - percent-core
        role: primary
      - name: "@eristack/money"
        skills:
          - money-amounts
        role: supporting

  - id: fraction-exact-rational
    title: Exact rationals as fractions (recipe yields, BOM ratios)
    priority: 18
    triggers:
      - fraction
      - rational number
      - numerator denominator
      - recipe yield
      - bom ratio
      - parts ratio
      - irrational approximation
      - sqrt approximation
    rationale: >
      Load @eristack/fraction#fraction-core for exact num/den arithmetic; approximateFraction
      for decimals/irrationals with maxDenominator — not @eristack/percent for VAT rates.
    packages:
      - name: "@eristack/fraction"
        skills:
          - fraction-core
        role: primary

  - id: household-ledger
    title: Household cashbook / ledger-first spine
    priority: 11
    triggers:
      - household ledger
      - cashbook
      - personal finance
      - household accounts
      - journal posting
      - general ledger cashbook
    rationale: >
      Load @eristack/ai-knowledge#ledger-first and read knowledge/ledger-first.md only.
      financial-ledger + money + timestamp + fiscal-calendar + epoch — not qups or document-lines-erp.
    canonicalSkills:
      - "@eristack/ai-knowledge#ledger-first"
    packages:
      - name: "@eristack/financial-ledger"
        skills:
          - financial-ledger-core
        role: primary
      - name: "@eristack/money"
        skills:
          - money-ledger
        role: supporting
      - name: "@eristack/timestamp"
        skills:
          - timestamp-core
        role: supporting
      - name: "@eristack/fiscal-calendar"
        skills:
          - fiscal-calendar-core
        role: supporting
      - name: "@eristack/epoch"
        skills:
          - epoch-core
        role: supporting

  - id: fiscal-period-posting
    title: Fiscal period open/closed for journal dates
    priority: 18
    triggers:
      - fiscal period
      - fiscal year
      - period close
      - posting period
      - closed period
    rationale: >
      Load @eristack/fiscal-calendar#fiscal-calendar-core for findPeriodForDate(calendar, wallClock)
      then assertPeriodOpen(period) on @eristack/timestamp wall dates — pair with doc-transitions lockGraph.
    packages:
      - name: "@eristack/fiscal-calendar"
        skills:
          - fiscal-calendar-core
        role: primary
      - name: "@eristack/timestamp"
        skills:
          - timestamp-core
        role: supporting
      - name: "@eristack/doc-transitions"
        skills:
          - doc-transitions-core
        role: supporting

  - id: postal-address-normalize
    title: Normalize and format postal addresses
    priority: 19
    triggers:
      - address
      - postal address
      - shipping address
      - billing address format
      - partner address
    rationale: >
      Load @eristack/address#address-core for PostalAddress normalize/format and ISO
      country codes — app owns partner tables and geocoding.
    packages:
      - name: "@eristack/address"
        skills:
          - address-core
        role: primary

  - id: stock-inventory-ledger
    title: Inventory stock movements by location and lot
    priority: 28
    triggers:
      - stock
      - inventory
      - warehouse
      - lot
      - stock movement
      - goods receipt
      - goods issue
      - on hand
    rationale: >
      Use @eristack/stock-movement on @eristack/hash-chained-ledger for qty
      ledgers with composable locations, lots, snapshots, and tamper checks.
    packages:
      - name: "@eristack/stock-movement"
        skills:
          - stock-movement-core
          - stock-movement-adapters
        role: primary
      - name: "@eristack/hash-chained-ledger"
        skills:
          - hash-chained-ledger-core
        role: supporting

  - id: financial-gl-ledger
    title: Financial / GL account ledger
    priority: 29
    triggers:
      - general ledger
      - gl
      - chart of accounts
      - account balance
      - journal entry
      - financial ledger
    rationale: >
      Use @eristack/financial-ledger for accountId+currency hash-chained
      balances with @eristack/money amounts.
    packages:
      - name: "@eristack/financial-ledger"
        skills:
          - financial-ledger-core
          - financial-ledger-adapters
        role: primary
      - name: "@eristack/hash-chained-ledger"
        skills:
          - hash-chained-ledger-core
        role: supporting
      - name: "@eristack/money"
        skills:
          - money-amounts
        role: supporting

  - id: inventory-valuation
    title: FIFO, average, and other inventory valuations
    priority: 30
    triggers:
      - fifo
      - lifo
      - fefo
      - moving average
      - weighted average
      - standard cost
      - inventory valuation
      - costing
      - cost layers
    rationale: >
      Use @eristack/valuations for canon costing methods with qty+value
      hash-chained ledgers.
    packages:
      - name: "@eristack/valuations"
        skills:
          - valuations-core
          - valuations-adapters
        role: primary
      - name: "@eristack/hash-chained-ledger"
        skills:
          - hash-chained-ledger-core
        role: supporting

  - id: compose-spine
    title: Compose business spine (auth, lines, lists, optional ledgers)
    priority: 9
    triggers:
      - compose erp modules
      - which eristack packages
      - erp module map
      - purchase order
      - sales order
      - work order
      - bill of materials
    rationale: >
      No @eristack/feature-* vertical packages — apps own document families.
      Read @eristack/ai-knowledge#package-relationships (knowledge/package-relationships.md)
      for the dependency map. Implement header + QUPS lines via #document-lines-erp or
      #backseat-then-backend — not this recipe alone. Default compose: qups, doc-number,
      pbac, data-grid, jwt-auth; add stock-movement, financial-ledger, valuations only
      when inventory or GL is explicitly in scope.
    canonicalSkills:
      - "@eristack/ai-knowledge#package-relationships"
    packages:
      - name: "@eristack/qups"
        skills:
          - qups-core
          - qups-line
        role: primary
      - name: "@eristack/pbac"
        skills:
          - pbac-core
        role: primary
      - name: "@eristack/doc-number"
        skills:
          - doc-number-core
        role: supporting
      - name: "@eristack/data-grid"
        skills:
          - data-grid-core
        role: supporting
      - name: "@eristack/jwt-auth"
        skills:
          - jwt-auth-core
        role: supporting

  - id: hash-chain-audit
    title: Audit trail and tamper-evident ledger
    priority: 25
    triggers:
      - audit trail
      - tamper
      - tamper detection
      - tamper-evident
      - hash chain
      - append-only ledger
      - immutable log
    rationale: >
      Use @eristack/hash-chained-ledger for SHA-256 chained append-only entries.
      Stock, financial, and valuation packages compose this primitive in production.
    packages:
      - name: "@eristack/hash-chained-ledger"
        skills:
          - hash-chained-ledger-core
        role: primary

  - id: ai-workflow-memory
    title: Sprint backlog and local project memory
    priority: 12
    triggers:
      - sprint
      - backlog
      - adr
      - project memory
      - mcp workflow
      - eristack workflow
      - .eristack/workflow
    rationale: >
      Use @eristack/ai-workflow for local MCP, FTS+vector index, and sprint/backlog
      folders under .eristack/workflow — complements Intent, does not replace git.
    packages:
      - name: "@eristack/ai-workflow"
        skills:
          - ai-workflow-core
        role: primary

  - id: ai-dev-tooling
    title: Monorepo plan, check profiles, and dev MCP
    priority: 11
    triggers:
      - eristack plan
      - dev tooling
      - monorepo check
      - ci profile
      - pnpm ci
      - dev mcp
      - check profile
      - token minimal check
    rationale: >
      Use @eristack/ai-dev before chaining scripts: eristack plan --json for minimal
      next steps, eristack check --profile pr for CI parity, eristack-mcp for dev_plan/dev_check.
    packages:
      - name: "@eristack/ai-dev"
        skills:
          - ai-dev-core
        role: primary

  - id: maintainer-tickets
    title: Bug reports and feature suggestions for maintainers
    priority: 15
    triggers:
      - bug report
      - bug ticket
      - support ticket
      - feature request
      - feature suggestion
      - maintainer ticket
      - fixer upper
      - report a bug
      - suggest a feature
      - eristack ticket
    rationale: >
      Use @eristack/ai-ticket-generator to produce a portable markdown ticket
      (logs/scenario/fix plan or feasibility-gated suggestion) the user can
      send to maintainers for an agent fixer-upper. Every package has ticket.yaml.
    packages:
      - name: "@eristack/ai-ticket-generator"
        skills:
          - ai-ticket-bug
          - ai-ticket-suggest
        role: primary

  - id: checksum-export-integrity
    title: Export file SHA-256 checksum
    priority: 14
    triggers:
      - checksum
      - sha256 export
      - file digest
      - export integrity
    rationale: >
      @eristack/checksum sha256Hex and checksumEquals for download/export verification;
      pair with @eristack/file-manager metadata in the app.
    packages:
      - name: "@eristack/checksum"
        skills:
          - checksum-core
        role: primary

  - id: currency-pair-fx-key
    title: FX currency pair keys (no rates)
    priority: 14
    triggers:
      - currency pair
      - base quote
      - fx pair
      - USD/IDR
    rationale: >
      @eristack/currency-pair validates ISO codes via @eristack/money — formatPairKey for
      rate table PKs until fx-table ships.
    packages:
      - name: "@eristack/currency-pair"
        skills:
          - currency-pair-core
        role: primary

  - id: geo-distance-logistics
    title: Geo coordinates and distance (km)
    priority: 14
    triggers:
      - geo point
      - latitude longitude
      - haversine
      - depot radius
      - distance km
    rationale: >
      Use @eristack/geo for lat/lng decimal strings and geoDistanceKm. Geocode in the app;
      postal addresses stay on @eristack/address.
    packages:
      - name: "@eristack/geo"
        skills:
          - geo-core
        role: primary

  - id: dimension-logistics
    title: Carton and item dimensions (L×W×H)
    priority: 14
    triggers:
      - dimension
      - l x w x h
      - carton size
      - cubic volume
      - package dimensions
    rationale: >
      Use @eristack/dimension for length/width/height decimal strings and dimensionVolume.
      Optional unit label — validate units with @eristack/uom in the app.
    packages:
      - name: "@eristack/dimension"
        skills:
          - dimension-core
        role: primary

  - id: entity-id-v7-primary-key
    title: UUID v7 sortable primary keys
    priority: 13
    triggers:
      - entity id
      - entity-id
      - uuid v7
      - uuidv7
      - sortable primary key
      - primary key uuid
    rationale: >
      Use @eristack/entity-id for RFC 9562 UUID v7 generate/parse, Drizzle entityIdColumn,
      and zod entityIdSchema — not ad hoc uuid v4 or serial ids on app-facing tables.
    packages:
      - name: "@eristack/entity-id"
        skills:
          - entity-id-core
        role: primary

  - id: party-and-platform-compose
    title: Wave 13 party, platform, and finance compose
    priority: 8
    triggers:
      - wave 13 compose
      - wave 13 platform
      - party platform compose
      - compose at boundary
      - one package per pr wave 13
      - party contact
      - normalize contact
      - business calendar
      - working days
      - api key middleware
      - rate limit middleware
      - email template render
      - spreadsheet export
      - checksum export
      - health readiness
      - drizzle kit helper
    rationale: >
      Approved Wave 13 pipelines compose at the app boundary without sibling hard deps.
      Load @eristack/ai-knowledge#party-and-platform-compose and read
      knowledge/party-and-platform-compose.md — ship one npm package per PR.
    canonicalSkills:
      - "@eristack/ai-knowledge#party-and-platform-compose"
    packages:
      - name: "@eristack/ai-knowledge"
        skills:
          - party-and-platform-compose
        role: primary

  - id: person-normalize
    title: Normalize person name and gender
    priority: 14
    triggers:
      - person name
      - normalize person
      - gender identity
      - contact name form
    rationale: >
      Use @eristack/person normalizePerson and formatPersonDisplay — app owns person rows.
    packages:
      - name: "@eristack/person"
        skills:
          - person-core
        role: primary

  - id: party-contact-normalize
    title: Normalize party contacts (person, phone, email)
    priority: 15
    triggers:
      - party normalize
      - contact list
      - primary contact
      - e.164
      - normalize email
    rationale: >
      Chain @eristack/person, phone, email-address, and contact at the API boundary.
      Handler order in #party-and-platform-compose.
    canonicalSkills:
      - "@eristack/ai-knowledge#party-and-platform-compose"
    packages:
      - name: "@eristack/contact"
        skills:
          - contact-core
        role: primary
      - name: "@eristack/person"
        skills:
          - person-core
        role: supporting
      - name: "@eristack/phone"
        skills:
          - phone-core
        role: supporting
      - name: "@eristack/email-address"
        skills:
          - email-address-core
        role: supporting

  - id: platform-api-guard
    title: B2B API edge (rate limit, API key, idempotency)
    priority: 16
    triggers:
      - platform api guard
      - partner api
      - b2b api
      - idempotency store
    rationale: >
      Load @eristack/ai-knowledge#idempotency-and-outbox — middleware order rate-limit → api-key
      → idempotency → handler; Drizzle idempotency store in prod (memory tests only).
    packages:
      - name: "@eristack/rate-limit"
        skills:
          - rate-limit-core
        role: primary
      - name: "@eristack/api-key"
        skills:
          - api-key-core
        role: supporting
      - name: "@eristack/idempotency"
        skills:
          - idempotency-core
        role: supporting

  - id: idempotency-http-replay
    title: HTTP Idempotency-Key replay (Drizzle + Express)
    priority: 15
    triggers:
      - idempotency key
      - replay post
      - duplicate payment post
      - idempotency middleware
    rationale: >
      Load @eristack/ai-knowledge#idempotency-and-outbox — Drizzle store, scoped runScoped,
      wrapIdempotentHandler; memory store unit tests only.
    packages:
      - name: "@eristack/idempotency"
        skills:
          - idempotency-adapters
        role: primary

  - id: ledger-idempotent-append
    title: Idempotent ledger append (stock, GL, valuations)
    priority: 14
    triggers:
      - duplicate goods receipt
      - ledger retry
      - idempotent append
    rationale: >
      Load @eristack/ai-knowledge#idempotency-and-outbox — hash-chained-ledger idempotencyKey;
      stock-movement, financial-ledger, valuations pass keys through.
    packages:
      - name: "@eristack/hash-chained-ledger"
        skills:
          - hash-chained-ledger-core
        role: primary

  - id: reliable-side-effects-outbox
    title: Outbox for comms and payment side effects
    priority: 14
    triggers:
      - transactional outbox
      - reliable email
      - po confirmation email
    rationale: >
      Load @eristack/ai-knowledge#idempotency-and-outbox — @eristack/outbox enqueue in TX;
      comms/payment claim-before-vendor; derived idempotency keys in workers.
    packages:
      - name: "@eristack/outbox"
        skills:
          - outbox-core
        role: primary

  - id: api-key-partner-auth
    title: Partner API key verify
    priority: 15
    triggers:
      - api key hash
      - partner b2b key
      - verify api key
    rationale: >
      @eristack/api-key generateApiKey, hashApiKey, verifyApiKey with optional pepper —
      persist hash in Drizzle; show raw key once.
    packages:
      - name: "@eristack/api-key"
        skills:
          - api-key-core
        role: primary

  - id: rate-limit-edge
    title: Fixed-window rate limit
    priority: 15
    triggers:
      - rate limit
      - throttle api
      - too many requests
    rationale: >
      @eristack/rate-limit createRateLimiter — memory for tests/dev; Redis at app edge in prod.
    packages:
      - name: "@eristack/rate-limit"
        skills:
          - rate-limit-core
        role: primary

  - id: pdf-render-invoice
    title: HTML to PDF (driver)
    priority: 20
    triggers:
      - html to pdf
      - invoice pdf
      - pdf render driver
    rationale: >
      @eristack/pdf-render createPdfRenderer(driver) — stub for tests; Puppeteer/Playwright in app.
    packages:
      - name: "@eristack/pdf-render"
        skills:
          - pdf-render-core
        role: primary

  - id: posting-date-guard
    title: Posting date, fiscal period, and business days
    priority: 17
    triggers:
      - posting date
      - business day
      - holiday calendar
      - period closed
      - fiscal period post
    rationale: >
      Compose @eristack/fiscal-calendar and @eristack/business-calendar with timestamp wall
      dates at the app boundary. Load #party-and-platform-compose (finance pipeline).
    canonicalSkills:
      - "@eristack/ai-knowledge#party-and-platform-compose"
    packages:
      - name: "@eristack/ai-knowledge"
        skills:
          - party-and-platform-compose
        role: primary
      - name: "@eristack/business-calendar"
        skills:
          - business-calendar-core
        role: secondary
      - name: "@eristack/fiscal-calendar"
        skills:
          - fiscal-calendar-core
        role: secondary

  - id: invoice-line-tax
    title: Tax codes and line tax with qups
    priority: 18
    triggers:
      - tax code
      - tax rate effective date
      - line tax
      - vat rate
      - sales tax rate
    rationale: >
      @eristack/tax createTaxRegistry() → registry.resolveTaxRate({ code, asOf }) +
      registry.applyTaxToAmount(net, ratePercent) (unrounded tax portion); @eristack/qups line math;
      @eristack/money Tax ops.
    packages:
      - name: "@eristack/tax"
        skills:
          - tax-core
        role: primary
      - name: "@eristack/qups"
        skills:
          - qups-line
        role: supporting
      - name: "@eristack/money"
        skills:
          - money-amounts
        role: supporting

  - id: ledger-rounding-policy
    title: Company rounding policy at ledger boundary
    priority: 17
    triggers:
      - rounding policy
      - company rounding
      - ledger rounding
      - half even policy
    rationale: >
      @eristack/rounding-policy createRoundingPolicyRegistry() → registry.roundingFor({ policyId, currency })
      → money.with at post time; pair with tax and qups totals.
    packages:
      - name: "@eristack/rounding-policy"
        skills:
          - rounding-policy-core
        role: primary
      - name: "@eristack/money"
        skills:
          - money-ledger
        role: supporting

  - id: email-template-render
    title: "Render {{var}} email bodies"
    priority: 15
    triggers:
      - email template
      - mail merge
      - template variables
      - render email body
      - "{{var}} email"
    rationale: >
      @eristack/email-template renderEmailTemplate and extractTemplateKeys — HTML escape
      for HTML parts; send via @eristack/comms in the app.
    packages:
      - name: "@eristack/email-template"
        skills:
          - email-template-core
        role: primary

  - id: outbound-message-render
    title: Outbound email (template, comms, optional PDF)
    priority: 21
    triggers:
      - outbound email
      - transactional email render
      - invoice email pdf
      - message render pipeline
    rationale: >
      App pipeline: email-template → comms send; optional pdf-render attachment.
      Load @eristack/ai-knowledge#party-and-platform-compose for compose rules.
    canonicalSkills:
      - "@eristack/ai-knowledge#party-and-platform-compose"
    packages:
      - name: "@eristack/email-template"
        skills:
          - email-template-core
        role: primary

  - id: spreadsheet-keyboard-operator
    title: Spreadsheet keyboard navigation for in-browser grids
    priority: 15
    triggers:
      - spreadsheet keyboard
      - excel like grid
      - arrow keys table
      - active cell
      - enter commit cell
      - cost sheet keyboard
      - spreadsheet operator
      - two grids keyboard
    rationale: >
      Load @eristack/spreadsheet-operator#spreadsheet-operator-core then /react adapters.
      Not spreadsheet-render (xlsx export) and not data-grid (HTTP lists). Commit → patchLine.
    packages:
      - name: "@eristack/spreadsheet-operator"
        skills:
          - spreadsheet-operator-core
          - spreadsheet-operator-adapters
        role: primary

  - id: spreadsheet-export-download
    title: Export list rows to xlsx or csv
    priority: 22
    triggers:
      - export xlsx
      - export csv
      - spreadsheet download
      - excel export
      - download list excel
    rationale: >
      App maps data-grid list rows to string cells, then @eristack/spreadsheet-render driver.
      Optional @eristack/checksum for file-manager downloads.
    packages:
      - name: "@eristack/spreadsheet-render"
        skills:
          - spreadsheet-render-core
        role: primary

  - id: health-readiness
    title: Liveness and readiness HTTP
    priority: 19
    triggers:
      - health check
      - readiness probe
      - liveness probe
      - k8s health
    rationale: >
      @eristack/health createHealthRegistry + express/nest handlers — app registers Drizzle ping checks.
    packages:
      - name: "@eristack/health"
        skills:
          - health-core
        role: primary

  - id: local-monorepo-versioning
    title: Private monorepo versioning without Changesets
    priority: 14
    triggers:
      - version.lock.json
      - local monorepo versioning
      - private monorepo release
      - bump without changesets
      - product version lock
    rationale: >
      @eristack/local-monorepo-versioning planRelease + eristack-version CLI for deploy-only pnpm
      monorepos. Use Changesets (@eristack/ai-knowledge#dev-conventions) when publishing npm libraries.
    packages:
      - name: "@eristack/local-monorepo-versioning"
        skills:
          - local-monorepo-versioning-core
        role: primary

  - id: drizzle-kit-monorepo
    title: drizzle-kit config for Eristack apps
    priority: 12
    triggers:
      - drizzle kit config
      - drizzle migrate monorepo
      - sqlite test drizzle
    rationale: >
      @eristack/drizzle-kit-helpers defineEristackDrizzleConfig and pg/sqlite templates.
    packages:
      - name: "@eristack/drizzle-kit-helpers"
        skills:
          - drizzle-kit-helpers-core
        role: primary

  - id: vercel-express-deploy
    title: Deploy Express on Vercel serverless
    priority: 12
    triggers:
      - vercel express
      - serverless express handler
      - vercel adapter
    rationale: >
      @eristack/vercel-adapters createVercelExpressHandler — pair with @eristack/logger requestId.
    packages:
      - name: "@eristack/vercel-adapters"
        skills:
          - vercel-adapters-core
        role: primary

  - id: erp-ui-design-system
    title: Erista tokens and density
    priority: 18
    triggers:
      - design system
      - erista tokens
      - tailwind preset erp
      - density compact comfortable
    rationale: >
      Load @eristack/design-system#design-system-core — ERISTACK_CSS_VARS, tailwindPreset, DensityProvider.
    packages:
      - name: "@eristack/design-system"
        skills:
          - design-system-core
        role: primary

  - id: erp-ui-shell
    title: ERP React UI shell (lists, forms, docs)
    priority: 17
    triggers:
      - list page layout
      - document detail shell
      - money input react
      - qups line grid
      - command palette erp
      - filter builder data grid
    rationale: >
      UI stack: form-ui, list-shell, filter-builder, line-grid, spreadsheet-operator,
      doc-shell, policy-ui, master-detail, command-palette — load package skill getting-started per task.
    packages:
      - name: "@eristack/form-ui"
        skills:
          - form-ui-core
        role: primary
      - name: "@eristack/list-shell"
        skills:
          - list-shell-core
        role: supporting
      - name: "@eristack/line-grid"
        skills:
          - line-grid-core
        role: supporting
      - name: "@eristack/spreadsheet-operator"
        skills:
          - spreadsheet-operator-core
        role: supporting
      - name: "@eristack/doc-shell"
        skills:
          - doc-shell-core
        role: supporting

  - id: erp-list-and-doc-screens
    title: List and document ERP screens (canonical stack)
    priority: 16
    triggers:
      - erp list screen
      - erp document screen
      - ui package stack
      - load ui-package-stack
    canonicalSkills:
      - "@eristack/ai-knowledge#ui-package-stack"
    rationale: >
      One guide: knowledge/ui-package-stack.md — design-system through spreadsheet-operator; headless fields on money/percent/timestamp.
    packages:
      - name: "@eristack/ai-knowledge"
        skills:
          - ui-package-stack
        role: primary
