Skip to content

fix(web): point agents at Cap Infra in llms files and serve docs as Markdown - #4170

Merged
richiemcilroy merged 20 commits into
mainfrom
fix/infra-agent-discovery
Nov 13, 2026
Merged

richiemcilroy merged 20 commits into
mainfrom
fix/infra-agent-discovery

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

An agent given a Cap Infra key had trouble finding its way in. llms.txt and llms-full.txt never named Cap Infra, and their "start here" link sent the agent to the screen recorder CLI. The docs disagreed on how often to poll. Docs pages ignored Accept: text/markdown and returned 600 to 700 KB of HTML with code blocks broken into one token per line.

What changes

llms files. Both files now have a "Cap Infra (video and speech API)" section near the top. It covers what the product is, Get Started, the REST reference, openapi.json, billing, the console, auth, rate limits and poll intervals:

  • Auth: the secret csk_ key goes in the Bearer header from the server only. A browser uploads with the short-lived cut_ token from POST /api/developer/v1/uploads.
  • Rate limits: 300 requests a minute per secret key, 1,200 for all the keys of one account together, 1,200 per upload token, and 30 rejected credentials a minute per address. These are the limits that ship with fix(web): Infra request limits per account and address, retire empty uploads, wait out a busy farm #4160. llms.txt used to say 60 for both keys and upload tokens.

The agent section now names both products and says which link is for which: /infra for building with an API key, /agents for the recorder. The stale media stack lines in llms-full.txt are replaced with what runs today: S3 and CloudFront, plus Cap's own media server and GPU fleet for transcoding and HLS. No code on main imports the MediaConvert or Mux SDKs. The only MediaConvert left is a source-type label for the file layout of older recordings.

One poll interval. Poll video status every 3 seconds and transcripts every 5 seconds. A short video is playable about 3 seconds after its upload completes, and a short transcript takes about 5 seconds, so one check usually finds it done. Both numbers are constants next to the rate limits. The OpenAPI descriptions (info, status, createTranscript, getTranscript) and the console agent prompt read the constants. The API docs, the /infra FAQ and the llms files give the same numbers.

Docs as Markdown. A docs URL ending in .md (or .mdx), or a docs request with Accept: text/markdown, is rewritten by the proxy to /docs-markdown/<slug>. That route returns the page source with Content-Type: text/markdown; charset=utf-8 and Vary: Accept:

  • The frontmatter becomes a title and summary.
  • <CopyablePrompt /> becomes the prompt text in a fenced block.
  • <Warning> becomes a blockquote and <CapEmbed> becomes a link.
  • Site-relative links become absolute.
  • Code blocks pass through exactly as written.

A missing page gets the existing Markdown 404. Browsers still get HTML. Each docs page also adds <link rel="alternate" type="text/markdown">. get-started comes out at about 34 KB. The Cap Infra section of both llms files also points at the hosted MCP server, https://cap.so/api/developer/mcp, and the Get Started section #4174 adds for it. That endpoint stays gated with the rest of Infra until launch.

Docs accuracy and the /infra page.

  • The docs introduction now points at Cap Infra and its webhooks. With the merge of main, the llms files also say webhooks (video.ready, video.errored) can replace video status polling, and that transcripts are still polled.
  • The Get Started player no longer sets an hls.js start level, and now agrees with the reference. The served master playlist already leads with a rendition that starts quickly (leadWithStartRendition in lib/developer-video-playback.ts).
  • The REST reference now says what the hosted player records: no cookies, and one anonymous view with the page's address each time it loads (the site-wide OpenPanel screen view). The embed snippets are left as main has them; fix(infra): quieter embed code and a viewer-facing waiting message #4189 changes them.
  • On /infra, "Docs" and "Read the docs" now open Get Started, and "API reference" and the FAQ's reference link stay on the REST reference. Only hrefs change there.

Transcript polling and word timings.

  • The reference and Get Started now say to wait on several transcripts with one List Transcripts call per status (?status=processing&limit=100, plus status=queued), not one Get per transcript. An app has at most 20 transcripts in flight. Getting each of 20 every 5 seconds takes 240 requests a minute, and the two list calls take 24. List Videos has no status filter, so there is no such advice for videos.
  • The reference and the OpenAPI words description no longer say timings come in steps of 0.08 seconds. That is not true for a file long enough to be transcribed in chunks.

Proof on a real deployment

Run with vercel curl against the preview for 4b98682, from one client, in this order. The browser Accept is text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8.

[1] GET /docs/api/billing  Accept: text/markdown
    200, 9,699 bytes, body "# Billing"
    content-type: text/markdown; charset=utf-8
    vary: Accept
    cache-control: public, max-age=300
    age: 0, x-vercel-cache: MISS
    x-matched-path: /docs-markdown/[...slug]
[2] GET /docs/api/billing  Accept: browser
    200, 102,354 bytes, body "<!DOCTYPE html>..."
    content-type: text/html; charset=utf-8
    vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch
    cache-control: private, no-cache, no-store, max-age=0, must-revalidate
    age: 0, x-vercel-cache: MISS
    x-matched-path: /docs/[[...slug]]
[3] GET /docs/api/billing  Accept: text/markdown
    200, 9,699 bytes, body "# Billing"
    content-type: text/markdown; charset=utf-8
    vary: Accept
    cache-control: public, max-age=300
    age: 4, x-vercel-cache: HIT
    x-matched-path: /docs-markdown/[...slug]
[4] GET /docs/api/billing  Accept: browser
    200, 102,354 bytes, HTML, x-vercel-cache: MISS
[5] GET /s/15hm7kjtn8jmyr3  Accept: text/markdown
    404, 19,480 bytes, content-type: text/html
    x-matched-path: /s/[videoId]
[6] GET /s/15hm7kjtn8jmyr3  Accept: browser
    404, 19,480 bytes, content-type: text/html
    x-matched-path: /s/[videoId]
  • The proxy runs before the edge cache. Request 3 is served from cache, but request 2 between it and request 1 still got HTML. The Markdown is cached under its own route (/docs-markdown/[...slug]), so it cannot be served for an HTML request.
  • The HTML docs page is private, no-store and is never stored at the edge (MISS every time). So it needs no Vary: Accept, and nothing changes there.
  • A share page with Accept: text/markdown still goes to the normal /s/[videoId] route and gets HTML. That share id is not in the preview's database, so both Accept values get the same 404 page. On production (main) the same id returns the 200 HTML page (77,831 bytes) for both Accept values. The docs rewrite only matches /docs and /docs/... paths.

Tests

  • New docs-markdown.test.ts: it checks slug parsing and runs every docs page through the converter. No component tags and no relative links may be left outside code. Every code block in get-started has to come out byte for byte. It also covers the route's headers, the 404, a path traversal attempt, and the proxy rewrite for both triggers while a browser still gets HTML.
  • The prompt test now checks for the new intervals. The billing docs test also counts h4 headings as link targets, since List Transcripts is one. proxy-infra-path.test.ts mocks the two new exports.
  • The related suites pass (206 tests). tsc --noEmit for apps/web is clean except for one error that is already on main (organization-settings-ownership.test.ts).

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no new actionable issue was established.

Summary

This PR makes Cap Infra easier for agents to find and adds Markdown versions of docs pages.

  • Docs readers can request a page as Markdown.
  • Agents now get separate starting points for Cap Infra and the screen recorder.
  • API callers get consistent video and transcript polling advice.
  • The HLS player example starts with the playlist's first rendition.
  • The API reference explains what the hosted player records.

The supplied previous threads are unnumbered, so they receive no entries in previousFindings. Their reported issues are addressed or acknowledged.

Reviews (12) · Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." · Reviewed by Greptile

@vercel

vercel Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
cap-status Skipped Skipped Nov 13, 2026 8:59am UTC

@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 05:38 Inactive

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 3 other findings in Capy.

Open in Capy

@sandchest-com

sandchest-com Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Sandchest

Sandchest reviewed b1ba110: nothing exploitable found in this change.

Sandchest reviews every change for vulnerabilities an attacker could use · Review details

Comment thread apps/web/public/llms-full.txt Resolved
@richiemcilroy
richiemcilroy force-pushed the fix/infra-agent-discovery branch from 78c49f0 to 8e27462 Compare November 13, 2026 05:49
@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 05:49 Inactive

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 2 other findings in Capy.

Open in Capy

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found 1 potential issue (1 medium).

Open in Capy

Comment thread apps/web/public/llms.txt Resolved

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found 1 potential issue (1 medium).

View 2 other findings in Capy.

Open in Capy

Comment thread apps/web/content/docs/api/rest-api.mdx Resolved
Comment thread apps/web/public/llms.txt Resolved
Comment thread apps/web/content/docs/api/rest-api.mdx Resolved
@richiemcilroy
richiemcilroy force-pushed the fix/infra-agent-discovery branch from 1a691c2 to 495c9c2 Compare November 13, 2026 06:09
@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 06:09 Inactive
@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

A docs URL ending in .md, or requested with Accept: text/markdown, is
rewritten to a route that returns the page source as Markdown, with its
components replaced by plain text and links made absolute. Docs pages
also advertise the Markdown version with a link alternate.
The introduction no longer promises webhooks, which do not exist yet. The
Get Started player no longer picks a start level: the master playlist
already leads with a rendition that starts quickly, as the reference says.
Every Infra embed snippet, including the console's, now uses
allow="fullscreen; picture-in-picture; autoplay; encrypted-media". The
/infra page's Docs and Read the docs links open Get Started, and API
reference stays on the reference.
300 requests a minute per secret key, 1,200 for all the keys of one account,
1,200 per upload token and 30 rejected credentials a minute per address.
…mments

The /api routes follow the HttpApi pattern, and this one only returns a
file as text, so it moves to /docs-markdown behind the same proxy rewrite.
A 409 video_not_ready succeeds once the video finishes processing, so it
joins 429 and completion_in_progress, and agents are told to follow each
error's hint.
An app has at most 20 transcripts in flight. Getting each one every 5
seconds takes 240 requests a minute, and listing by status takes 24.
Words in a file long enough to be transcribed in chunks are offset off that
grid, so the reference and the OpenAPI words description no longer claim it.
@richiemcilroy
richiemcilroy force-pushed the fix/infra-agent-discovery branch from f71e047 to 86f4b52 Compare November 13, 2026 07:13
@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 07:13 Inactive
@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

…very

# Conflicts:
#	apps/web/content/docs/api/get-started.mdx
#	apps/web/content/docs/api/rest-api.mdx
#	apps/web/content/docs/api/webhooks.mdx
#	apps/web/data/infra-agent-prompt.ts
@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

Open in Capy

@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 08:59 Inactive

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

Open in Capy

@richiemcilroy
richiemcilroy merged commit e105a83 into main Nov 13, 2026
39 checks passed

This branch was successfully deployed

1 active and 1 inactive deployments
Preview – cap-web — b1ba1100 Deployed Nov 13, 2026 by vercel[bot]
Preview – cap-status — b1ba1100 Deployed Nov 13, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant