Docs

Tier-1 vs Tier-2

When to use a declarative manifest (Tier-1) vs arbitrary TypeScript in a Vercel Sandbox (Tier-2), and how to publish each.

On this page

Tier-1 — Manifest-only (start here)

A Tier-1 agent is a single YAML manifest. No code. Fully self-serve from the dashboard.

The shape it fits is: form input → optional file ingest → AI call(s) → optional Python compute → rendered report.

That covers a surprising amount of ground: document analyzers, receipt extractors, sentiment classifiers, policy Q&A bots, data enrichment pipelines. If your agent takes something in, runs AI over it, and produces a readable result, Tier-1 is probably the right choice.

Pick Tier-1 when you want to:

  • Ship fast without writing code
  • Offer a single, focused workflow
  • Accept files (PDFs, images, CSVs), text queries, or URLs as input
  • Return a rendered HTML/Markdown report or structured JSON

Tier-2 — Code in a Vercel Sandbox

Tier-2 agents are arbitrary TypeScript/JavaScript running in a Vercel Sandbox per request. Pick Tier-2 when you need any of the following:

NeedExample
Multiple HTTP routes/api/evaluate, /dashboard, /webhook
Scheduled jobsDaily digest, nightly data sync
OAuth integrationsReddit, GitHub, Twitter — acting as the user
Outbound channelsEmail via Resend, git commits, Slack messages
Persistent per-tenant dataPer-user databases or vector stores
Custom UI surfacesMore than a single rendered report

How to publish a Tier-2 agent

1. Start from a Tier-1 agent

You need an apps row first. Create a Tier-1 agent at /dashboard/apps/new using the slug you want, or have an admin run the hand-onboard script. The slug in your manifest must match the apps row slug exactly.

2. Develop locally from a template

Clone one of the existing Tier-2 agents in the repo as a starting point (e.g. agents/saas-idea-validator/). Edit:

  • src/endpoints.ts — your HTTP handlers
  • src/install.ts — tenant install hook
  • src/schedules.ts — cron handlers

Update your manifest.yaml for Tier-2:

yaml
manifest_version: 2
slug: <your-slug>
runtime: node20
package:
  entry: dist/
ui:
  routes:
    - path: /
      method: GET
      kind: html
integrations:
  - id: gemini
    kind: api_key
    required: true

3. Build and zip

Run the build script:

bash
npx tsx scripts/build-agent-package.ts agents/<your-slug>

This compiles and bundles your TypeScript, then produces a .zip ready for upload. (The CLI also prints a curl command — ignore it, use the dashboard instead.)

4. Upload and activate

Navigate to /dashboard/apps/<your-slug>/publish. Drag the zip onto the drop zone. The server:

  1. Extracts manifest.yaml (or manifest.json) from the zip.
  2. Validates it against the v2 schema.
  3. Confirms the slug in the manifest matches the URL slug.
  4. Uploads the zip to Supabase Storage.
  5. Inserts an agent_packages row with is_active=false.

The version list below the drop zone shows all uploaded packages. Click Activate to make a version live. Activation:

  • Sets the new package to is_active=true and all siblings to false.
  • Syncs agent_schedules to match the manifest's schedule[].
  • Provisions a per-tenant Postgres schema if data.mode === 'platform_owned'.

After activation, your agent serves at /user/<slug>/<path> for HTML routes and /user/<slug>/api/<path> for JSON API routes. The /agents/<slug> catalog listing points users at the first GET route declared in the manifest.