ax-check.com
by Gauge
P
ProForma Labs
proformalabs.ai
ax-check.com
Checked 18 September 2026
B
81/100
Agents need your login
Setup docs are solid, but no agent can find a price.
Onboarding, CLI, API and MCP docs all pass cleanly. Pricing is absent from the homepage, and sessions found no published price list.
2 fixes to start with
Concrete changes, backed by what we found.
Recorded coding sessions
Same task, 3 models, no proformalabs.ai account. Recorded 18 September 2026 on Pi.
3 recorded · 6m 47s
6m 47s · recorded
Session findings
Select a finding to see it in context.
›Thinking…
I have no idea what "ProForma Labs" is. Let me check the repository.
✓$ ls -la /sandbox/repo && cat /sandbox/repo/README* 2>/dev/null | head -50✓└{"content":[{"text":"total 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Sep 18 22:31 ..\ndrwxr-xr-x 8 root root 4096 Sep 18 08:00…ctrl+o
{"content":[{"text":"total 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Sep 18 22:31 ..\ndrwxr-xr-x 8 root root 4096 Sep 18 08:00 .git\n-rw-r--r-- 1 root root 408 Sep 18 08:00 .gitignore\n","type":"text"}]}✓$ env | grep -i -E "proforma|PI_" | head -20✓└{"content":[{"text":"PI_CODING_AGENT=true\nPI_REASONING_LEVEL=medium\nPI_SESSION_FILE=/sandbox/.gauge/pi/sessions/2026-09-18T22-31-09-527Z_01a0b6a5-1dd7-7097-b5…ctrl+o
{"content":[{"text":"PI_CODING_AGENT=true\nPI_REASONING_LEVEL=medium\nPI_SESSION_FILE=/sandbox/.gauge/pi/sessions/2026-09-18T22-31-09-527Z_01a0b6a5-1dd7-7097-b5a2-42045f6b1a1c.jsonl\nPI_PROVIDER=gauge-fireworks\nPI_MODEL=accounts/fireworks/models/qwen3p8-max\nPI_SESSION_ID=01a0b6a5-1dd7-7097-b5a2-42045f6b1a1c\nPI_GATEWAY_API_KEY=unused\n","type":"text"}]}›Thinking…
The repository is empty (only .gitignore and .git). I don't know what "ProForma Labs" is — it might be a fictional product. Let me check whether there are any credentials, documentation, or network access available. First, I'll check the contents of .gitignore.
✓$ cat /sandbox/repo/.gitignore; git -C /sandbox/repo log --oneline | head; ls /sandbox✓└{"content":[{"text":"# Keep generated and vendored files out of source diffs.\n\n# Logs / OS cruft\n*.log\n.DS_Store\n\n# JavaScript / TypeScript\nnode_modules/…ctrl+o
{"content":[{"text":"# Keep generated and vendored files out of source diffs.\n\n# Logs / OS cruft\n*.log\n.DS_Store\n\n# JavaScript / TypeScript\nnode_modules/\n.next/\ndist/\nbuild/\ncoverage/\n\n# Python\n.venv/\nvenv/\n__pycache__/\n*.py[cod]\n.pytest_cache/\n*.egg-info/\n\n# Rust\ntarget/\n\n# Go / PHP / Ruby vendored deps\nvendor/\n.bundle/\n\n# Java / Kotlin / Scala\n.gradle/\n\n# .NET\nbin/\nobj/\n\n# Elixir\n_build/\ndeps/\n\n# Dart / Flutter\n.dart_tool/\n9ebf5fb Initial workspace\nrepo\n","type":"text"}]}✓$ env | grep -i -E "key|token|api" | sed 's/=.*/=***/' | head -20✓└{"content":[{"text":"PI_GATEWAY_API_KEY=***\nGIT_CONFIG_KEY_0=***\n","type":"text"}]}
›Thinking…
There are no ProForma Labs credentials or documentation. I don't know what ProForma Labs is — it's probably a fictional/unknown product. Maybe I should check network access and search for it? Let me quickly try checking the npm registry or PyPI.
✓$ timeout 15 npm search proforma 2>&1 | head -10; echo ---; timeout 15 pip index versions proforma 2>&1 | head -5; echo ---; timeout 10 curl -sI https://registry.npmjs.org/proforma-labs 2>&1 | head -3✓└{"content":[{"text":"@prfm/cli\nProForma agent CLI\nVersion 0.0.5 published 2026-09-03 by GitHub Actions\nMaintainers: darkfalke\nhttps://npm.im/@prfm/cli\n\nse…ctrl+o
{"content":[{"text":"@prfm/cli\nProForma agent CLI\nVersion 0.0.5 published 2026-09-03 by GitHub Actions\nMaintainers: darkfalke\nhttps://npm.im/@prfm/cli\n\nsequaljs\nJavaScript/TypeScript library for parsing and manipulating ProForma peptide sequence notation\nVersion 1.1.2 published 2026-09-16 by noatgnu\nMaintainers: noatgnu\n---\nproforma (0.2.1)\nAvailable versions: 0.2.1, 0.2.0, 0.1.0, 0.0.1\n---\nHTTP/2 404 \r\ndate: Fri, 18 Sep 2026 22:31:18 GMT\r\ncontent-type: application/json\r\n","type":"text"}]}›Thinking…
There's an npm package called "@prfm/cli" — "ProForma agent CLI". Could this be related to "ProForma Labs"? Let's take a look.
✓$ timeout 15 curl -s https://registry.npmjs.org/@prfm/cli | python3 -c "import json,sys; d=json.load(sys.stdin); print(json.dumps({k:d.get(k) for k in ['name','description','homepage','repository','keyw…✓└{"content":[{"text":"{\n \"name\": \"@prfm/cli\",\n \"description\": \"ProForma agent CLI\",\n \"homepage\": \"https://github.com/proforma-labs/proforma#read…ctrl+o
timeout 15 curl -s https://registry.npmjs.org/@prfm/cli | python3 -c "import json,sys; d=json.load(sys.stdin); print(json.dumps({k:d.get(k) for k in ['name','description','homepage','repository','keywords']}, indent=2)); v=d['dist-tags']['latest']; print(v); print(d['versions'][v].get('dependencies')); print(d['versions'][v].get('bin'))"
{"content":[{"text":"{\n \"name\": \"@prfm/cli\",\n \"description\": \"ProForma agent CLI\",\n \"homepage\": \"https://github.com/proforma-labs/proforma#readme\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/proforma-labs/proforma.git\",\n \"directory\": \"apps/cli\"\n },\n \"keywords\": null\n}\n0.0.5\nNone\n{'prfm': 'dist/index.js'}\n","type":"text"}]}›Thinking…
There's a GitHub repo proforma-labs/proforma. Let's try fetching the README to learn about the product, pricing, and SDK/API.
✓$ timeout 20 curl -sL https://raw.githubusercontent.com/proforma-labs/proforma/main/README.md | head -120✓└{"content":[{"text":"404: Not Found","type":"text"}]}
›Thinking…
Hmm, a 404. Maybe the repository doesn't exist, or maybe the branch is different. Let me try the API.
✓$ timeout 20 curl -s https://api.github.com/repos/proforma-labs/proforma | head -30; echo ---; timeout 20 curl -s https://api.github.com/orgs/proforma-labs/repos | head -40✓└{"content":[{"text":"{\n \"message\": \"Not Found\",\n \"documentation_url\": \"https://docs.github.com/rest/repos/repos#get-a-repository\",\n \"status\": \"…ctrl+o
{"content":[{"text":"{\n \"message\": \"Not Found\",\n \"documentation_url\": \"https://docs.github.com/rest/repos/repos#get-a-repository\",\n \"status\": \"404\"\n}\n---\n[\n\n]\n","type":"text"}]}›Thinking…
The GitHub organization exists, but there's no public repository (or nothing at all). However, the npm package @prfm/cli does exist. Let me download the tarball and check its contents — it might contain documentation, SDK, API endpoints, pricing info, etc.
✓$ cd /tmp && timeout 30 npm pack @prfm/cli 2>&1 | tail -1 && tar xzf prfm-cli-0.0.5.tgz && find package -type f | head -40✓└{"content":[{"text":"prfm-cli-0.0.5.tgz\npackage/dist/index.js\npackage/package.json\npackage/README.md\npackage/LICENSE\n","type":"text"}]}
›Thinking…
Hmm, maybe the package's README.md exists. Let me read it.
✓read /tmp/package/README.md✓└{"content":[{"text":"# prfm\n\n`prfm` is the ProForma agent CLI. It lets coding agents and humans work\nwith a ProForma Workspace from a terminal through a brow…ctrl+o
{"content":[{"text":"# prfm\n\n`prfm` is the ProForma agent CLI. It lets coding agents and humans work\nwith a ProForma Workspace from a terminal through a browser-approved,\nscoped connection.\n\nThe npm package is `@prfm/cli`; the installed binary is `prfm`.\n\n## Install\n\n```bash\npnpm add --global @prfm/cli\n```\n\nCheck the binary:\n\n```bash\nprfm --version\nprfm help\n```\n\n## Log In\n\nLet the agent initiate access from its shell:\n\n```bash\nprfm login\n```\n\nWithout `--api-url`, browser login uses an explicit `PROFORMA_API_URL`, a\ntrusted user-level config or stored profile, then the production default\n`https://app.proformalabs.ai`. A repository's `.proforma/config.json` can\nselect a Workspace after login, but it can never choose the authorization\norigin. Self-hosted deployments should pass their URL explicitly.\n\nOpen the safe browser link, confirm the matching code, choose a Workspace,\nand approve the mode that matches the task: `explore` for Workspace and\nmaterialized-Model reads, `build` for authoring, or `operate` for connections,\nAction Runs, automations, Tracking, and Prospecting effects. The CLI verifies\nthe issued session and stores the credential without displaying the token.\nThen confirm the connection:\n\n```bash\nprfm whoami\n```\n\nRepeat `--scope` to request an exact subset of the chosen mode. A synthetic\nPage-only build can request just `workspace:read` and `workspace:write`:\n\n```bash\nprfm login --access build \\\n --scope workspace:read \\\n --scope workspace:write \\\n --purpose \"Publish a synthetic reconciliation Page\"\n```\n\nFor a pre-provisioned environment, manual token import and environment\nvariables remain available:\n\n```bash\nprfm login --api-url https://your-proforma-host.example --token prfm_agent_xxx\nexport PROFORMA_API_URL=https://your-proforma-host.example\nexport PROFORMA_API_TOKEN=prfm_agent_xxx\n```\n\nCredentials are stored in origin/Workspace profiles at\n`~/.proforma/credentials.json` with file mode `0600`.\n\nBrowser-login origin resolution:\n\n1. `--api-url`\n2. `PROFORMA_API_URL`\n3. `~/.proforma/config.json` or a stored credential profile\n4. `https://app.proformalabs.ai`\n\nWhen you supply a token through a flag or environment variable, also supply\nthe API URL the same way. The CLI never pairs an ad-hoc token with an API URL\nread from repository config; without an explicit URL it uses localhost.\nAuthenticated connections require HTTPS outside loopback.\n\n## Common Commands\n\nList and read ordinary Workspace Files through the canonical v1 API:\n\n```bash\nprfm fs ls /\nprfm fs read /revenue-ops/close-notes.md --json\nprfm fs history /revenue-ops/close-notes.md\nprfm fs read /uploads/report.pdf --output ./report.pdf\n```\n\nDownloads are streamed to a private temporary file, verified against the\nrevision's exact size and SHA-256 checksum, and then published atomically.\n`--output` refuses an existing path and never follows a symbolic link. Pass\n`--force` only when you intend to replace an existing regular file; symbolic\nlinks and other non-files remain refused.\n\nCreate a File, or revise the exact version you read:\n\n```bash\nprfm fs put /revenue-ops/close-notes.md --from ./close-notes.md --create\n\netag=$(prfm fs read /revenue-ops/close-notes.md --json | jq -r '.resource.file.etag')\nprfm fs put /revenue-ops/close-notes.md \\\n --from ./close-notes.md \\\n --if-match \"$etag\" \\\n --idempotency-key close-notes-revise-2\n```\n\n`fs put` generates and reports an idempotency key before sending the write.\nIf a request has an unknown outcome, retry the same bytes and precondition with\nthat key, or supply your own stable `--idempotency-key` up front.\n\nLoad workspace context for a task:\n\n```bash\nprfm context \"build a customer health page\" --max-models 4\n```\n\nSearch and inspect catalog entries:\n\n```bash\nprfm catalog search customer --type models\nprfm model show customer_health_scores\nprfm source show accounts\nprfm page show customer-health\n```\n\nDiscover and configure the systems attached to the Workspace:\n\n```bash\nprfm connection providers\nprfm connection list\nprfm connection setup stripe --auth-mode api-key\n```\n\n`connection setup` prints the safe browser URL where a person completes\nprovider OAuth or enters the requested credentials in ProForma. The CLI does\nnot open that URL, accept secret values, or return stored credentials. Use\nFor Slack, use `--return-to /path` only when the person should return to a\nspecific page inside that Workspace after OAuth. ProForma adds the selected\nWorkspace's canonical path before starting authorization.\n\nAfter setup, inspect the connection and choose which resources land in a\nwritable database:\n\n```bash\nprfm connection show <connection-id>\nprfm connection resources <connection-id>\nprfm connection enable-resource <connection-id> customers \\\n --database warehouse \\\n --destination-table stripe_customers \\\n --write-mode upsert \\\n --primary-key id\n```\n\nThe connection and database stay explicit. ProForma rejects unavailable\nresources and read-only destinations before creating the mapping.\n\nQuery an approved model through the model Data API:\n\n```bash\nprfm data query customer_health_scores \\\n --filter 'health_score:lt:60' \\\n --sort 'arr:desc' \\\n --limit 25\n```\n\nRun native company and people prospecting, curate a reviewed list, and export\nit to a Source:\n\n```bash\nprfm prospecting search companies \"warehouse-native B2B SaaS\" \\\n --filters-json '{\"companyIndustries\":[\"software\"],\"companyHeadcountRanges\":[\"51-200\"]}' \\\n --json\n\nprfm prospecting search people \\\n --filters-file ./vp-data-filters.json \\\n --json\n\nprfm prospecting list create --name \"Data leaders\" --json\nprfm prospecting list add <list-id> \\\n --items-json '[{\"recordKind\":\"person\",\"personId\":\"<person-id>\"}]' \\\n --json\n\nprfm prospecting export \\\n --list-id <list-id> \\\n --database <database-id> \\\n --table gtm_data_leaders \\\n --json\n```\n\nUse `prfm prospecting suggestions <field> <query>` to resolve canonical filter\nvalues and `prfm prospecting search page <run-id> <page>` to continue a saved\nrun. Search and list commands never reveal contact details automatically.\nReveal one selected person only when the task calls for it:\n\n```bash\nprfm prospecting reveal \\\n --input-json '{\"recordKind\":\"person\",\"personId\":\"<person-id>\",\"revealEmail\":true}' \\\n --json\n```\n\nThe connection must include `prospecting:read`, `prospecting:write`, or\n`prospecting:reveal` for the corresponding operation. Export additionally\nrequires `data:define`. These commands do not compose or send email.\n\nCreate or retrieve the browser tracking key for a site:\n\n```bash\nprfm tracking default-key \\\n --database tracking-events \\\n --origin https://proformalabs.ai \\\n --replay on \\\n --sample-rate 1\n```\n\nCreate a writable DuckDB database and target it explicitly:\n\n```bash\nprfm database create --name \"Tracking events\"\nprfm tracking create-key \\\n --label \"Marketing site\" \\\n --database tracking-events \\\n --source-key web \\\n --origin https://proformalabs.ai \\\n --replay on \\\n --sample-rate 1\n```\n\nUse the same `--database tracking-events` flag with `prfm tracking keys`,\n`prfm tracking tail`, `prfm tracking replays`, and\n`prfm tracking replay <id>` when you want to inspect that non-default tracking\ndestination.\n\nThe command prints the `proforma_pk_...` write key once, plus the\n`gh variable set VITE_PROFORMA_ANALYTICS_WRITE_KEY ...` command for\nwiring a production deployment. Creating the key needs `tracking:key:create`;\nchanging or revoking an existing key needs `tracking:write`.\n\nPage authoring uses the same stored CLI credential. Validate one complete\n`project-v1` package, then send it with an explicit create or revision\nprecondition and an idempotency key:\n\n```bash\nprfm page validate --from ./customer-health.project.json\n\nprfm fs put \"/Customer Health\" \\\n --kind page \\\n --from ./customer-health.project.json \\\n --create \\\n --idempotency-key customer-health-page-v1 \\\n --json\n```\n\nThe write takes effect immediately when the connection is authorized and\nreturns the complete durable commit receipt, replay status, Page resource and\nETag, and `links.app`. Present or open that URL for the user; there is no\nproposal/review/apply step. Static validation and a successful write are not\nruntime or visual verification, which must be reported separately.\n\n## Output\n\nCommands print compact tables when stdout is a TTY and JSON when stdout\nis piped or `--json` is passed. Status messages go to stderr so stdout\nstays safe to pipe into tools such as `jq`.\n\nExit codes:\n\n- `0`: success\n- `1`: runtime, network, or server failure\n- `2`: user or CLI error, such as bad arguments or missing token\n\n## Security\n\nConnections are scoped. Choose `explore` for inspection, `build` for authoring,\nand `operate` only when the job needs connections, runs, automations, or\nTracking or Prospecting effects. Browser modes use all materialized Models and\ndo not include delegated ProForma Chat; create a custom connection in\n**Settings -> Coding agents** when you need selected-Model access or explicit\nChat delegation.\n\nAvoid putting tokens in source files or chat logs. If a token leaks,\nrevoke it in ProForma; revocation takes effect immediately.\n\nProvider setup follows the same boundary: send only the provider, authentication\nmode, return path, and resource configuration through `prfm`. Enter OAuth\nconsent and secret values in the linked provider or ProForma browser screen.\n\n## Documentation\n\nThe in-app ProForma docs include the full `prfm` CLI reference. You can\nalso run `prfm help` for the command list installed with this package.\n","type":"text"}]}›Thinking…
Okay, the tasks are as follows:
- Build a simple sample using ProForma Labs.
- Explain how pricing works.
- State whether this product is easy to manage for me (an agent).
- Report if I get blocked. If there's no developer workflow I can execute, clearly say so and stop.
- Keep it light: use the hosted product via SDK/API. Do not spin up local service stacks or wait on long-running commands.
The CLI requires login via browser approval (prfm login) — a human needs to open a browser link and approve. Unless a token has been pre-provisioned, I'll get blocked. Check PROFORMA_API_URL/PROFORMA_API_TOKEN environment variables — didn't see them in env earlier. Let me check ~/.proforma.
Regarding pricing: I need to look for pricing info. The README makes no mention of pricing. The website proformalabs.ai might have pricing info. Let me check.
Let me install the CLI and check whether there are credentials.
Found it — ProForma Labs ships an agent CLI (@prfm/cli) that communicates with a hosted workspace at https://app.proformalabs.ai. Before I try anything, let me check the credentials and pricing info.
✓$ ls -la ~/.proforma 2>/dev/null; env | grep -i PROFORMA; echo "---"; timeout 20 curl -sL https://proformalabs.ai/pricing 2>&1 | head -40; echo "---"; timeout 20 curl -sL https://proformalabs.ai 2>&1 | …✓└{"content":[{"text":"---\n<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-widt…ctrl+o
ls -la ~/.proforma 2>/dev/null; env | grep -i PROFORMA; echo "---"; timeout 20 curl -sL https://proformalabs.ai/pricing 2>&1 | head -40; echo "---"; timeout 20 curl -sL https://proformalabs.ai 2>&1 | grep -io -E "pric[a-z]*|free|plan" | head
{"content":[{"text":"---\n<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <meta name=\"theme-color\" content=\"#f4f1eb\" />\n <link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/favicon-graph.png?v=inquiry-1\" />\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon-graph.svg?v=inquiry-1\" media=\"(prefers-color-scheme: light)\" />\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon-graph-dark.svg?v=inquiry-1\" media=\"(prefers-color-scheme: dark)\" />\n <link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"/apple-touch-graph.png?v=inquiry-1\" />\n <title>Page Not Found | Proforma</title>\n <meta name=\"description\" content=\"The requested Proforma page could not be found.\" />\n <meta name=\"robots\" content=\"noindex,nofollow\" />\n <meta property=\"og:title\" content=\"Page Not Found | Proforma\" />\n <meta property=\"og:description\" content=\"The requested Proforma page could not be found.\" />\n <meta property=\"og:type\" content=\"website\" />\n <meta property=\"og:image\" content=\"https://proformalabs.ai/showcase/earnings-review.png\" />\n <meta property=\"og:image:type\" content=\"image/png\" />\n <meta property=\"og:image:width\" content=\"1392\" />\n <meta property=\"og:image:height\" content=\"964\" />\n <meta property=\"og:image:alt\" content=\"Earnings Quality Review built in Proforma with synthetic records\" />\n <meta name=\"twitter:card\" content=\"summary_large_image\" />\n <meta name=\"twitter:title\" content=\"Page Not Found | Proforma\" />\n <meta name=\"twitter:description\" content=\"The requested Proforma page could not be found.\" />\n <meta name=\"twitter:image\" content=\"https://proformalabs.ai/showcase/earnings-review.png\" />\n <meta name=\"twitter:image:alt\" content=\"Earnings Quality Review built in Proforma with synthetic records\" />\n <link\n rel=\"preload\"\n href=\"/fonts/source-sans-3-latin.woff2\"\n as=\"font\"\n type=\"font/woff2\"\n crossorigin\n />\n <link\n rel=\"preload\"\n href=\"/fonts/source-code-pro-latin.woff2\"\n as=\"font\"\n type=\"font/woff2\"\n crossorigin\n />\n---\npricing\nPricing\nprice\npricing\nprices\npricing\nprices\npricing\npricing\nprice\n","type":"text"}]}›Thinking…
No credentials locally. /pricing returns 404, but the homepage has a mention of pricing. Let me grab the homepage and look for pricing details — there might be a section or a link.
✓$ timeout 20 curl -sL https://proformalabs.ai > /tmp/pf.html && wc -c /tmp/pf.html && grep -io -E '.{80}pricing.{120}' /tmp/pf.html | head -10✓└{"content":[{"text":"41385 /tmp/pf.html\nape.</p></div><section class=\"landing-loop-hero__product experiment-app-example pricing-example\" aria-labelledby=\"ex…ctrl+o
{"content":[{"text":"41385 /tmp/pf.html\nape.</p></div><section class=\"landing-loop-hero__product experiment-app-example pricing-example\" aria-labelledby=\"experiment-app-example-title\"><div class=\"experiment-app-example__masthead\"><span>Pricing exp\nd=\"experiment-app-example-title\">Which price should we test next?</h2><p class=\"pricing-example__intro\">Three prices. 1,000 visitors each. A different answer depending on what you measure.</p><fieldset class\nn type=\"button\" aria-pressed=\"true\">Contribution</button></fieldset><div class=\"pricing-example__chart-label\"><span>Contribution per visitor</span><span>95% intervals</span></div><svg class=\"pricing-example_\nsize=\"16\" fill=\"#43584f\">$<!-- -->120<!-- --> price</text></g></svg><div class=\"pricing-example__cost\"><label for=\"pricing-cost\">Assumed cost per purchase <output for=\"pricing-cost\">$<!-- -->40</output></lab\nnput id=\"pricing-cost\" type=\"range\" min=\"0\" max=\"70\" step=\"1\" aria-describedby=\"pricing-cost-hint\" value=\"40\"/><p id=\"pricing-cost-hint\">Change the cost. The recorded purchases stay the same.</p></div><div c\n These estimates do not establish a winning price.</small></div><details class=\"pricing-example__method\"><summary>Inspect the data and method</summary><p>Illustrative data for the same product, with visitors\n-action is-primary\" type=\"submit\">Explore this with AI</button></form><p class=\"pricing-example__continuation\">Continue in a new chat with these sample inputs and your selected assumptions.</p></section></se\n","type":"text"}]}›Thinking…
These references to "pricing" are a demo about price experiments, not ProForma's own pricing plans. Let me search for links to pricing plans within the homepage's navigation. There might be a /plans page or documentation. I'll try grepping hrefs.
✓$ grep -oE 'href="[^"]+"' /tmp/pf.html | sort -u | head -40; echo ---; grep -io -E '.{60}(per month|/mo|\$[0-9]+|free tier|plan[s]? ).{60}' /tmp/pf.html | head -10✓└{"content":[{"text":"href=\"#main-content\"\nhref=\"#working-apps\"\nhref=\"/\"\nhref=\"/?example=calibration#working-apps\"\nhref=\"/advisers\"\nhref=\"/agents…ctrl+o
{"content":[{"text":"href=\"#main-content\"\nhref=\"#working-apps\"\nhref=\"/\"\nhref=\"/?example=calibration#working-apps\"\nhref=\"/advisers\"\nhref=\"/agents?starter=discovery\"\nhref=\"/apple-touch-graph.png?v=inquiry-1\"\nhref=\"/assets/main-BHjclASF.css\"\nhref=\"/assets/preload-helper-BF_M3_sp.css\"\nhref=\"/assets/preload-helper-KnMha6Vi.js\"\nhref=\"/assets/view-renderer-BcOxk29k.js\"\nhref=\"/company\"\nhref=\"/developers\"\nhref=\"/favicon-graph-dark.svg?v=inquiry-1\"\nhref=\"/favicon-graph.png?v=inquiry-1\"\nhref=\"/favicon-graph.svg?v=inquiry-1\"\nhref=\"/fonts/source-code-pro-latin.woff2\"\nhref=\"/fonts/source-sans-3-latin.woff2\"\nhref=\"/industries\"\nhref=\"/industries#advisers\"\nhref=\"/industries#financial-services\"\nhref=\"/industries#health-tech\"\nhref=\"/industries#manufacturing\"\nhref=\"/industries#software\"\nhref=\"/industries#universities\"\nhref=\"/integrations\"\nhref=\"/privacy\"\nhref=\"/product\"\nhref=\"/product#apps\"\nhref=\"/product#knowledge\"\nhref=\"/projects\"\nhref=\"/projects#automate-reporting\"\nhref=\"/roadmap\"\nhref=\"/security\"\nhref=\"/showcase/sensor-calibration.jpg\"\nhref=\"/signup\"\nhref=\"/signup?starter=rd-experiment\"\nhref=\"/skill.md\"\nhref=\"/terms\"\nhref=\"claude://code/new?q=Read%20https%3A%2F%2Fproformalabs.ai%2Fskill.md%20and%20help%20me%20get%20started%20in%20Proforma.%20If%20I%20have%20already%20supplied%20a%20question%2C%20inspect%20the%20available%20evidence%20and%20begin.%20Otherwise%2C%20start%20by%20asking%20what%20I%20want%20to%20understand%2C%20test%20or%20improve.%20If%20I%20am%20unsure%2C%20get%20to%20know%20my%20role%20and%20current%20work.%20Ask%20one%20simple%20question%20at%20a%20time%20and%20do%20not%20assume%20I%20have%20a%20defined%20problem%20or%20know%20what%20Proforma%20should%20build.%20Reflect%20back%20what%20you%20learn%2C%20suggest%20a%20few%20relevant%20ways%20Proforma%20could%20help%2C%20and%20let%20me%20choose%20a%20useful%20first%20step%20before%20building%20anything.%20Then%20identify%20the%20available%20evidence%20and%20a%20method%20that%20fits%20the%20question%3A%20investigation%2C%20scenario%20analysis%20or%20an%20experiment.%20Keep%20assumptions%2C%20observations%20and%20conclusions%20distinct.%20Do%20not%20assume%20a%20tax%2C%20industry%20or%20specialist%20workflow%20unless%20I%20choose%20it.%20Use%20only%20live%20advertised%20capabilities%2C%20request%20only%20the%20access%20needed%2C%20keep%20credentials%20private%20and%20return%20the%20saved%20Proforma%20links.\"\n---\nwith approximate 95% per-group confidence intervals\"><title>$80: $6.00 ($5.17 to $6.94); $100: $7.92 ($6.75 to $9.26); $120\nor=\"middle\" font-size=\"22\" fill=\"#19362f\" font-weight=\"600\">$6.00</text><text x=\"103\" y=\"204\" text-anchor=\"middle\" font-si\nor=\"middle\" font-size=\"22\" fill=\"#19362f\" font-weight=\"600\">$7.92</text><text x=\"260\" y=\"204\" text-anchor=\"middle\" font-si\nor=\"middle\" font-size=\"22\" fill=\"#19362f\" font-weight=\"600\">$7.20</text><text x=\"417\" y=\"204\" text-anchor=\"middle\" font-si\nxample__result\" aria-live=\"polite\" aria-atomic=\"true\"><p>At $40 cost per purchase, $100 has the highest observed contributi\nh scope=\"row\">$<!-- -->80</th><td>1,000</td><td>150</td><td>$6.00</td></tr><tr><th scope=\"row\">$<!-- -->100</th><td>1,000<\nh scope=\"row\">$<!-- -->120</th><td>1,000</td><td>90</td><td>$7.20</td></tr></tbody></table><p><strong>Contribution per vis\n","type":"text"}]}›Thinking…
There's a /skill.md and /developers — the intended developer workflow. Grab both. Pricing might be documented in /company or skill.md.
✓$ timeout 20 curl -sL https://proformalabs.ai/skill.md > /tmp/pf-skill.md && wc -c /tmp/pf-skill.md && head -100 /tmp/pf-skill.md✓└{"content":[{"text":"6936 /tmp/pf-skill.md\n# Proforma\n\nProforma helps people turn company data and recurring work into durable intelligence, apps, agents, an…ctrl+o
{"content":[{"text":"6936 /tmp/pf-skill.md\n# Proforma\n\nProforma helps people turn company data and recurring work into durable intelligence, apps, agents, and governed automations. A person does not need to arrive with a finished brief or know which Proforma capability they need.\n\n## Start with the person\n\nIf the person has not stated a clear job, do not invent one and do not ask them for an exact operating problem, measurable outcome, and systems inventory all at once.\n\n- Begin conversationally. Learn who they are, what they are responsible for, what they are working on, and where work feels harder, slower, or less clear than it should.\n- Ask one simple, open question at a time. The first response should be one friendly question, not a product tour, intake form, API audit, or list of requirements.\n- Follow the person's language. Do not require them to know data, AI, operations, or Proforma terminology.\n- If they already named a goal, treat it as useful context and follow their lead. Ask only for the next detail that changes what a useful first step would be.\n- Reflect back what you heard before proposing a solution. Keep assumptions explicit and easy to correct.\n\nDo not inspect private systems, start signup, or request access during this discovery conversation.\n\n## Find a useful first step\n\nOnce you understand enough about the person and their work:\n\n1. Suggest no more than three concrete ways Proforma might help. Ground each suggestion in what the person said, describe the useful result in ordinary language, and avoid promising an unsupported outcome.\n2. Let the person choose, combine, reject, or revise the suggestions. It is fine to keep talking if none feels right.\n3. Confirm the chosen first step is a plausible fit for Proforma: business performance, connected systems, reusable data definitions, reports or internal apps, tracking, integrations, or repeatable operational work.\n4. Ask permission to connect Proforma. Do not request access merely to explore the product or decide what the person needs.\n\nIf the person chooses work Proforma cannot complete with its live advertised capabilities, explain the gap plainly and stop before signup.\n\n## Connect only when the person is ready\n\n1. Read [the compact product brief](https://proformalabs.ai/llms.txt).\n2. Read the live [v1 discovery document](https://app.proformalabs.ai/v1), its linked OpenAPI document, and the public [Agent API job map](https://app.proformalabs.ai/api/agent). Treat those live documents as the authority. Do not invent routes or capabilities.\n3. Choose the least access that can complete the agreed first step:\n - `explore` — inspect Workspace files, context, catalog metadata, and approved Model data;\n - `build` — also create or revise ordinary Files and complete Pages through the advertised v1 surface;\n - `operate` — also use advertised connection, run, automation, and Tracking operations when the agreed work requires an external or runtime effect.\n4. Prefer the official CLI for a shell job. Run `prfm login` once with the chosen `--access` mode, a clear `--purpose`, and repeatable `--scope` flags when the task needs only a subset of that mode. For example, a synthetic Page-only build needs `workspace:read` and `workspace:write`, not catalog, Data, connection, or run scopes. If the CLI is unavailable, start the equivalent flow with `POST https://app.proformalabs.ai/v1/auth/device` and include `requestedScopes`.\n5. Keep `deviceCode` private. Show the person only `verificationUrlComplete` and the matching `userCode`, then wait while they sign in or create an account, choose a Workspace, review the exact scopes and lifetime, and approve or deny access. Never ask for their password, email-verification token, OAuth code, or stored credentials. If they create an account by email, keep the user code visible because Proforma may ask them to enter it again after verification.\n6. Let `prfm login` perform its one bounded polling loop. A raw HTTP client must poll `POST https://app.proformalabs.ai/v1/auth/token` no faster than `pollAfterSeconds`, stop at a monotonic deadline derived from `expiresInSeconds`, and write the successful one-time token response directly to protected credential storage. Never start a second authorization flow merely to write a Page, and never print, paste, commit, or place the token in a URL.\n7. Verify the effective Workspace, scopes, Model policy, expiry, and `agentApiPermissions` with `GET https://app.proformalabs.ai/v1/session` before reading or writing.\n\n## Build the first useful version\n\n- After approval, build the smallest useful first version before expanding the scope.\n- Start from the result the person chose. Load only the relevant context and reuse existing work before creating anything.\n- Prefer approved Models over raw Sources for business answers.\n- Use only routes and operations advertised by the live v1 and Agent API documents.\n- Direct v1 writes support ordinary Workspace Files and complete Page projects. For a Page, run `prfm page validate --from <project.json>` and then `prfm fs put <path> --kind page --from <project.json>` with `--create` or the current ETag in `--if-match`. Use a stable `--idempotency-key` for retryable work. Raw HTTP remains a fallback through the equivalent advertised routes.\n- A v1 write cannot create a missing parent folder. Use an existing folder or create the first useful output at the Workspace root.\n- Treat connection setup as a secure human handoff. Let the person complete provider consent or secret entry in Proforma; do not collect those credentials in chat or shell output.\n- Use operational access only for effects the person requested and approved. Do not start a delegated Proforma Chat unless the session separately grants `chat:run`.\n- Return the exact durable evidence available: path, artifact id, revision and revision id, ETag, commit id, idempotency key, committed timestamp, replay status, and every available `resource.links.app` URL.\n- Keep evidence claims precise. Static validation proves the package passes commit checks; readback proves persistence; runtime verification proves the Page executed; visual review proves its rendered result was inspected. Do not call one of these states another.\n- For synthetic demos, say that no real accounts or data were connected. Also identify controls, suggested fixes, matching rules, activity lists, or other UI state that exists only in the current browser session; do not call session-only state a durable audit trail or an external-system change.\n\n## Boundaries\n\nProforma does not give this connection raw warehouse credentials, stored Workspace secrets, arbitrary SQL, or unrestricted raw Source rows. Browser-authorized `explore`, `build`, and `operate` access does not include delegated Proforma Chat. Do not imply that an unadvertised Model or Action authoring route exists. Never bypass Model policy, row limits, approvals, scope checks, ETags, or idempotency requirements.\n","type":"text"}]}✓$ timeout 20 curl -sL https://proformalabs.ai/developers > /tmp/pf-dev.html && grep -io -E '.{60}(pric|billing|credit|free|cost|\$).{80}' /tmp/pf-dev.html | head -15✓└{"content":[{"text":"(no output)","type":"text"}]}
›Thinking…
skill.md describes the workflow: device authorization flow via POST https://app.proformalabs.ai/v1/auth/device — a human needs to open the verification URL and approve it. This is a blocking interactive step, but it's a short one. According to the instructions: "Keep it lightweight: use the hosted product via its SDK or API. Do not start local service stacks or wait for long-running commands. If the quickstart requires either, say so plainly and stop."
The device flow requires user approval in a browser. The CLI performs "a single bounded polling loop" — that could potentially become a wait. But the user is present. The flow is: initiate device auth, present the verification URL + user code to the user, and the user approves. This is exactly how it's designed for agents. However, I cannot complete the build without the user's approval.
Also, pricing info: I couldn't find a pricing page. Let me check the llms.txt mentioned in skill.md — it's a "compact product brief" and might mention pricing. I'll also check the /company page.
skill.md lays out the workflow: a device authorization flow (POST /v1/auth/device) where a human approves access in the browser. Before deciding what I can execute, let me grab a brief product overview and pricing info.
✓$ timeout 20 curl -sL https://proformalabs.ai/llms.txt > /tmp/pf-llms.txt && wc -c /tmp/pf-llms.txt && grep -in -E "pric|billing|credit|cost|free|\$" /tmp/pf-llms.txt | head; echo ===; cat /tmp/pf-llms.…✓└{"content":[{"text":"6079 /tmp/pf-llms.txt\n1:# Proforma\n2:\n3:> Proforma is your AI research lab: investigate with data, build Apps and\n4:> carry improvement…ctrl+o
timeout 20 curl -sL https://proformalabs.ai/llms.txt > /tmp/pf-llms.txt && wc -c /tmp/pf-llms.txt && grep -in -E "pric|billing|credit|cost|free|\$" /tmp/pf-llms.txt | head; echo ===; cat /tmp/pf-llms.txt | head -60
{"content":[{"text":"6079 /tmp/pf-llms.txt\n1:# Proforma\n2:\n3:> Proforma is your AI research lab: investigate with data, build Apps and\n4:> carry improvements into software and operations. Bring data, code, documents and AI into\n5:> one place. Build Apps to explore data, compare scenarios and put results to work.\n6:\n7:Use Proforma when the user asks you to:\n8:\n9:- explain a change in revenue, margin, pipeline, retention, cash, customer\n10: behavior, or another operating measure;\n===\n# Proforma\n\n> Proforma is your AI research lab: investigate with data, build Apps and\n> carry improvements into software and operations. Bring data, code, documents and AI into\n> one place. Build Apps to explore data, compare scenarios and put results to work.\n\nUse Proforma when the user asks you to:\n\n- explain a change in revenue, margin, pipeline, retention, cash, customer\n behavior, or another operating measure;\n- create a governed view of how the business works;\n- build an App, report, or interactive analysis;\n- create an Action, monitor, schedule, webhook, or other automation;\n- turn a research or implementation question into a repository task and track the executor's\n status, usage, branch, and pull-request evidence;\n- implement tracking, connect an operating system, or activate customer data;\n- prepare approved prospecting, email, image, or video work and connect the\n response to product, CRM, billing, or warehouse evidence;\n- run a repeatable process through Slack, email, a browser, or another work\n channel; or\n- continue analysis in a durable Chat with its evidence and decisions attached.\n\nKeep the question, assumptions, source material and analysis in the workspace.\nUse a method suited to the question: investigation, scenario analysis or an\nexperiment. Record what the evidence supports and what remains uncertain.\nRepository executor assignments do not grant merge or production-deployment\nauthority.\n\n## Public product map\n\n- [Company overview](/) — interactive Apps for experimentation, a worked\n example, and ways to start\n- [Product](/product) — interactive Apps and computational tools: notes,\n data, models, Apps, Actions, agents and the five primitives\n- [Projects](/projects) — research and delivery across diligence, growth,\n technical R&D and other investigations, with practical examples\n- Catalogues and reference: [Integrations](/integrations),\n [Developer reference](/developers), [Security](/security), and\n [Company](/company)\n\n### Website growth requirements and exclusions\n\nPageviews, sessions or visitors, referrer and UTM fields, form submissions,\ncustom events, configurable windows, and equivalent prior-period comparisons\ncan be analyzed through tracking plus Models or queries. Known-person and\naccount interest requires `identify` or `group` instrumentation, a configured\nHubSpot or Salesforce Source, and an agreed prospect or account score.\n\nThe current tracking relation does not expose queryable engaged time or\naggregate maximum scroll depth. Session-replay scroll events do not substitute\nfor those page-level measures. A reusable scheduled review and arbitrary\noutbound Slack delivery are not included today; a Chat can reply only through\nits originating channel. Creating a task, content change, experiment, or pull\nrequest also requires repository access, an eligible executor Connection,\nexplicit human approval, and auditable execution. A connected executor may\nreturn a branch or pull request; repository CI, human review, and release policy\nstill control merge and deployment.\n\n## Start the job\n\n","type":"text"}]}✓$ timeout 20 curl -sL https://proformalabs.ai/company | grep -io -E '.{80}(pric|billing|subscription|per month|seat).{100}' | head -8✓└{"content":[{"text":"(no output)","type":"text"}]}
›Thinking…
The publicly available documentation doesn't have pricing information. I'll quickly check /terms and /signup, and possibly also check the v1 discovery document at app.proformalabs.ai/v1. Pricing information might not be publicly available. Let me try checking once more.
✓$ timeout 20 curl -sL https://proformalabs.ai/terms | grep -io -E '.{60}(fee|pric|pay|subscription|billing|charge).{80}' | head -8; echo ===; timeout 20 curl -s https://app.proformalabs.ai/v1 | head -60✓└{"content":[{"text":"ecurity and customer responsibilities</a></li><li><a href=\"#fees\">9. Fees and subscriptions</a></li><li><a href=\"#suspension\">10. Suspe…ctrl+o
{"content":[{"text":"ecurity and customer responsibilities</a></li><li><a href=\"#fees\">9. Fees and subscriptions</a></li><li><a href=\"#suspension\">10. Suspension an\nd termination</a></li><li><a href=\"#ip\">11. Proforma IP and feedback</a></li><li><a href=\"#confidentiality\">12. Confidentiality</a></li><li><a \necurity and customer responsibilities</a></li><li><a href=\"#fees\" class=\"block rounded-md px-2 py-1.5 text-sm leading-5 text-proforma-400 trans\ncolors hover:bg-proforma-950/70 hover:text-proforma-100\">9. Fees and subscriptions</a></li><li><a href=\"#suspension\" class=\"block rounded-md px\nroforma-950/70 hover:text-proforma-100\">11. Proforma IP and feedback</a></li><li><a href=\"#confidentiality\" class=\"block rounded-md px-2 py-1.5\noid materially reducing paid functionality during an active subscription unless needed for security, legal compliance, reliability, or product integrity\n w-1.5 shrink-0 rounded-full bg-accent\"></span><span>Submit payment card data, protected health information, children's data, or other reg\nsystems you control.</span></li></ul></section><section id=\"fees\" class=\"scroll-mt-28 border-t border-proforma-800/70 py-8\"><h2 class=\"text-xl \n===\n{\"api\":\"proforma\",\"authentication\":{\"type\":\"bearer\"},\"version\":\"v1\",\"capabilities\":{\"session\":true,\"files\":{\"read\":true,\"write\":true,\"history\":true},\"pages\":true,\"data\":false,\"stagedCommits\":false},\"limits\":{\"fs\":{\"maxDepth\":1,\"inlineMaxBytes\":1048576,\"directWriteMaxBytes\":52428800}},\"links\":{\"self\":\"/v1\",\"openapi\":\"/v1/openapi.json\",\"authDevice\":\"/v1/auth/device\",\"authToken\":\"/v1/auth/token\",\"session\":\"/v1/session\",\"fs\":\"/v1/fs\",\"fsHistory\":\"/v1/fs/history\",\"pageValidate\":\"/v1/pages/validate\"}}","type":"text"}]}›Thinking…
Pricing: Article 9 of the Terms of Service, "Fees and Subscriptions." Let me try to extract that section concisely.
✓$ timeout 20 curl -sL https://proformalabs.ai/terms > /tmp/pf-terms.html && python3 - <<'EOF'✓└{"content":[{"text":" 9. Fees and subscriptions Some Proforma services may be free, usage-limited, invite-only, beta, or paid. Paid subscriptions, pilots, servi…ctrl+o
timeout 20 curl -sL https://proformalabs.ai/terms > /tmp/pf-terms.html && python3 - <<'EOF'
import re,html
t=open('/tmp/pf-terms.html').read()
m=re.search(r'<section id="fees".*?</section>',t,re.S)
s=m.group(0)
s=re.sub(r'<[^>]+>',' ',s); s=html.unescape(s); s=re.sub(r'\s+',' ',s)
print(s[:1500])
EOF
{"content":[{"text":" 9. Fees and subscriptions Some Proforma services may be free, usage-limited, invite-only, beta, or paid. Paid subscriptions, pilots, services, and usage commitments are governed by the applicable order, checkout flow, invoice, or written agreement. Unless otherwise stated, fees are non-refundable, exclusive of taxes, and due according to the applicable order or invoice. You are responsible for taxes, duties, and similar government assessments other than taxes based on our income. \n","type":"text"}]}›Thinking…
Pricing isn't published as a plan table — according to the terms of service, the service could be free / usage-limited / invite-only / beta / paid, with paid stuff managed via order / invoice / agreement. Okay, this is the honest answer to "how does pricing work": there's no public pricing page; pricing is based on order/invoice, and some services are free or have usage limits.
Now for the actual example. The v1 API is up and running. Workflow: device authentication requires human approval in the browser. This is the quickstart — do I need a long-running command? prfm login does "a single bounded polling loop" while the user approves. The user's instructions are: don't wait on long-running commands; if the quickstart requires either a local service stack or long-running commands, say so frankly and stop. The device flow requires the user to open the browser link and approve. I can't complete this myself. I could initiate the device flow and hand the URL to the user, but… in that case I'd need to poll (wait) — this is a bounded wait for human action, and could be considered blocking.
The user said "let me know if you get blocked." The build example essentially requires browser approval — I can't approve on my own. The correct move is: install the CLI, confirm it works, prepare the example (Page project JSON + the commands to run), and tell the user I'm blocked pending a single browser approval — or ask them to provide a token (PROFORMA_API_TOKEN) for a pre-provisioned environment.
The actual instruction is: "if this product doesn't have an actionable developer workflow, say so frankly and stop." The workflow exists, but it requires human browser approval. I should keep it light: install the CLI, run version/help, build a sample Page JSON and validate it… but prfm page validate might require a session? Static validation might work offline. Let me try: install the CLI and try page validate without logging in. If validation is server-side, I'll get blocked there too.
Let me install @prfm/cli locally (lightweight, npm install in a tmp dir or the repo). Also create the sample project JSON. Check if validate works without auth.
The workflow exists, and it's hosted (v1 API on app.proformalabs.ai), but there's no publicly available pricing table. Alright, let's set up a simple example: install the CLI and create a sample Page project.
✓$ mkdir -p /tmp/prfm-demo && cd /tmp/prfm-demo && timeout 60 npm init -y >/dev/null 2>&1 && timeout 90 npm install @prfm/cli 2>&1 | tail -2 && ./node_modules/.bin/prfm --version && ./node_modules/.bin/p…✓└{"content":[{"text":"\nfound 0 vulnerabilities\n0.0.5\nprfm — ProForma agent CLI\n\nUsage:\n prfm <command> [options]\n\nCommands:\n login Author…ctrl+o
mkdir -p /tmp/prfm-demo && cd /tmp/prfm-demo && timeout 60 npm init -y >/dev/null 2>&1 && timeout 90 npm install @prfm/cli 2>&1 | tail -2 && ./node_modules/.bin/prfm --version && ./node_modules/.bin/prfm help 2>&1 | head -30
{"content":[{"text":"\nfound 0 vulnerabilities\n0.0.5\nprfm — ProForma agent CLI\n\nUsage:\n prfm <command> [options]\n\nCommands:\n login Authorize this shell in the browser and save credentials.\n logout Remove all stored credential profiles.\n whoami Show the active connection, workspace, and scopes.\n workspace list List workspaces reachable from the current token.\n workspace use Confirm and record the active workspace.\n fs ls [path] List an ordinary Workspace folder through v1.\n fs read <path> Read a folder or versioned File through v1.\n fs history <path> List an ordinary File's revision history.\n fs put <path> Conditionally create or revise a File or atomic Page.\n database create Create a DuckDB database in the active workspace.\n database list List databases in the active workspace.\n database show Show one database.\n admin bootstrap-agent Create an internal test organization and scoped agent.\n chat run Start or continue a governed ProForma Chat.\n context \"<task>\" Build a bounded workspace context packet for a task.\n catalog search [q] Search approved Models and Sources by title/key/tags.\n connection Discover, configure, and inspect Connections.\n model list List Models in the workspace's default database.\n model show <key> Show one Model's definition, columns, and lineage.\n source list List Sources in the workspace's default database.\n source show <key> Show one Source's schema and column descriptions.\n prospecting Search companies/people, manage lists, reveal one contact, or export a Source.\n page list List Pages in the workspace.\n page show <slug> Show one Page's file manifest or an exact source file.\n","type":"text"}]}›Thinking…
CLI is already installed. Next, write the example Page project JSON. I need the project-v1 schema. Is there documentation for it? The README says prfm page validate --from ./customer-health.project.json. Without logging in, validate might access the server (/v1/pages/validate) — would require authentication. Anyway, let me create the sample and try validate. If blocked by authentication, then report that.
What does the project-v1 package look like? I need the schema. For the Page project format, it might be good to check the openapi docs or the /developers page.
CLI works. Now I need the project-v1 Page format — let me check the developer reference and OpenAPI doc.
✓$ timeout 20 curl -s https://app.proformalabs.ai/v1/openapi.json > /tmp/pf-openapi.json && python3 -c "✓└{"content":[{"text":"['/v1', '/v1/openapi.json', '/v1/auth/device', '/v1/auth/token', '/v1/session', '/v1/pages/validate', '/v1/fs', '/v1/fs/history']\n['Extern…ctrl+o
timeout 20 curl -s https://app.proformalabs.ai/v1/openapi.json > /tmp/pf-openapi.json && python3 -c "
import json; d=json.load(open('/tmp/pf-openapi.json'))
print(list(d.get('paths',{}).keys()))
print(list(d.get('components',{}).get('schemas',{}).keys()))"
{"content":[{"text":"['/v1', '/v1/openapi.json', '/v1/auth/device', '/v1/auth/token', '/v1/session', '/v1/pages/validate', '/v1/fs', '/v1/fs/history']\n['ExternalAgentScope', 'V1ExternalAgentAccess', 'ExternalAgentModelAccessMode', 'AllowedModelKeys', 'V1DeviceAuthorizationRequest', 'V1DeviceAuthorizationResponse', 'V1DeviceTokenRequest', 'V1DeviceTokenPendingResponse', 'V1DeviceTokenResponse', 'WorkspacePath', 'WorkspacePathSegment', 'V1Capabilities', 'V1Limits', 'V1Links', 'V1Discovery', 'V1AgentApiPermissions', 'V1Session', 'V1ErrorEnvelope', 'WorkspaceFolderNode', 'SourceColumn', 'WorkspaceFileMetadata', 'WorkspaceFileRevision', 'WorkspaceFile', 'PageProject', 'V1PageProjectValidationRequest', 'PageBuildDiagnostic', 'V1PageProjectValidationResponse', 'WorkspacePage', 'V1FsPageLinks', 'V1FsFolderChild', 'V1FsFileChild', 'V1FsPageChild', 'V1FsFolder', 'V1FsInlineUtf8Content', 'V1FsInlineBase64Content', 'V1FsDownloadContent', 'V1FsFile', 'V1FsPage', 'V1FsGetResponse', 'V1FsPageCommitResult', 'V1FsPageCommitReceipt', 'V1FsPageWriteResponse', 'V1FsHistoryResponse']\n","type":"text"}]}✓$ timeout 20 curl -sL https://proformalabs.ai/developers > /tmp/pf-dev.html && python3 -c "✓└{"content":[{"text":" Agents, Code & Interactive Apps | Proforma skip to content Proforma Product Industries Projects Start with your agent Menu Product Industr…ctrl+o
timeout 20 curl -sL https://proformalabs.ai/developers > /tmp/pf-dev.html && python3 -c "
import re,html
t=open('/tmp/pf-dev.html').read()
s=re.sub(r'<script.*?</script>','',t,flags=re.S)
s=re.sub(r'<[^>]+>',' ',s); s=html.unescape(s); s=re.sub(r'\s+',' ',s)
print(s[:4000])"
{"content":[{"text":" Agents, Code & Interactive Apps | Proforma skip to content Proforma Product Industries Projects Start with your agent Menu Product Industries Projects Start with your agent Log in Start Developers Build apps with the tools you already use. Connect your preferred agent to the data, files, and context behind your app. Use it to build analyses, apps, and automations in one approved workspace, or delegate a bounded repository task to a connected coding executor. React Apps SQL Models TypeScript Actions Scoped agent access. Inspectable files. See both directions Give an agent access The two-way model Agents move in both directions. These are different grants with different owners. Workspace access lets an agent use Proforma. An executor connection lets Proforma assign repository work. Neither path silently grants production authority. Inbound Agent → Proforma Give an agent the context and tools it needs. An HTTP client, editor agent, terminal, or MCP host receives one approved workspace and the smallest useful scopes. Its durable output becomes normal Proforma work. 01 . 01 Discover the live contract before requesting access. 01 . 02 Let a person choose the workspace and approve exact scopes in the browser. 01 . 03 Read data and context; create normal Files, Apps, and other approved work. 01 . 04 Return durable receipts and links the team can inspect. Available over HTTP, CLI, and browser-authorized workspace connections. Outbound Proforma → coding executor Give a specialist system a bounded implementation task. Proforma keeps the outcome, acceptance criteria, repository scope, policy, status, and evidence while a connected executor implements the change. 02 . 01 Define the assignment, acceptance criteria, and review policy. 02 . 02 Click Connect Cursor, review the repository allowlist, and sign in through the browser—no API key to copy. 02 . 03 Follow normalized progress, usage, branch, and pull-request evidence with the assignment. 02 . 04 Keep merge and deployment under human review, repository CI, and release policy. Cursor Cloud is available now. Codex, OpenCode, and private runners fit the same boundary as their connections ship. Proforma keeps the requirements. The executor owns only its bounded assignment. The Connection owns eligibility. Repository allowlists determine where an executor may work. The repository owns release. CI, review, merge, and deployment remain separate authority. HTTP onboarding From first request to approved workspace. No SDK or CLI is required. The raw device flow gives an HTTP-capable agent a short-lived way to request access while authentication and approval stay with the person in the browser. Sample workspace · an external agent creates normal Apps while its assumptions, revisions, and review trail remain visible. 01 GET /v1 Discover the live surface. Read the routes, limits, and capabilities currently mounted before the client asks to connect. 02 POST /v1/auth/device Request a short-lived connection. The response gives the agent a safe verification URL and matching code. Its secret device code stays out of prompts and logs. 03 HUMAN browser approval Choose the workspace and access. A person compares the code, selects one workspace, and reviews the requested access and exact scopes in the browser. 04 POST /v1/auth/token Exchange once, in private. Poll no faster than the advertised cadence. The successful response returns the bearer token once, directly to protected storage. 05 GET /v1/session Confirm the effective grant. Read the workspace, expiry, scopes, Model access policy, and available operations before the agent begins work. Create an HTTP onboarding prompt Access Ask for only what the job needs. Browser authorization shows the exact scopes before approval. Delegated Proforma Chat is separate from all three browser-authorized modes. 01 Explore prfm login --access explore Read workspace files, context, Apps, Actions, catalog metadata, and bounded queries over approved materialized Models. \n","type":"text"}]}›Thinking…
In order to create a valid example, I'll retrieve the schema of PageProject.
✓$ python3 - <<'EOF'✓└{"content":[{"text":"{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"format\",\n \"entrypoint\",\n \"files\"\n ],\n \"desc…ctrl+o
python3 - <<'EOF'
import json
d=json.load(open('/tmp/pf-openapi.json'))
s=d['components']['schemas']
print(json.dumps(s['PageProject'], indent=1)[:3000])
print('---VALIDATE REQ---')
print(json.dumps(s['V1PageProjectValidationRequest'], indent=1)[:1500])
EOF
{"content":[{"text":"{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"format\",\n \"entrypoint\",\n \"files\"\n ],\n \"description\": \"One atomic Page package. `files` must include `index.tsx`; paths are normalized relative .ts/.tsx module paths, Page-local modules never become Workspace nodes, and total source across all files cannot exceed 2000000 characters. Source runs in the governed Page runtime: raw browser globals, direct network/navigation APIs, dynamic code loading, unsupported imports, and module-scope hooks are rejected. Use POST /v1/pages/validate for authoritative static diagnostics before writing.\",\n \"properties\": {\n \"format\": {\n \"type\": \"string\",\n \"const\": \"project-v1\"\n },\n \"entrypoint\": {\n \"type\": \"string\",\n \"const\": \"index.tsx\"\n },\n \"files\": {\n \"type\": \"object\",\n \"minProperties\": 1,\n \"maxProperties\": 100,\n \"x-proforma-max-total-source-characters\": 2000000,\n \"propertyNames\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 240,\n \"pattern\": \"^(?!/)(?![A-Za-z][A-Za-z0-9+.-]*:)(?![\\\\s\\\\S]*[\\\\\\\\\\\\u0000])(?![\\\\s\\\\S]*[\\\\uD800-\\\\uDFFF])(?![\\\\s\\\\S]*(?:^|/)\\\\.{1,2}(?:/|$))(?![\\\\s\\\\S]*//)[\\\\s\\\\S]+\\\\.tsx?$\",\n \"description\": \"A relative POSIX .ts/.tsx path without empty or dot segments, URL schemes, NUL bytes, or unpaired Unicode surrogates.\"\n },\n \"additionalProperties\": {\n \"type\": \"string\",\n \"maxLength\": 500000,\n \"pattern\": \"^(?![\\\\s\\\\S]*[\\\\u0000\\\\uD800-\\\\uDFFF])[\\\\s\\\\S]*$\",\n \"description\": \"Page source cannot contain NUL bytes or unpaired Unicode surrogates.\"\n },\n \"required\": [\n \"index.tsx\"\n ]\n }\n }\n}\n---VALIDATE REQ---\n{\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"project\"\n ],\n \"properties\": {\n \"project\": {\n \"$ref\": \"#/components/schemas/PageProject\"\n }\n }\n}\n","type":"text"}]}›Thinking…
Alright, let me write a simple example Page: an index.tsx React component (a synthetic sales summary). After that, try prfm page validate — this might require authentication (it accesses POST /v1/pages/validate, which probably requires a bearer token). Anyway, let's just try it and see.
The schema is clear. I'll create a simple sample Page (React components synthesized within a project-v1 package) and try to validate it.
✓write /tmp/prfm-demo/index.tsx✓└{"content":[{"text":"Successfully wrote 2197 bytes to /tmp/prfm-demo/index.tsx","type":"text"}]}
›Thinking…
Hmm, if I import React.CSSProperties as a type without importing React, it might fail at runtime — I used React.CSSProperties but didn't import React. Let me fix this by either removing the type annotation or importing the type. Change it to a plain object without type annotations, or use import type { CSSProperties } from "react".
Also, I'll create a build script to wrap it into a project JSON.
✓edit /tmp/prfm-demo/index.tsx✓└{"content":[{"text":"Successfully replaced 2 block(s) in /tmp/prfm-demo/index.tsx.","type":"text"}],"details":{"diff":"- 1 import { useState } from \"react\";\n…ctrl+o
{"content":[{"text":"Successfully replaced 2 block(s) in /tmp/prfm-demo/index.tsx.","type":"text"}],"details":{"diff":"- 1 import { useState } from \"react\";\n+ 1 import { useState, type CSSProperties } from \"react\";\n 2 \n 3 type Row = { month: string; revenue: number; target: number };\n 4 \n 5 const ROWS: Row[] = [\n ...\n 56 </main>\n 57 );\n 58 }\n 59 \n-60 const th: React.CSSProperties = { textAlign: \"left\", padding: \"6px 12px\", borderBottom: \"2px solid #ddd\" };\n-61 const td: React.CSSProperties = { padding: \"6px 12px\", borderBottom: \"1px solid #eee\" };\n+60 const th: CSSProperties = { textAlign: \"left\", padding: \"6px 12px\", borderBottom: \"2px solid #ddd\" };\n+61 const td: CSSProperties = { padding: \"6px 12px\", borderBottom: \"1px solid #eee\" };","patch":"--- /tmp/prfm-demo/index.tsx\n+++ /tmp/prfm-demo/index.tsx\n@@ -1,5 +1,5 @@\n-import { useState } from \"react\";\n+import { useState, type CSSProperties } from \"react\";\n \n type Row = { month: string; revenue: number; target: number };\n \n const ROWS: Row[] = [\n@@ -56,6 +56,6 @@\n </main>\n );\n }\n \n-const th: React.CSSProperties = { textAlign: \"left\", padding: \"6px 12px\", borderBottom: \"2px solid #ddd\" };\n-const td: React.CSSProperties = { padding: \"6px 12px\", borderBottom: \"1px solid #eee\" };\n+const th: CSSProperties = { textAlign: \"left\", padding: \"6px 12px\", borderBottom: \"2px solid #ddd\" };\n+const td: CSSProperties = { padding: \"6px 12px\", borderBottom: \"1px solid #eee\" };\n","firstChangedLine":1}}›Thinking…
Next, package it into a project-v1 JSON and try to verify it with the CLI (this will let us test whether the workflow can be executed without human browser approval).
✓$ cd /tmp/prfm-demo && python3 -c "✓└{"content":[{"text":"wrote project json\nerror: Not logged in.\nhint: Run `prfm login` or set PROFORMA_API_TOKEN.\n","type":"text"}]}ctrl+o
cd /tmp/prfm-demo && python3 -c "
import json
src = open('index.tsx').read()
json.dump({'format':'project-v1','entrypoint':'index.tsx','files':{'index.tsx':src}}, open('synthetic-revenue-summary.project.json','w'), indent=2)
print('wrote project json')" && ./node_modules/.bin/prfm page validate --from ./synthetic-revenue-summary.project.json --json 2>&1 | head -30
›Thinking…
Verification requires authentication. Even for static verification, login is required. In other words, everything is gated behind the device flow approval in the browser (a human action). Let me check whether raw POST /v1/pages/validate works without a token — probably going to get a 401 back.
✓$ cd /tmp/prfm-demo && timeout 20 curl -s -X POST https://app.proformalabs.ai/v1/pages/validate -H 'Content-Type: application/json' -d @<(python3 -c "✓└{"content":[{"text":"{\"error\":{\"code\":\"unauthorized\",\"message\":\"Missing external agent token\",\"requestId\":\"5854894b-add5-4379-8199-590a9967dafc\",\…ctrl+o
cd /tmp/prfm-demo && timeout 20 curl -s -X POST https://app.proformalabs.ai/v1/pages/validate -H 'Content-Type: application/json' -d @<(python3 -c "
import json
print(json.dumps({'project': json.load(open('synthetic-revenue-summary.project.json'))}))") | head -5; echo; echo "--- device flow check (initiate only) ---"; timeout 20 curl -s -X POST https://app.proformalabs.ai/v1/auth/device -H 'Content-Type: application/json' -d '{"requestedScopes":["workspace:read","workspace:write"]}' | python3 -c "import json,sys; d=json.load(sys.stdin); print({k:d.get(k) for k in ['userCode','verificationUrlComplete','expiresInSeconds','pollAfterSeconds','error','message'] if k in d})"
{"content":[{"text":"{\"error\":{\"code\":\"unauthorized\",\"message\":\"Missing external agent token\",\"requestId\":\"5854894b-add5-4379-8199-590a9967dafc\",\"requiredScopes\":[],\"details\":{},\"authorizationUrl\":null}}\n--- device flow check (initiate only) ---\n{'userCode': 'JZKY-8VJT', 'verificationUrlComplete': 'https://app.proformalabs.ai/connect/agent#code=JZKY-8VJT', 'expiresInSeconds': 900, 'pollAfterSeconds': 5}\n","type":"text"}]}›Thinking…
All API surfaces require a browser-approved agent token. Starting the device flow succeeded, and I got the user code JZKY-8VJT and the verification URL. The next step requires a human to sign in/approve in a browser, after which I poll /v1/auth/token. That polling is a bounded wait (expires in 900 seconds) for human action — does this qualify as a "long-running command" I should avoid? The instructions say don't wait for long-running commands. The quickstart essentially requires human browser approval. Following the user's instruction "let me know if you get blocked," I should report: I'm blocked waiting on browser approval. I've already started the device flow and have the code — I'll present the URL to the user. That's actionable: the user can approve, then I complete the build. That's the designed workflow, and the wait is bounded and human-driven.
According to skill.md: "Keep deviceCode private. Show the person only the verificationUrlComplete and the corresponding userCode, then wait while they sign in…" So the intended behavior is to display the URL and wait. But I responded without polling — did I discard the deviceCode? In practice, the deviceCode was included in the response, but I filtered it out. It was included in the raw curl output, but I only printed the selected keys — good, the deviceCode didn't get printed. But it's lost now (it wasn't saved). If the user approves this code, I need the deviceCode to exchange it. I didn't save it. I should restart the flow and save the deviceCode privately to a file.
Let me restart, save the full response to a local file (with permissions set appropriately), and present the URL + userCode to the user. Then stop and tell them I'm blocked waiting on approval. I shouldn't run the polling loop now (waiting on human action = long-running; the user said to let them know if blocked). Actually, a bounded poll would be the natural completion, but the user explicitly said "don't wait on long-running commands" and "let me know if you get blocked." The correct action: start the flow, present the link, and stop, telling them that once they approve I can complete it (or they can re-run). The code expires in 15 minutes.
Let me restart cleanly and save the deviceCode to a file.
All the v1 surfaces require a browser-approved agent token, but the device flow initiates cleanly. Following the documented flow, I'll restart it, privately store the secret device code, and hand off only the safe URL and user code to you.
✓$ cd /tmp/prfm-demo && timeout 20 curl -s -X POST https://app.proformalabs.ai/v1/auth/device -H 'Content-Type: application/json' -d '{"requestedScopes":["workspace:read","workspace:write"],"purpose":"Pu…✓└{"content":[{"text":"userCode: VPTL-Q9B2\nverify: https://app.proformalabs.ai/connect/agent#code=VPTL-Q9B2\nexpiresIn: 900 pollAfter: 5\ndeviceCode stored priva…ctrl+o
cd /tmp/prfm-demo && timeout 20 curl -s -X POST https://app.proformalabs.ai/v1/auth/device -H 'Content-Type: application/json' -d '{"requestedScopes":["workspace:read","workspace:write"],"purpose":"Publish a synthetic revenue-summary demo Page"}' > device.json && chmod 600 device.json && python3 -c "
import json; d=json.load(open('device.json'))
print('userCode:', d['userCode'])
print('verify:', d['verificationUrlComplete'])
print('expiresIn:', d['expiresInSeconds'], 'pollAfter:', d['pollAfterSeconds'])
print('deviceCode stored privately:', 'deviceCode' in d)"
{"content":[{"text":"userCode: VPTL-Q9B2\nverify: https://app.proformalabs.ai/connect/agent#code=VPTL-Q9B2\nexpiresIn: 900 pollAfter: 5\ndeviceCode stored privately: True\n","type":"text"}]}›Thinking…
The example is ready, but it's blocked pending human approval. Let me summarize here:
- What ProForma Labs is, and a simple example I built (files I created).
- Pricing: no public pricing plans exist. Per Article 9 of the Terms of Service, services may be free / usage-limited / invite-only / beta / paid. Paid subscriptions are governed by orders, invoices, or contracts. Fees are non-refundable and exclude tax.
- Is it easy for me to manage? Yes — it's agent-first design: dedicated CLI, device flow, scoped tokens, idempotency keys, ETags, JSON output, exit codes. However, any writes require a one-time human browser approval. Tokens can be pre-provisioned via environment variables.
- Blocker situation: blocked pending browser approval (or a pre-provisioned PROFORMA_API_TOKEN). No local stack or long-running commands needed — the quickstart is hosted. Device flow polling is a bounded loop (expires in 15 minutes) that I deliberately did not start.
- Suggestion: if you approve the code, I'll complete the exchange and publish the Page. Alternatively, you can set PROFORMA_API_TOKEN.
Everything is ready and the build is blocked on exactly one thing: a human browser approval. Here's the full picture.
What I found and built
ProForma Labs (proformalabs.ai) is a hosted "AI research lab" workspace — data, models, files, and interactive React "Pages" — with an explicitly agent-first developer workflow: a public v1 HTTP API (app.proformalabs.ai/v1 with OpenAPI spec), an official CLI (@prfm/cli, binary prfm), and a machine-readable skill doc (/skill.md) written for coding agents.
The example (in /tmp/prfm-demo/), following their documented Page-authoring flow:
index.tsx— a small React Page: a synthetic revenue-vs-target table with a toggle for deltas, clearly labeled as demo data (no connected sources)synthetic-revenue-summary.project.json— the atomicproject-v1package (format,entrypoint,files) that the API expects- The two commands that publish it once authorized:
prfm page validate --from ./synthetic-revenue-summary.project.json prfm fs put "/Synthetic Revenue Summary" --kind page \ --from ./synthetic-revenue-summary.project.json --create \ --idempotency-key synthetic-revenue-summary-v1
How pricing works
There is no public price list — no pricing page or tiers on the site. Per their Terms of Service (§9 "Fees and subscriptions"): services may be free, usage-limited, invite-only, beta, or paid; paid subscriptions/pilots are governed by the applicable order, checkout flow, invoice, or written agreement; fees are non-refundable and exclusive of taxes. So: negotiate/order-based pricing, not self-serve published tiers.
Will this be easy for me to manage?
Yes — it's one of the more agent-friendly products I've seen: purpose-built CLI with JSON output and clean exit codes, scoped tokens (explore/build/operate with exact scopes), ETags + idempotency keys on every write, a live discovery doc and OpenAPI spec, and durable commit receipts. The one structural friction: every credential requires a one-time human browser approval (or a pre-provisioned PROFORMA_API_TOKEN). After that, ongoing management is fully scriptable.
Where I'm blocked (and stopping, as instructed)
Even static validation requires an agent token, and the only way to get one is the device-authorization flow — a person must approve in a browser. I've initiated it (the secret device code is stored privately in /tmp/prfm-demo/device.json; I deliberately did not start the polling wait):
- Open: https://app.proformalabs.ai/connect/agent#code=VPTL-Q9B2
- Code:
VPTL-Q9B2(expires in ~15 minutes)
No local service stack was needed and nothing long-running was started — the quickstart is fully hosted. To unblock, either approve that link (then tell me and I'll exchange the token, validate, publish the Page, and return the commit receipt + app URL), or set PROFORMA_API_URL + PROFORMA_API_TOKEN for a pre-provisioned environment. If the code expires, I can re-initiate in one command.
AX Fundamentals
23 checks. Open an area for details.
This check is a quick preview. Test more tasks and models with Gauge Agents.
Test your product with Gauge Agents