InsForge Documentation Audit
The docs are agent-aware (llms.txt, skill.md, MCP-first onboarding) and broad in surface area, but key architecture pages contradict themselves on cryptography, file size limits, and supported providers; two separate "deployment" primitives co-exist without reconciliation; OpenAPI specs are split across two hosts; and Payments/Email exist only in TypeScript despite the multi-language SDK story.
1. Authentication architecture contradicts itself on JWT signing (critical)
Location: /core-concepts/authentication/architecture
Problem: The overview prose says InsForge uses "JWT tokens with RSA signing." The Core Components table immediately below declares Token Format: JWT with HS256, Signing Algorithm: HMAC-SHA256, described as "Symmetric key signing with shared secret." The llms-full.txt summary also says "HS256 signing." RSA (asymmetric) and HS256 (symmetric, shared-secret) are fundamentally different threat models.
Consequence: A developer or agent integrating token verification will pick the wrong algorithm and either (a) attempt to verify with a public key that doesn't exist, or (b) ship a service that trusts a shared secret it shouldn't have. Security-sensitive readers cannot tell which claim is authoritative. Agents will silently choose one and produce broken verification code.
The fix: Pick one. Remove "RSA signing" from the overview if HS256 is correct (most likely, given bcryptjs + symmetric secret), and update the prose to match the table. If RSA is correct, fix the table and document the key distribution model.
2. Storage default upload size given two different values on the same page (critical)
Location: /core-concepts/storage/architecture
Problem: The "Size Limits" card says "50MB default, configurable via MAX_FILE_SIZE." The "Upload Methods → Direct Upload" subsection on the same page says direct upload is "Limited by server memory (10MB default)." Worse, the Configuration → Environment Variables table lists only AWS_S3_BUCKET, AWS_REGION, and APP_KEY — MAX_FILE_SIZE is referenced in the card but never defined in the env var table.
Consequence: A developer building an upload UI doesn't know whether to validate at 10 MB or 50 MB; an agent will pick whichever it sees first and ship a broken upload page or an oversized request that the server rejects. Anyone trying to raise the limit can't find the env var because it's not in the configuration table.
The fix: State a single default (and make clear whether direct-upload and the overall ceiling differ), then add MAX_FILE_SIZE to the environment variables table with type, units, and the actual default.
3. Two parallel "deployment" primitives, no cross-reference (critical)
Location: /core-concepts/compute/architecture and /core-concepts/deployments/architecture
Problem: "Compute" is described as a Fly.io-backed feature for running Docker containers with a public URL ("Compute is the InsForge feature for that"). "Deployments" is a separate Core Concept built on Vercel for "single-prompt" web app deployments. Both pages live under Core Concepts, both use the word "deployment," and neither page links to the other or explains when to choose which.
Consequence: A developer (or coding agent) that asks "deploy my app" gets routed via MCP to Vercel-backed Deployments; one that asks for "containerized backend" gets Fly-backed Compute. There's no decision tree, no comparison, and no way to know that asking the wrong question puts you on the wrong primitive — possibly with different pricing, different limits, and a different lifecycle.
The fix: Add a "When to use Compute vs. Deployments" matrix to both pages (and to the Core Concepts index). Document which feature each MCP tool maps to, the billing model for each, and link from each page to the other.
4. Hostname schema is fragmented across multiple URL patterns with no canonical reference (significant)
Location: /core-concepts/functions/architecture, /core-concepts/storage/s3-compatibility, /sdks/rest/overview, /partnership
Problem: The platform exposes at least five URL families across the scraped pages:
- REST:
your-app.insforge.app - Functions direct:
{appKey}.functions.insforge.app/{slug} - Functions fallback:
{appKey}.{region}.insforge.app/functions/{slug} - Storage S3:
{project-ref}.{region}.insforge.app/storage/v1/s3 - Partnership API:
api.insforge.dev(different host and auth scheme entirely)
Variable names also drift: appKey, project-ref. No single page documents the canonical hostname schema or how these subdomains relate to each other.
Consequence: Agents and developers configuring CORS, allowlists, CSP headers, webhooks, or DNS cannot enumerate the full set of origins. SDK consumers don't know whether appKey and project-ref are the same value. A misconfigured allowlist silently breaks one surface (e.g., functions fallback) while the others work.
The fix: Add a "Hostnames & URL Schema" reference page that lists every subdomain pattern, the variable that fills it, and which feature uses which. Standardize on one casing/term (appKey vs project-ref).
5. OAuth provider list disagrees with itself across three places (significant)
Location: /core-concepts/authentication/architecture and /changelog
Problem: On the Authentication Architecture page, the mermaid diagram lists only Google and GitHub as OAuth providers. The Core Components table on the same page says "Google, GitHub, Microsoft, Discord, and more." The changelog separately announces Apple, LinkedIn, Microsoft, Facebook, and Discord. The llms-full.txt summary lists "Google, GitHub, Microsoft, Discord, LinkedIn, Facebook, Apple."
Consequence: A developer choosing a stack based on "does it support Apple/LinkedIn login" can't tell from the architecture page that those providers exist. An agent searching for OAuth setup instructions will find conflicting lists and may tell a user that Apple is unsupported.
The fix: Make the architecture page the single source of truth for the provider list. Either enumerate every supported provider in the table and the diagram, or link to a dedicated /auth/providers page that's authoritative. Remove "and more" — agents can't act on it.
6. UUID schema vs. usr_abc123 example contradiction across SDK and OpenAPI (significant)
Location: /sdks/typescript/auth and /api-reference/client/register-new-user
Problem: The TypeScript SDK auth reference shows sample output "id": "usr_abc123". The OpenAPI schema rendered at /api-reference/client/register-new-user declares the same field as format: uuid. These are mutually exclusive — usr_abc123 is a Stripe-style prefixed ID, not a UUID.
Consequence: Developers using the documented id field for FK references, RLS policies, or client-side parsing will write code against the wrong shape. Type-generated TS clients will declare id: string (uuid) while runtime returns usr_abc123 (or vice versa), surfacing as parse failures or RLS lookup mismatches.
The fix: Pick the actual production format. Update either the SDK example or the OpenAPI schema so they agree, and grep the rest of the docs (the usr_abc123 shape appears in further auth examples elsewhere on the site) to fix them all in one pass.
7. AI model table and /api/ai/models endpoint are not reconciled; no version-stability annotation (significant)
Location: /core-concepts/ai/architecture and /changelog
Problem: The supported-models table lists specific identifiers (openai/gpt-5.2, google/gemini-3-flash-preview, deepseek/deepseek-v3.2) but immediately notes "Model availability may vary. Use the GET /api/ai/models endpoint…" — meaning the table is potentially stale. The changelog announces "Gemini 3 Flash" and "DeepSeek V3" while the table shows gemini-3-flash-preview (preview) and deepseek-v3.2. Nothing tells a reader which identifiers are stable, which are preview, or which can disappear.
Consequence: Agents and developers hardcode a model identifier from the docs, ship code, and break in production when the preview model is renamed or pulled. There's no contract about deprecation windows or version pinning.
The fix: Add stability tags (GA / preview / experimental) to each row. Document the deprecation policy. Either keep the table fresh or remove it and direct readers to the live endpoint as the only source.
8. Realtime defaults are open to anonymous publish, framed as a feature (significant)
Location: /core-concepts/realtime/architecture and /sdks/typescript/realtime
Problem: The default permission table says anonymous users can both subscribe and publish to any channel out of the box, with a Note framing this as "best developer experience." The TypeScript Realtime SDK's publish() reference says "You must be subscribed to a channel before publishing to it" — implying an authorization check that, per the architecture page, doesn't actually exist by default.
Consequence: A developer reading the SDK reference believes there is a subscription-gating check; in reality, with default RLS-disabled config, anyone on the internet can publish to any channel. Apps go to production with open WebSocket pub/sub. Worse, the "must be subscribed" sentence reads like a security guarantee — it isn't, it's a client-side ordering rule.
The fix: Add a prominent Warning on both pages: "Default config allows anonymous publish — enable RLS before going to production." Rewrite the publish() note to clarify that "must be subscribed first" is a client-side requirement, not an authorization check.
9. Payments and Email exist only in TypeScript; not flagged on architecture pages (significant)
Location: /core-concepts/email/architecture, /core-concepts/payments/architecture, /sdks/rest/overview, llms.txt
Problem: The llms.txt index has no /sdks/swift/payments, /sdks/kotlin/payments, /sdks/swift/email, /sdks/kotlin/email, /sdks/rest/email, or /sdks/rest/payments. The Email architecture page surfaces this only at the bottom in a truncated note ("Email SDK is currently only available for TypeScript as p…"). The Payments architecture page does not surface it at all. The REST overview page lists Payments and Email nowhere.
Consequence: A Swift or Kotlin developer adopts InsForge expecting parity with the published SDK story, builds a feature, and discovers mid-implementation that there is no Email or Payments SDK and no documented REST recipe. An agent picking Kotlin will hallucinate an SDK that doesn't exist.
The fix: Add an SDK availability matrix to each architecture page (Email, Payments, Realtime, Storage, Auth, AI) with TS / Swift / Kotlin / REST columns, marking gaps explicitly. If REST coverage exists, link to it; if not, say "TypeScript only."
10. Email SDK page shows broken Mintlify code-fence metadata (significant)
Location: /sdks/typescript/email
Problem: Code-fence info strings include the literal text theme={null} repeated four times: bash npm theme={null} theme={null} theme={null} theme={null} ```. This is rendered raw to readers (visible in the scraped output), not stripped at build.
Consequence: Copy-pasting the snippet — exactly what an AI agent will do — picks up the malformed fence. The first impression of the only Email reference page is a broken build artifact, undermining confidence in the rest of the docs.
The fix: Fix the source MDX and add a CI check that lints code-fence info strings. The same theme={null} artifact likely exists elsewhere; grep the repo.
11. OAuth Server "Register Your Application" has no contact channel and conflates two audiences (significant)
Location: /oauth-server
Problem: The first step of using the OAuth Server is "Contact InsForge to register your application as an OAuth client." No email, no portal URL, no link, no Discord, no form. The page also conflates two audiences: the title and overview say "authenticate users in third-party applications" against "your InsForge project," but the documented scopes (user:read, organizations:read, projects:read, projects:write) describe OAuth against the InsForge platform, not against an end-developer's project.
Consequence: A developer who reads the doc and wants to ship has no way to start. The audience confusion means they may also be reading the wrong page entirely (e.g., expecting end-user OAuth and getting platform-management OAuth).
The fix: Add an explicit registration link or email (the partnership page uses partnerships@insforge.dev — pick something equivalent). Disambiguate "OAuth Server for end-user auth in your app" vs "OAuth client against the InsForge platform" — they're different products and need different pages.
12. Partnership API is on a different host with a different auth scheme, never indexed (significant)
Location: /partnership and llms.txt
Problem: Partnership API uses https://api.insforge.dev/partnership/v1/... and X-Partnership-Secret header. Every other documented API surface uses your-app.insforge.app with Authorization: Bearer ... (per /sdks/rest/overview). The Partnership API endpoints are never enumerated in the llms.txt index — there is no OpenAPI spec for it.
Consequence: An agent indexing the docs cannot discover Partnership endpoints at all. A partner integrator cannot tell which endpoints exist or what they accept; they're stuck emailing for docs.
The fix: Publish a Partnership OpenAPI spec, link it from llms.txt, and explain on the page why the host and auth header differ from the rest of the platform (or unify them).
13. Database page mentions "two PostgreSQL databases" but only describes one; auth schema access not explained (significant)
Location: /core-concepts/database/architecture
Problem: The page states "InsForge uses two PostgreSQL databases:" and then describes only the Main Database (insforge). The second database is never named, scoped, or described. Separately, the page says "tables in the public schema are exposed via PostgREST" but never explains how a developer should reach the users row that lives in the auth schema — from('users') is the obvious guess and silently does the wrong thing or fails.
Consequence: A developer trying to model their data, set up backups, or reason about row-level security has half the picture. Anyone wiring up FKs to auth.users or referencing user records from RLS policies has to learn the access pattern by trial and error.
The fix: Either document the second database (name, role, schemas, access) or remove the "two databases" claim. Add an explicit table mapping schemas → DB → exposure mechanism (PostgREST vs. internal API) and show the canonical pattern for joining/referencing auth.users from public.
14. OpenAPI specs split across two hosts, with the newer features stranded on raw GitHub (significant)
Location: /llms.txt
Problem: The OpenAPI spec list in llms.txt mixes hosts: 11 specs are served from docs.insforge.dev/api-reference/*.yaml, but payments, email, and realtime point at raw.githubusercontent.com/InsForge/InsForge/main/openapi/*.yaml. These three are exactly the newer / private-preview surfaces, the ones an agent is most likely to need fresh schemas for.
Consequence: An agent that fetches OpenAPI specs uniformly will hit different hosts with different latency, caching, and CORS behaviors. raw.githubusercontent.com URLs track the main branch, not a tagged release, so the spec can change underneath consumers between requests. Developers loading specs into Postman/Stoplight/Scalar will get a different experience for half the platform.
The fix: Re-host all OpenAPI specs under docs.insforge.dev/api-reference/, version them, and update llms.txt. If GitHub-hosting is intentional for newer surfaces, document why and pin to a tag rather than main.
15. llms-full.txt is a marketing summary, not a full corpus, and Database section is cut off (significant)
Location: /llms-full.txt
Problem: The llms-full.txt file is a brief platform summary (endpoint counts, feature bullets, recent updates) — not the full Markdown corpus that peers like Mintlify and Stripe ship at this filename. Within the summary, the Database Architecture section is cut off mid-description with an explicit (document truncated) marker: "…migrations, and metadata management (document truncated)." For a platform whose headline differentiator is agent-first machine ingestibility, the filename promises a full dump and delivers a synopsis.
Consequence: Agents fetching llms-full.txt expecting the full docs corpus get a summary instead, then have to traverse the llms.txt page list one URL at a time — slower and more brittle. The visible (document truncated) marker is also a build artifact escaping into published output.
The fix: Generate llms-full.txt from the full Markdown bodies of every page in llms.txt (Mintlify supports this natively). Remove the (document truncated) marker or surface what's missing. Keep the current summary as a separate file (e.g., llms-summary.txt) if it's useful.
16. Realtime presence appears in SDK output but is never documented as a subsystem (minor)
Location: /core-concepts/realtime/architecture and /sdks/typescript/realtime
Problem: The TypeScript Realtime SDK's subscribe() reference shows Output (Success) containing presence data — implying a presence subsystem exists. The Realtime architecture page describes channels, messages, and RLS, but says nothing about presence (no schema, no permission model, no API).
Consequence: A developer who sees presence in the SDK output goes looking for "how do I track who's online" and finds nothing. An agent will guess — invent a presence.track() call, an RLS policy on a non-existent table — and the developer will burn time before realizing the feature isn't documented (or doesn't exist as advertised).
The fix: Either add a Presence section to the Realtime architecture page (data model, permissions, API surface) or remove presence from the SDK output example until it's a real, documented feature.
17. Functions hard 10MB payload limit conflicts with storage limits without cross-reference (minor)
Location: /core-concepts/functions/architecture and /core-concepts/storage/architecture
Problem: The Functions execution-limits table sets payload size at 10MB for both Cloud and Self-Hosted. Storage's "Size Limits" card says 50MB default. Developers commonly use Functions to broker uploads (resize, virus-scan, transcode), and the docs never note that a 50MB upload cannot pass through a Function — it has to go direct to storage.
Consequence: Agents and developers wire an upload through a Function for "free" preprocessing, then hit a 413 at 10MB and have no signal in either page that the limits don't compose.
The fix: Add a cross-reference Note on both pages: "If you broker uploads through Edge Functions, the 10MB function payload limit applies — uploads larger than that must go direct to Storage." Or unify the limits.
18. VS Code extension supports 9 clients, MCP setup page lists 13+, with no acknowledgment (minor)
Location: /vscode-extension and /mcp-setup
Problem: The VS Code extension's supported-clients table covers 9 clients (cursor, claude-code, copilot, windsurf, cline, roocode, codex, trae, qoder). MCP Setup's Local Configuration accordion lists 13+ including Antigravity, Kiro, OpenCode, plus a generic "MCP JSON" option. The Remote MCP note enumerates yet another shorter list. No page flags the gap.
Consequence: A user on Kiro tries the VS Code extension and it doesn't list their client; they don't know whether the omission is intentional (not yet supported) or a docs miss.
The fix: Maintain a single canonical client matrix and reference it from both pages. State explicitly which clients are supported via VS Code extension vs. CLI install vs. remote MCP.
19. VS Code login callback URL is a malformed link (minor)
Location: /vscode-extension
Problem: The login-callback note wraps the URL in a malformed <code>[http://127.0.0.1:54321/callback](http://127.0.0.1:54321/callback)</code> — Markdown link syntax inside a <code> tag — so the page renders the raw […](…) rather than a clickable URL. (The choice of port 54321 is also a commonly used local dev port, and a collision with another dev stack on the same machine will surface as a confusing callback failure.)
Consequence: Anyone landing on this page sees a visibly broken link in their first auth instruction, which dents trust in the rest of the page.
The fix: Replace with either a plain <code>http://127.0.0.1:54321/callback</code> or [http://127.0.0.1:54321/callback](http://127.0.0.1:54321/callback) — not both. Optionally note the chosen port and how to handle collisions if the extension supports overrides.
20. Deployment & Security guide links a relative ./README.md that isn't published; placeholder version (minor)
Location: /deployment/deployment-security-guide
Problem: A Scope callout says "see the deployment directory" — that's a relative link to a README that doesn't appear in the published docs site (no /deployment/README in llms.txt). Cloud-specific guides for AWS EC2, GCP, Azure, Render are referenced as existing but not listed in the index. The health-check sample response shows version 1.x.x rather than a real version.
Consequence: The link 404s for any reader who clicks it. Self-hosters who want AWS/GCP/Azure/Render specifics can't find them. The placeholder version suggests a doc was never finished.
The fix: Either publish the cloud-specific guides and link them with absolute URLs, or remove the references. Replace 1.x.x with the actual current version (or a documented format like <MAJOR>.<MINOR>.<PATCH>).
21. Self-hosted S3 gateway promised but no setup guide exists (minor)
Location: /core-concepts/storage/s3-compatibility
Problem: The page's "Cloud only" callout tells self-hosters they can recreate the S3-compatible gateway "by running the platform against a MinIO or AWS S3 bucket" — but no MinIO/self-hosted S3 setup guide appears in the docs index, and the deployment guide makes no mention of it.
Consequence: Self-hosters reading the storage docs see an opt-out promise ("you can do this yourself") without instructions, then have to reverse-engineer the gateway or open a support ticket.
The fix: Add a "Self-host the S3 gateway" guide under /deployment with the env vars, MinIO config, and verification steps. Or, remove the "Cloud only" exception and clearly state the gateway is Cloud-only.
22. Quickstart never tells you to install MCP (minor)
Location: /quickstart
Problem: Step 3 of the Quickstart tells the user to verify the agent setup, but the actual MCP install lives at /mcp-setup; Quickstart only references link --project-id. There's no inline pointer that a developer arriving at "Quickstart" from a search engine needs to leave the page first to install MCP.
Consequence: A developer following the Quickstart end-to-end will hit the verify step without having run the install, get a confusing failure, and either bounce or hunt through the sidebar.
The fix: Add an explicit "Install MCP" step before "Verify" in the Quickstart, linking to /mcp-setup. Or inline the one-line remote MCP install command.
23. TypeScript SDK overview duplicates the same snippet in Installation and Quick Start (minor)
Location: /sdks/typescript/overview
Problem: The same createClient snippet appears under "Installation" and again under "Quick Start" with no additional context — Quick Start is effectively a copy of Installation. The Features list and CardGroup also omit the Email SDK entirely, even though /sdks/typescript/email exists and is referenced from /core-concepts/email/architecture.
Consequence: Readers (and agents) waste a scroll on a duplicate, and an agent that uses the overview to enumerate available features will silently miss Email.
The fix: Make Quick Start an actual end-to-end first-call example (sign in, query a table, return a row). Add Email to the Features list and CardGroup.
24. Changelog duplicates rollouts across adjacent dates with inconsistent formatting (minor)
Location: /changelog
Problem: The Dec 21 entry announces Realtime, Apple OAuth, Alipay, and new AI models. The Dec 12 entry separately announces Alipay and the new AI models. The Dec 11 entry announces Apple Login. "GPT 5.2" appears with two formattings (GPT 5.2 and GPT-5.2) on the same page.
Consequence: Readers can't tell which date is the actual GA date for Apple OAuth or Alipay. Search queries for "GPT-5.2" miss the unhyphenated occurrence. The page reads like overlapping product announcements rather than a versioned changelog.
The fix: Pick one rollout date per feature, link the announcement post separately if you want marketing copy. Standardize model name formatting across the page.
What they do well
- Agent-first framing is real, not just branding — there's a
skill.md, an MCP-first onboarding, an llms.txt index, and adata-for-agentsinvisible div on the introduction page that points agents at canonical setup. Few BaaS docs go this far. - OpenAPI specs exist for most surfaces (auth, tables, storage, ai, functions, records, metadata, profiles, secrets, logs, health) — agents have something to consume, even if hosting is split (#14).
- S3 compatibility page is unusually honest about footguns — explicitly calls out that access keys are project-admin scoped and bypass public/private flags, that the secret is shown once, and that there's a 50-key cap.
Top 3 recommendations
- Fix the JWT signing contradiction (#1) — this is a security-relevant, two-sentence fix that currently makes the auth architecture page unsafe to follow.
- Reconcile Compute vs. Deployments (#3) — pick a decision matrix, cross-reference both pages, and clarify which feature each MCP tool maps to so agent-driven "deploy my app" is deterministic.
- Make agent-readiness real (#14, #15) — re-host all OpenAPI specs on one host, and replace the
llms-full.txtsummary with the actual concatenated corpus. Agent-first is the platform's pitch; these are the two files agents fetch first.