Proferprofer

How It Works

The complete lifecycle of a Profer artifact

How It Works

The lifecycle

Agent in Claude Code / Cursor / any MCP client

  ├── 1. publish({ html, title, questions })
  │     └── Profer stores HTML + questions
  │     └── Returns { id: "PF-K8M3N", url }

  │   2. User shares URL (Slack, email, WhatsApp)
  │     │
  │     ├── Reviewer opens URL in browser
  │     │     ├── Sees agent's HTML (sandboxed iframe)
  │     │     ├── Answers structured questions
  │     │     └── Submits (no login required)
  │     │
  │     └── Webhook fires (if configured)

  │   3. Feedback aggregated in database

  └── 4. get({ id: "PF-K8M3N" })
        └── Returns { html, feedback[], status }

Key design decision: the agent generates the HTML

Profer doesn't have templates, themes, or renderers. The agent generates whatever HTML it wants. We just:

  1. Store it — in Supabase Postgres
  2. Serve it — at a public URL
  3. Wrap it — with a feedback widget
  4. Return feedback — structured, typed data

This means any agent can use Profer. Claude generates different HTML than GPT. Both work.

Public page rendering

When a reviewer opens profer.dev/v/PF-K8M3N:

  1. Edge function reads the page from Postgres
  2. Agent HTML is placed inside a sandboxed iframe (srcdoc with sandbox="allow-same-origin")
  3. CSP headers with a per-request nonce protect against XSS
  4. The feedback widget renders below the iframe
  5. Submitting feedback POSTs to /v/PF-K8M3N/feedback

Status tracking

Pages have three statuses:

StatusMeaning
awaiting_feedbackInitial state, or after an update()
approvedAll approve-type questions answered "yes"
changes_requestedAny approve-type question answered "no" or "needs_changes"

Status auto-updates when feedback with approve-type questions is submitted.

Version tracking

Each update() increments the version number and resets status to awaiting_feedback. Previous feedback is preserved and tied to the version it was given on.

On this page