Skip to content

About

Production-ready starter templates for Introspection agents and AG-UI

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Introspection starter templates

Two hackathon-ready Next.js references for building task-backed agent applications with the latest Introspection Node SDK and AG-UI.

Template Best for Included
agent-chat One configured runtime Concurrent chats, streaming, task history, refresh/resume, HITL, cancel, archive
agent-workspace Several configured runtimes Everything in Agent Chat plus runtime-grouped workspaces and concurrent runtime sessions
Agent Chat Agent Workspace
Agent Chat with several live conversations Agent Workspace with chats grouped by runtime

Choose a template

Start with Agent Chat unless users need to choose between different agent runtimes. It has the complete chat lifecycle without workspace configuration. Choose Agent Workspace when one product should expose several runtime-backed workspaces, such as coding and research agents.

The apps intentionally share the same chat core while keeping their route and authentication glue local. This makes either app independently copyable without hiding the important server boundary in a framework package.

Quick start

pnpm install
cp apps/agent-chat/.env.example apps/agent-chat/.env.local
pnpm dev:chat

Required configuration:

INTROSPECTION_CP_URL=https://api.staging.introspection.dev
INTROSPECTION_TOKEN=intro_...
INTROSPECTION_RUNTIME=coding-agent
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_...

INTROSPECTION_PROJECT is optional when the API key already selects the project. In Supabase, enable email/password authentication and add http://localhost:3202/auth/callback or http://localhost:3203/auth/callback to the permitted redirect URLs. Use https://api.introspection.dev when targeting production.

INTROSPECTION_RUNTIME (Agent Chat) and INTROSPECTION_WORKSPACES_JSON (Agent Workspace) are now optional pins. Without them, the apps discover the project's active runtimes through the Node SDK (client.runtimes.list) and populate the sidebar from what is actually deployed.

How a message works

Browser
  -> protected same-origin Next.js route
  -> authenticated Supabase user ID
  -> Introspection Node SDK runner with that identity
  -> task start or task run creation
  -> NDJSON stream through the same route
  -> AG-UI AbstractAgent reduces events into session state
  -> React renders messages, tools, status, and HITL controls

New chats are task-first: the first prompt starts an Introspection task, and the UI promotes its local draft session to the returned task ID. Later messages create runs on that task. The user message appears optimistically, so sending is immediate even while the task or run starts.

Each active chat has an independent Zustand session. Switching chats does not stop background streams. React Query owns task-list caching and invalidation, while Introspection remains the source of truth for persisted tasks, transcripts, and run state. On refresh, the app loads the transcript and attaches to an active run when one exists.

Authentication and data ownership

Both templates use Supabase Auth for application users and a project API key used only by server-side Introspection code.

State Owner Notes
Login session Supabase Auth The validated claim sub becomes the Introspection identity user ID.
Tasks, transcripts, runs Introspection A task is the chat record; no second chat database is required.
Live chat sessions Zustand One independent client store per open/draft task.
Task lists React Query Cached, polled while active, and invalidated after mutations.
Workspace membership Introspection task metadata starter_template.workspace_key groups tasks in Agent Workspace.

The browser receives the Supabase publishable key, which is designed for public clients, but never receives an Introspection token, Data Plane URL, or Data Plane cookie. Every runner uses the authenticated Supabase user.id as its Introspection identity, so task history is user-scoped.

The API currently treats operation and message IDs as metadata rather than enforced idempotency keys. Applications that automatically retry ambiguous task-creation failures should reconcile those IDs before retrying.

Before a public deployment: add per-user rate limiting to the protected agent routes. Authentication prevents anonymous API-key use but does not by itself control how much an authenticated user can spend.

Repository structure

apps/
  agent-chat/                 # Single-runtime Next.js app
    src/app/api/introspection # Protected task/run route handlers
    src/app/auth              # Supabase sign-in and callback
    src/lib/runtime-targets.ts# Server-side runtime configuration
    src/lib/template-user.ts  # Supabase claim -> Introspection identity
  agent-workspace/            # Multi-runtime Next.js app with the same boundaries
packages/
  chat-core/src/
    chat-app.tsx              # Sidebar, composer, messages, HITL, task queries
    pending-interrupt-panel.tsx # Approval/question panel shown in place of the composer
    client.ts                 # Same-origin API client and NDJSON run handle
    session.ts                # Per-chat AG-UI/Zustand lifecycle
    session-registry.ts       # Concurrent session registry
    transcript.ts             # Introspection transcript -> AG-UI messages
    server/node-api.ts        # Server-only Node SDK task/run operations + runtime discovery
    styles.css                # Shared starter UI
introspection/
  email-agent/                # Pi recipe: Gmail assistant, sends gated by a tool_call approval hook
  multi-research-agent/       # Pi recipe: coordinator + researcher/writer subagents
  meeting-actionables/        # Pi recipe: meetings -> structured actionables
.introspection/               # Deployment manifests for the three recipes above
tests/
  e2e/chat.spec.ts            # Browser user-flow coverage for both templates
  fake-supabase.mjs           # Local auth boundary used only by automated tests
docs/images/                  # Real staging-backed screenshots

The four route handlers in each app are deliberately thin adapters around chat-core/server. runtime-targets.ts is the allowlist boundary: the browser sends a target key, never an arbitrary runtime name.

What to customize

  • Change runtime labels and runtime names in each app's runtime-targets.ts or environment variables.
  • Restyle the shared experience in packages/chat-core/src/styles.css, or replace the UI while retaining the session and server layers.
  • Extend tool rendering in chat-app.tsx and the HITL experience in pending-interrupt-panel.tsx without changing stream transport. While interrupts are pending, the panel replaces the composer; approvals resolve with { approved: true } or { approved: false, feedback }, matching interrupts raised with reason confirmation (for example by the email-agent recipe's send-approval hook).
  • Add application data to Supabase when your product needs projects, teams, billing, or domain records. Chat persistence itself does not require another table.
  • Add pagination, rate limits, observability, and deployment-specific duration limits before production scale.

The route handlers and SDK streams use a five-minute execution limit. The sidebar intentionally shows the 50 most recent chats per workspace; adapt pagination and deployment limits for longer-running production workloads.

Validate

pnpm lint
pnpm typecheck
pnpm test
pnpm build
pnpm test:e2e

The browser suite covers authentication, optimistic sending, concurrent chats, switching during streams, refresh/resume, deep links, cancellation, archive, HITL, workspace isolation, and mobile navigation. The screenshots above were captured from real staging-backed multi-turn sessions; the fake Supabase server is only an automated-test fixture.

About

Production-ready starter templates for Introspection agents and AG-UI

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages