forge-app-review
Reviews Forge apps for security vulnerabilities, architecture issues, cost inefficiencies, performance problems, and trigger/scheduling waste before deployment. Use when the user says "review my Forge app", "check my app", "pre-deploy check", "is my app ready to deploy", "audit my Forge app", "check for security issues", "check performance", "review manifest", "check my Forge app for problems", "app review", "optimize my Forge app costs", "reduce invocations", "why is my app expensive", "check my triggers", or any request to evaluate a Forge app's quality, safety, cost efficiency, or readiness. Also triggers when users ask about Forge best practices, permission scopes, resolver optimization, storage efficiency, cold start reduction, frontend offloading, trigger filtering, scheduled trigger frequency, N+1 API calls, bulk API usage, verbose logging, or Forge platform pricing.
What this skill does
# Forge App Review Deep pre-deploy review of Forge apps across **Security**, **Architecture**, **Cost**, **Performance**, and **Triggers & Scheduling**. Produces a severity-sorted issue list with actionable fixes. ## Forge Pricing Reference Forge uses a consumption-based pricing model. Charges only apply above free monthly allowances. Use this table to assess cost impact of findings: | Capability | Billing Unit | Free Monthly Allowance | Overage Price (USD) | |-----------|-------------|----------------------|-------------------| | **Functions: Duration** | GB-seconds | 100,000 GB-seconds | $0.000025 / GB-second | | **KVS: Reads** | GB read | 0.1 GB | $0.055 / GB | | **KVS: Writes** | GB written | 0.1 GB | $1.090 / GB | | **Logs: Writes** | GB written | 1 GB | $1.005 / GB | | **SQL: Compute duration** | Hours | 1 hour | $0.143 / hour | | **SQL: Compute requests** | Per 1M requests | 100,000 requests | $1.929 / 1M requests | | **SQL: Data stored** | GB-hours | 730 GB-hours | $0.00076850 / GB-hour | **Key cost insight:** KVS writes are ~20× more expensive than reads. Logging is ~$1/GB over the free tier. The cost formula for functions is: **GB-seconds = (memoryMiB ÷ 1024) × duration in seconds**. **Free capabilities** (not billed): UI modules (UI Kit and Custom UI frontends run in the browser), Jira expressions, Forge Remote invocations (though the remote function runtime is billed), entity properties (stored by the product, not by Forge Storage). --- ## Execution Mandate When triggered, immediately: 1. Read `manifest.yml` — this is the source of truth for permissions, modules, egress, triggers, scheduled triggers, and function memory settings 2. Read `package.json` — check dependencies, versions, scripts 3. Scan all resolver files in `src/` — check patterns, error handling, data flow, API call patterns (N+1, missing fields, sequential calls), logging verbosity 4. Scan UI code (Custom UI or UI Kit) — check component patterns, bridge usage, whether API calls and logic could be moved to the frontend, product context usage, invoke patterns (chatty, per-render) 5. Check for Forge Storage / Entity Store usage patterns — TTL strategy, write frequency, query vs iteration, entity properties vs KVS 6. Check trigger and scheduling configuration — frequency, filtering, ignoreSelf, early exit, polling vs event-driven 7. Check for Forge Remote usage or opportunities — compute offloading, trade-offs 8. Compile all findings into a severity-sorted issue list Do NOT ask the user what to review. Review everything. Do NOT modify any code unless explicitly asked. Do NOT skip categories — even if the app looks clean, confirm it explicitly. --- ## Review Process ### Step 1: Manifest Analysis (`manifest.yml`) Read the manifest first. Extract: - **Permissions/scopes** — list all `scopes` and `permissions` entries - **Modules** — list all module types and their function key references - **Egress** — check `app.connect.remotes` or `permissions.external.fetch.backend` URLs - **Environment variables** — check for `app.storage` or environment variable declarations Cross-reference every `function` key in modules against actual resolver `resolver.define()` calls. ### Step 2: Dependencies (`package.json`) Check: - Node.js engine compatibility (Forge requires Node 18.x+) - Unnecessary large dependencies (e.g., `lodash` when only one function is used, `moment` instead of native Date or `dayjs`) - Missing `@forge/api`, `@forge/bridge`, or `@forge/ui` depending on app type - Dev dependencies leaking into production - Outdated `@forge/*` packages ### Step 3: Resolver Code Read all files that contain `resolver.define` or `Resolver` imports. Check for: - Error handling patterns - API call patterns (`requestJira`, `requestConfluence`, `api.asUser()`, `api.asApp()`) - Data validation and sanitization - Storage operations - External fetch calls ### Step 4: UI Code For **UI Kit** apps — scan for `@forge/react` imports, component usage, hooks. For **Custom UI** apps — scan for `@forge/bridge` usage, `invoke()` calls, CSP compliance. In both cases, check for: - **Frontend offloading opportunities**: Are there resolvers that only do read-only `requestJira()`/`requestConfluence()` calls that could instead use `@forge/bridge` directly from the browser? - **Product context via resolver**: Is the app invoking a resolver just to get issue/project/space key? Use `useProductContext()` (UI Kit) or `view.getContext()` (Custom UI) instead. - **Invoke on every render**: Is `invoke()` called without proper `useEffect` with empty dependency array, causing re-invocation on every render? - **Client-side logic**: Is data formatting, sorting, filtering, or validation done in a resolver when it could run in the browser for free? ### Step 5: Storage Analysis Search for usage of: - `storage.get`, `storage.set`, `storage.delete` — check for unnecessary writes, short TTLs (KVS writes are ~20× more expensive than reads), and missing caching patterns - `storage.query` (Entity Store) — check for proper use of indexes, `.where()`, and `.limit()` instead of fetching all items and filtering in code - Entity properties (`requestJira` to `/properties/`) — note these are **free** and stored by the product (not Forge Storage quota), suitable for small per-entity metadata (max 32 KB per property). Good for flags, markers, timestamps attached to Jira issues or Confluence pages. Queryable via JQL for Jira entity properties. **Not suitable for sensitive data** — visible to other apps and users via REST API. - Cache patterns — is app-level data that rarely changes (e.g., custom field IDs, project configs, workflow statuses) being fetched from APIs on every invocation? Should be cached in KVS with a TTL (1 hour+ preferred to minimize writes) - Write amplification — a 1-minute TTL cache with 100 calls/hour causes ~60 writes/hour; a 1-hour TTL causes ~1 write/hour at ~60× less cost ### Step 6: Trigger & Scheduling Analysis Check the manifest for `scheduledTrigger` and `trigger` modules: - **Scheduled triggers**: Is the interval appropriate? (`fiveMinutes` is rarely justified — prefer `hour`, `day`, or `week`) - **Polling vs events**: Is a scheduled trigger polling for changes that could be caught by a product event trigger? - **Event filtering**: Do product event triggers have `filter.expression` to limit invocations to relevant events? - **ignoreSelf**: If the app writes to entities and listens to events on those entities, is `filter.ignoreSelf: true` set? (Jira only) - **Early exit**: Do trigger handler functions check for work to do before running expensive operations? - **External polling**: Could scheduled triggers polling external services be replaced with web triggers? ### Step 7: Forge Remote Analysis Check if the app uses Forge Remote (`remotes:` section in manifest): - If present, note that Forge Remote offloads compute to an external backend — the Forge function is not executed for those calls, saving FaaS invocations. But the app loses "Runs on Atlassian" eligibility. - If not present, check whether the app would benefit from Forge Remote: - Compute-intensive operations (ML inference, image processing, complex report generation) - Long-running operations that approach the 25-second function timeout - Existing backend services the app duplicates logic from - Large-scale storage needs exceeding Forge Storage limits - Note: For most apps, staying on-platform is simpler. Only recommend Forge Remote when there's a genuine need. ### Step 8: Compile Findings Produce a single issue list sorted: **Critical → Warning → Info**. --- ## Security Checks | ID | Check | Severity | What to Look For | |----|-------|----------|-----------------| | SEC-01 | Overly broad scopes | Critical | `read:jira-work` when only `read:jira-work:jira` (granular) is needed. Any `write:` scope that isn't actually used in code. Any `manage:` or `admin:` scope. | | SEC-02 | Missing egress restrictions | Critical | Exte
Related in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.