First Class Modules

AI Insights

Runs permission-aware AI analysis in the background each day to create prioritized, evidence-backed insights and governed next actions from meaningful changes in authorized business records.

Open raw .md
Runtime key
module.ai-insights
Experience
Proactive daily findings
Security
Server-enforced

Use AI Insights when the system should look for important changes without waiting for a user to ask. The daily background cycle turns permitted record and knowledge context into a small, prioritized insight feed for the people entitled to see and act on it.

Note

The bundled renderer key is module.ai-insights. First-class means BuildWithHQ supplies a native, typed, secured runtime experience inside normal app provisioning and the signed-in user's existing permissions.

What it does

Runs permission-aware AI analysis in the background each day to create prioritized, evidence-backed insights and governed next actions from meaningful changes in authorized business records.

Key capabilities

  • Run a durable daily background cycle for configured insight types and source scopes.
  • Read only AI-eligible records and evidence through tenant, DataRole, field, location, and CanAiReadRecords controls.
  • Create structured insights with source record, type/category, title, summary, recommended action, priority, confidence, severity, evidence, model/profile provenance, and lifecycle dates.
  • Use source version/context fingerprints and current-state checks to avoid repeatedly presenting stale or duplicate findings.
  • Deliver each insight only to users who can currently access its source record; losing source access removes the insight from their secured feed.
  • Let each user view, pin, snooze, hide, dismiss, or advance an insight without changing another user's personal feed state.
  • Turn a recommended next step into a governed action that still requires the current user's action permission and configured policy or approval.

Common uses

  • Daily account risk, opportunity, renewal, follow-up, and customer-health findings.
  • Operational exceptions, overdue work, recurring issues, quality changes, and material KPI movement.
  • Proactive company-knowledge, case, service, sales, support, or asset insights with evidence links.

How it connects

The background cycle writes canonical AiInsights linked to their source Records and stores supporting evidence separately. The secured Insights feed presents those findings with per-user state. Recommended work may create a governed insight action, workflow, Inbox item, or GoClaw suggestion, but the insight itself is a finding—not authorization to mutate business data.

Where applicable, its records use the universal RecordId conventions so they can participate in secured relationships, activity history, favorites, dynamic fields, notifications, Inbox attention, and global search without copying the source record.

Security and data boundary

Insight generation applies the AI-read envelope before model context is assembled. Insight visibility is inherited from the source record and rechecked at read time. Evidence, recommendations, and actions cannot reveal or operate on records, fields, locations, or tools outside the current user's permissions; material execution uses action-specific permission and policy/approval.

  • The authenticated service derives the SaaS app, tenant account, user, DataRole, and location scope; browser identifiers are never authorization proof.
  • The page editor composes React components with validated data bindings. Those bindings call typed runtime APIs, whose application services execute reviewed stored procedures.
  • List, search, detail, relation, activity, favorite, and write operations reapply their required server-side permissions.

Add it to an app

  1. Choose one decision users should make from a daily finding and define its source modules, eligible states, evidence, freshness window, and materiality threshold.
  2. Select the exact users/roles and AI-readable record scope; normal record access alone does not imply AI eligibility.
  3. Configure the daily schedule, model/harness profile, priority/confidence/severity rules, expiry, deduplication/current-context policy, and safe failure behavior.
  4. Define the user-facing insight lifecycle and any optional next action as a reviewed, permission-keyed contract with the required approval policy.
  5. Test no-change days, changed source context, duplicates, expired findings, revoked source access, restricted fields/locations, model failure/retry, and proposed-action denial.

Copy/paste the feed

The normal choice is the native block: it already includes the secured list, filters, bounded pagination, detail panel, evidence, and per-user view, pin, snooze, and hide state. Paste this page document into Raw JSON mode:

{
  "blocks": [
    {
      "_id": "ai-insights-feed",
      "_type": "module.ai-insights",
      "props": {},
      "children": []
    }
  ]
}

The page shell supplies the page heading. The module expands to the available center column; page and shell layout remain yours.

Custom unstyled React feed

For custom presentation inside apps/tenant-runtime/src, keep the official authenticated API helper and SDK contract parser, then replace only the markup. This starter deliberately does not make authorization decisions in React:

import { useEffect, useState } from "react";
import type { AiInsightList } from "@buildwithhq/module-sdk";
import { listAiInsights } from "./api";

export function CustomAiInsightsFeed() {
  const [feed, setFeed] = useState<AiInsightList | null>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const request = new AbortController();
    listAiInsights({ pageNumber: 1, pageSize: 50 }, request.signal)
      .then(setFeed)
      .catch((caught: unknown) => {
        if (!(caught instanceof DOMException && caught.name === "AbortError")) {
          setError(caught instanceof Error ? caught.message : "AI Insights could not be loaded.");
        }
      });
    return () => request.abort();
  }, []);

  if (error) return <p role="alert">{error}</p>;
  if (!feed) return <p role="status">Loading AI Insights...</p>;
  if (!feed.items.length) return <p>No insights match this secured view.</p>;

  return (
    <section className="custom-insights" aria-labelledby="insights-title">
      <header>
        <div>
          <p>First-class module</p>
          <h1 id="insights-title">AI Insights</h1>
        </div>
        <p>{feed.unviewedCount} new / {feed.totalRecords} visible</p>
      </header>
      <ol>
        {feed.items.map((insight) => (
          <li key={insight.insightId} data-unviewed={!insight.hasViewed}>
            <article>
              <p>{insight.insightCategory || insight.insightType}</p>
              <h2>{insight.title}</h2>
              <p>{insight.summary}</p>
              <small>
                {insight.sourceRecordTitle || insight.sourceModuleKey}
                {insight.severity ? ` / ${insight.severity}` : ""}
                {` / Priority ${insight.priorityScore}`}
              </small>
            </article>
          </li>
        ))}
      </ol>
    </section>
  );
}

Optional starter styling

Drop this next to the unstyled component, import it, and replace the design tokens with your own. Removing this CSS does not change data binding or security.

.custom-insights { width: 100%; max-width: none; }
.custom-insights > header {
  align-items: end;
  display: flex;
  gap: 1rem;
  justify-content: space-between;
}
.custom-insights ol {
  display: grid;
  gap: .75rem;
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
}
.custom-insights li {
  background: var(--surface, #fff);
  border: 1px solid var(--line, #d8dee8);
  border-radius: .75rem;
  padding: 1rem;
}
.custom-insights li[data-unviewed="true"] {
  border-left: .3rem solid var(--accent, #3157d5);
}
.custom-insights h2 { margin: .25rem 0 .5rem; }
@media (max-width: 640px) {
  .custom-insights > header { align-items: start; flex-direction: column; }
}

Exact data path

PurposeMethod and routeBound
FeedGET /api/modules/ai-insightsMaximum 200 rows per page
Insight and evidenceGET /api/modules/ai-insights/{insightId}Maximum 25 display-safe evidence rows
Personal statePUT /api/modules/ai-insights/{insightId}/stateView, pin, snooze, or hide for the signed-in user

All three routes derive identity on the server and reapply tenant, SaaS app, active-user, DataRole, location, record-read, and CanAiReadRecords checks. The detail route omits raw evidence JSON and action payloads. A recommendation is display-only until a separate Workflow or GoClaw action contract authorizes it.

See the complete React component catalog for the generated styled and unstyled block exports, or the headless application guide when the React application lives outside the BuildWithHQ tenant shell.

Build a professional AI Insights dashboard

These six registry-backed presentation blocks let a designer turn the secured AI Insights API into a complete admin page without writing a chart, grid, status badge, empty state, or timeline from scratch. The normal operational API begins at /api/modules/ai-insights; a dashboard-wide count or trend should come from a separate purpose-built presentation binding so the browser never downloads a broad record population to calculate one number.

The ZIP contains this feature's fictional design composition at pages/first-class/ai-insights-sample.json, its executable authenticated page at pages/first-class/ai-insights-live.json, and the catalog-driven FirstClassPresentationGallery.tsx. Use the sample only for visual design. The live page calls the real native API and reviewed stored procedures under the signed-in user's scope.

Payload kindRuntime blockUseful AI Insights projection
metric-setcore.metric-stripVisible, unviewed, pinned, severe, and expiring findings
entity-listcore.entity-listHighest-priority authorized findings and source records
progress-listcore.progress-listDistribution by state, severity, or category
series-chartcore.series-chartGenerated, viewed, acted-on, and dismissed findings
data-gridcore.presentation-gridOne bounded page with confidence and source context
timelinecore.timelineGeneration, view, pin, snooze, action, dismissal, and expiry

Copy/paste design preview: all six blocks

This complete static page document renders immediately in Puck/Monaco and is useful while styling a template. Its names, counts, dates, and IDs are fictional design fixtures; static preview values are not live tenant facts.

Copy the complete six-block page JSON
{
  "blocks": [
    {
      "_id": "ai-insights-metrics",
      "_type": "core.metric-strip",
      "props": {
        "title": "AI insight center",
        "asOfUtc": "2026-09-04T18:00:00Z",
        "items": [
          {
            "key": "visible",
            "label": "Visible insights",
            "value": 126,
            "format": "number",
            "tone": "neutral"
          },
          {
            "key": "unviewed",
            "label": "Unviewed",
            "value": 18,
            "format": "number",
            "tone": "warning"
          },
          {
            "key": "pinned",
            "label": "Pinned",
            "value": 7,
            "format": "number",
            "tone": "primary"
          },
          {
            "key": "high",
            "label": "High severity",
            "value": 5,
            "format": "number",
            "tone": "danger"
          }
        ]
      },
      "children": []
    },
    {
      "_id": "ai-insights-recent",
      "_type": "core.entity-list",
      "props": {
        "title": "Priority insights",
        "hasMore": true,
        "items": [
          {
            "id": "ai-insights-sample-1",
            "recordId": "ai-insights-record-1",
            "primary": "Renewal risk increased",
            "secondary": "Northstar account - 91% confidence",
            "status": {
              "key": "high-severity",
              "label": "High severity",
              "tone": "danger"
            },
            "trailing": "91%"
          },
          {
            "id": "ai-insights-sample-2",
            "recordId": "ai-insights-record-2",
            "primary": "Renewal risk increased - Follow-up",
            "secondary": "Northstar account - 91% confidence - Updated two hours ago by the assigned owner",
            "status": {
              "key": "in-review",
              "label": "In review",
              "tone": "primary"
            },
            "trailing": "Today"
          },
          {
            "id": "ai-insights-sample-3",
            "recordId": "ai-insights-record-3",
            "primary": "Renewal risk increased - West region",
            "secondary": "Northstar account - 91% confidence - Related to three visible records at the Reno location",
            "status": {
              "key": "on-track",
              "label": "On track",
              "tone": "success"
            },
            "trailing": "3 related"
          },
          {
            "id": "ai-insights-sample-4",
            "recordId": "ai-insights-record-4",
            "primary": "Renewal risk increased - Customer response",
            "secondary": "Northstar account - 91% confidence - Waiting for an external response before work can continue",
            "status": {
              "key": "scheduled",
              "label": "Scheduled",
              "tone": "warning"
            },
            "trailing": "Tomorrow"
          },
          {
            "id": "ai-insights-sample-5",
            "recordId": "ai-insights-record-5",
            "primary": "Renewal risk increased - Regional operations review with a deliberately long title",
            "secondary": "Northstar account - 91% confidence - This deliberately longer supporting line verifies wrapping, truncation, responsive spacing, and dense dashboard behavior.",
            "status": {
              "key": "needs-attention",
              "label": "Needs attention",
              "tone": "danger"
            },
            "trailing": "Review",
            "tertiary": "Long-content fixture: verify keyboard focus, wrapping, narrow columns, and mobile overflow before publishing."
          },
          {
            "id": "ai-insights-sample-6",
            "recordId": "ai-insights-record-6",
            "primary": "Renewal risk increased - Completed preview",
            "secondary": "Northstar account - 91% confidence - Closed after review with its related evidence retained",
            "status": {
              "key": "complete",
              "label": "Complete",
              "tone": "success"
            },
            "trailing": "Closed"
          }
        ]
      },
      "children": []
    },
    {
      "_id": "ai-insights-bystatus",
      "_type": "core.progress-list",
      "props": {
        "title": "Insights by state",
        "items": [
          {
            "key": "open",
            "label": "Open",
            "value": 62,
            "maximum": 126,
            "displayValue": "62",
            "tone": "warning",
            "status": {
              "key": "open",
              "label": "Open",
              "tone": "warning"
            }
          },
          {
            "key": "progress",
            "label": "In progress",
            "value": 29,
            "maximum": 126,
            "displayValue": "29",
            "tone": "primary",
            "status": {
              "key": "progress",
              "label": "In progress",
              "tone": "primary"
            }
          },
          {
            "key": "acted",
            "label": "Acted on",
            "value": 35,
            "maximum": 126,
            "displayValue": "35",
            "tone": "success",
            "status": {
              "key": "acted",
              "label": "Acted on",
              "tone": "success"
            }
          }
        ]
      },
      "children": []
    },
    {
      "_id": "ai-insights-trend",
      "_type": "core.series-chart",
      "props": {
        "title": "Insight outcomes",
        "variant": "bar",
        "defaultPeriodKey": "d7",
        "periods": [
          {
            "key": "d7",
            "label": "7 days",
            "labels": [
              "Fri",
              "Sat",
              "Sun",
              "Mon",
              "Tue",
              "Wed",
              "Thu"
            ],
            "series": [
              {
                "key": "primary",
                "label": "Generated",
                "tone": "primary",
                "values": [
                  8,
                  5,
                  4,
                  12,
                  15,
                  11,
                  17
                ]
              },
              {
                "key": "secondary",
                "label": "Acted on",
                "tone": "success",
                "values": [
                  6,
                  4,
                  3,
                  9,
                  12,
                  10,
                  14
                ]
              }
            ]
          }
        ]
      },
      "children": []
    },
    {
      "_id": "ai-insights-table",
      "_type": "core.presentation-grid",
      "props": {
        "title": "Authorized insights",
        "columns": [
          {
            "key": "insight",
            "label": "Insight",
            "type": "text",
            "align": "left"
          },
          {
            "key": "source",
            "label": "Source",
            "type": "text",
            "align": "left"
          },
          {
            "key": "confidence",
            "label": "Confidence",
            "type": "number",
            "align": "right"
          },
          {
            "key": "severity",
            "label": "Severity",
            "type": "status",
            "align": "left"
          },
          {
            "key": "created",
            "label": "Created",
            "type": "date",
            "align": "left"
          }
        ],
        "rows": [
          {
            "id": "ai-insights-row-1",
            "recordId": "ai-insights-record-1",
            "cells": {
              "insight": "Renewal risk increased",
              "source": "Northstar account",
              "confidence": 91,
              "severity": {
                "key": "high",
                "label": "High",
                "tone": "danger"
              },
              "created": "2026-09-04T16:30:00Z"
            }
          },
          {
            "id": "ai-insights-row-2",
            "recordId": "ai-insights-record-2",
            "cells": {
              "insight": "Renewal risk increased - Follow-up",
              "source": "Northstar account",
              "confidence": 92,
              "severity": {
                "key": "in-review",
                "label": "In review",
                "tone": "primary"
              },
              "created": "2026-09-04T15:42:00Z"
            }
          },
          {
            "id": "ai-insights-row-3",
            "recordId": "ai-insights-record-3",
            "cells": {
              "insight": "Renewal risk increased - West region",
              "source": "Northstar account",
              "confidence": 93,
              "severity": {
                "key": "on-track",
                "label": "On track",
                "tone": "success"
              },
              "created": "2026-09-04T12:18:00Z"
            }
          },
          {
            "id": "ai-insights-row-4",
            "recordId": "ai-insights-record-4",
            "cells": {
              "insight": "Renewal risk increased - Customer response",
              "source": "Northstar account",
              "confidence": 94,
              "severity": {
                "key": "scheduled",
                "label": "Scheduled",
                "tone": "warning"
              },
              "created": "2026-09-03T21:07:00Z"
            }
          },
          {
            "id": "ai-insights-row-5",
            "recordId": "ai-insights-record-5",
            "cells": {
              "insight": "Renewal risk increased - Regional operations review with a deliberately long title",
              "source": "Northstar account - This deliberately longer supporting line verifies wrapping, truncation, responsive spacing, and dense dashboard behavior.",
              "confidence": 95,
              "severity": {
                "key": "needs-attention",
                "label": "Needs attention",
                "tone": "danger"
              },
              "created": "2026-09-03T16:31:00Z"
            }
          },
          {
            "id": "ai-insights-row-6",
            "recordId": "ai-insights-record-6",
            "cells": {
              "insight": "Renewal risk increased - Completed preview",
              "source": "Northstar account",
              "confidence": 96,
              "severity": {
                "key": "complete",
                "label": "Complete",
                "tone": "success"
              },
              "created": "2026-09-02T19:14:00Z"
            }
          }
        ],
        "page": {
          "pageNumber": 1,
          "pageSize": 6,
          "totalRecords": 126,
          "totalIsExact": true,
          "hasMore": true
        }
      },
      "children": []
    },
    {
      "_id": "ai-insights-timeline",
      "_type": "core.timeline",
      "props": {
        "title": "Insight activity",
        "hasMore": true,
        "items": [
          {
            "id": "ai-insights-event-1",
            "recordId": "ai-insights-record-1",
            "occurredUtc": "2026-09-04T17:58:00Z",
            "title": "Insight generated",
            "description": "A new evidence-backed renewal finding is available.",
            "actor": "AI Insights",
            "tone": "primary"
          },
          {
            "id": "ai-insights-event-2",
            "recordId": "ai-insights-record-2",
            "occurredUtc": "2026-09-04T15:42:00Z",
            "title": "Insight generated - Follow-up",
            "description": "A new evidence-backed renewal finding is available. Updated two hours ago by the assigned owner.",
            "actor": "Avery Patel",
            "tone": "primary"
          },
          {
            "id": "ai-insights-event-3",
            "recordId": "ai-insights-record-3",
            "occurredUtc": "2026-09-04T12:18:00Z",
            "title": "Insight generated - West region",
            "description": "A new evidence-backed renewal finding is available. Related to three visible records at the Reno location.",
            "actor": "Sam Rivera",
            "tone": "success"
          },
          {
            "id": "ai-insights-event-4",
            "recordId": "ai-insights-record-4",
            "occurredUtc": "2026-09-03T21:07:00Z",
            "title": "Insight generated - Customer response",
            "description": "A new evidence-backed renewal finding is available. Waiting for an external response before work can continue.",
            "actor": "Maya Chen",
            "tone": "warning"
          },
          {
            "id": "ai-insights-event-5",
            "recordId": "ai-insights-record-5",
            "occurredUtc": "2026-09-03T16:31:00Z",
            "title": "Insight generated - Regional operations review with a deliberately long title",
            "description": "A new evidence-backed renewal finding is available. This deliberately longer supporting line verifies wrapping, truncation, responsive spacing, and dense dashboard behavior.",
            "actor": "Automation",
            "tone": "danger"
          },
          {
            "id": "ai-insights-event-6",
            "recordId": "ai-insights-record-6",
            "occurredUtc": "2026-09-02T19:14:00Z",
            "title": "Insight generated - Completed preview",
            "description": "A new evidence-backed renewal finding is available. Closed after review with its related evidence retained.",
            "actor": "Jordan Lee",
            "tone": "success"
          }
        ]
      },
      "children": []
    }
  ]
}

Copy/paste React composition

Copy InteractivePresentationComponents.tsx and its optional CSS from the Professional Foundation Developer Kit, then add this module-specific composition. It is semantic and unstyled by default; pass styled after importing interactive-presentation-components.css for the supplied polished foundation. Either version accepts only a bounded already-authorized document and fails closed through the shared strict parsers.

import {
  EntityList,
  MetricStrip,
  PresentationGrid,
  ProgressList,
  SeriesChart,
  Timeline,
} from "./InteractivePresentationComponents";

export interface AiInsightsPresentationData {
  readonly metrics: unknown;
  readonly recent: unknown;
  readonly byStatus: unknown;
  readonly trend: unknown;
  readonly table: unknown;
  readonly timeline: unknown;
}

export interface AiInsightsPresentationProps {
  /** Pass only the already-authorized presentation document returned by the API. */
  readonly data?: AiInsightsPresentationData | null;
  readonly loading?: boolean;
  readonly error?: boolean;
  readonly styled?: boolean;
  /** Record identity is navigation context; the detail API must authorize it again. */
  readonly onOpenRecord?: (recordId: string) => void;
}

export function AiInsightsPresentation({
  data,
  loading = false,
  error = false,
  styled = false,
  onOpenRecord,
}: AiInsightsPresentationProps) {
  if (error) return <p role="alert">The AI Insights presentation could not be loaded.</p>;
  if (loading || !data) return <p role="status">Loading AI Insights presentation...</p>;

  return (
    <main className={styled ? "bwhq-api-example" : undefined}>
      <header>
        <p>AI Insights</p>
        <h1>AI insight center</h1>
        <p>Prioritized findings, severity, confidence, source context, and governed user actions.</p>
      </header>

      <MetricStrip data={data.metrics} styled={styled} />
      <div className={styled ? "bwhq-api-example__split" : undefined}>
        <ProgressList data={data.byStatus} styled={styled} />
        <EntityList data={data.recent} styled={styled} onOpenRecord={onOpenRecord} />
      </div>
      <SeriesChart data={data.trend} styled={styled} />
      <PresentationGrid data={data.table} styled={styled} onOpenRecord={onOpenRecord} />
      <Timeline data={data.timeline} styled={styled} onOpenRecord={onOpenRecord} />
    </main>
  );
}

Copy the live, authenticated module page

This document has no placeholder key and needs no invented endpoint. Save it to a page and add that page to a User Type menu. The registered native component calls /api/modules/ai-insights, uses the current tenant session, and preserves the module's real list, detail, create/update, pagination, empty, loading, and error behavior. Dynamic Records discovers the organization's real tenant-owned modules when no module key is configured.

Copy the executable live page
{
  "blocks": [
    {
      "_id": "ai-insights-live",
      "_type": "module.ai-insights",
      "props": {},
      "children": []
    }
  ]
}

The server derives SaaS app, organization, user, DataRoles, locations, module-specific membership/privacy, and any AI-read gate from verified identity. A returned identifier can select a detail target, but the detail or write endpoint authorizes it again. Page layout, status, tone, totals, action names, and identifiers never grant authority.

Tip

A daily run should produce a short list worth reading, not summarize every record. Start with one high-value insight type, measure dismissals and acted-on outcomes, and tune thresholds before adding more.

Important

A renderer being bundled in the tenant application does not make its data visible in every app. The server returns only components and records authorized for the current app and signed-in user; unavailable or unauthorized blocks fail closed.

Capability review: 2026-09-14. For exact current technical availability, use the generated API Map and first-class module inventory.