Development Context
LLM-oriented project map, workflows, contracts, and change rules.
This page is written for humans and LLM agents working on Intertool. It is included in /llms-full.txt, so keep it current when architecture, routes, workflows, or developer commands change.
Product shape
Intertool is a private registry for AI agent skills, MCP servers, agent tools, and prompt templates. Teams publish items through the web UI, CLI, or API, then discover and install them into local AI tooling.
Core promises:
- User data is stored in managed object storage: Vercel Blob for hosted SaaS, or S3-compatible storage for self-hosted/custom deployments.
- The app can run self-hosted as a single tenant or in SaaS mode with path-based organizations.
- Access is controlled by NextAuth, OAuth providers, API tokens, and RBAC.
- Documentation is served through Fumadocs and exposed to LLMs at
/llms.txtand/llms-full.txt. - Public SEO/AEO discovery is intentionally limited to the homepage, pricing page, brand page, documentation,
robots.txt,sitemap.xml, and LLM documentation endpoints. Private registry, settings, auth, and API routes should remain blocked from indexing.
Architecture map
app/contains Next.js App Router pages and route handlers.app/(main)/contains the main registry UI: home, browse, dashboard, publish, review, settings, teams, skill detail, edit, versions, and diff pages.app/(auth)/contains sign-in, invitation, and org creation pages.app/api/contains JSON and file endpoints for auth, org creation/deletion, settings, members, invitations, tokens, import, publish, search, analytics, audit logs, Stripe billing, private distribution manifests, and skill files.components/contains shared React UI, including the publish wizard, command palette, skill cards, markdown rendering, filters, preferences, and shadcn-style primitives undercomponents/ui/.lib/contains the app contracts and backend logic: auth, API auth, RBAC, org routing, settings, Postgres control plane, object storage access, registry reads/writes, validation, rate limits, analytics, audit logs, plan limits, Stripe billing, distribution exports, security scanning, webhooks, and email.cli/contains the separateintertoolnpm CLI implemented with Commander.content/docs/contains MDX docs. Update these when CLI, API, auth, publishing, install behavior, or other user-facing behavior changes.registry/contains local category seed data and local development registry state.lib/seo.ts,app/robots.ts,app/sitemap.ts,app/opengraph-image.tsx,/llms.txt, and/llms-full.txtdefine the public discovery surface for search engines, social previews, and LLM/agent consumption.
Data flow
Web reads usually follow this path:
Page or API route -> lib/auth or lib/api-auth -> lib/registry -> lib/settings -> lib/s3Publishing flows follow this path:
PublishWizard or CLI -> /api/publish -> authenticateApi -> validateSkillInput -> replaceSkillFiles -> upsertSkill -> S3 objects and indexWhen publish_review_required is enabled, new non-admin submissions are written with status: review. Browse, search, CLI install, and list APIs only expose published items. Owners and admins approve or archive pending submissions from /review, which calls PATCH /api/skills/:slug.
Publishing also enforces SaaS plan limits from lib/plans.ts and runs scanRegistryItem from lib/security-scan.ts. Critical scan findings reject the publish before files are written to storage.
CLI flows usually follow this path:
intertool command -> cli/src/lib/config.ts -> cli/src/lib/api.ts -> app/api route -> local install filesSaaS routing follows this path:
/{org}/route -> proxy.ts strips org prefix -> x-org-slug header -> lib/org.ts -> settings/RBAC lookupPublic route aliases for deployment or landing experiments, currently /landing-exp, are stripped before routing and must not set the intertool.org cookie. Keep lib/public-route-aliases.ts, proxy.ts, and lib/org-slugs.ts aligned when adding another alias.
Auth redirect normalization lives in lib/auth-redirects.ts. The sign-in page sanitizes callbackUrl, unwraps nested sign-in callbacks, and redirects authenticated SaaS users to their current or primary org path so root callbacks like /dashboard become /{org}/dashboard. If a callback contains a stale org prefix, such as /default/dashboard, the redirect helper replaces it with the user's resolved org.
For authenticated root private routes such as /dashboard, proxy.ts sets x-org-slug from the user's resolved org and lets the request continue instead of issuing another browser redirect. This avoids root/org redirect loops when a browser has stale org cookies.
proxy.ts must pass the same Auth.js session cookie name configured in lib/auth.ts when calling getToken; production uses __Secure-authjs.session-token.
Proxy responses that redirect for auth, set intertool.org, or clear intertool.org must use no-store cache headers. default is an internal fallback namespace and is reserved in both proxy.ts and lib/org-slugs.ts so it cannot become an org cookie value.
Org resolution helpers must also treat reserved slugs as unusable even if they exist in old cookies or legacy control-plane rows. Auth callback normalization strips repeated stale /default prefixes so paths such as /default/default/dashboard resolve to /dashboard before org-aware redirect logic runs.
Logout is handled by /logout, not the Auth.js client sign-out flow, so Intertool can clear Auth.js cookies and the SaaS intertool.org cookie together. Keep /logout public in proxy.ts and reserved in lib/org-slugs.ts.
SaaS control-plane reads and writes prefer Postgres when DATABASE_URL, POSTGRES_URL, or POSTGRES_PRISMA_URL is configured:
settings/RBAC/invitations/tokens/audit -> lib/control-plane.ts -> intertool_* Postgres tablesStripe billing follows this path:
Owner -> /api/billing/checkout -> Stripe Checkout -> /api/webhooks/stripe -> saveSettings(plan/subscription ids)Private distribution endpoints follow this path:
Authenticated client -> /api/mcp/v0/servers or /api/claude/marketplace -> lib/registry -> lib/distributionStorage contracts
Registry items use Skill from lib/types.ts.
Supported item types:
skillmcp-serveragent-toolprompt-template
Supported source formats:
skill-yamlskill-mdserver-jsonzip
MCP server items may include mcp_config, which stores the original server.json object. CLI install and raw download should use that object when present and only fall back to generated install metadata for older records.
Important storage limits:
- Package files are stored under
{type-folder}/{slug}/files/{path}. - At most 20 package files are allowed.
- Each package file must be 10MB or smaller.
- Package files must be 50MB or smaller in total.
- Paths are normalized by
sanitizeSkillFilePath. - SaaS managed storage may set
s3_prefix=orgs/{orgSlug}for either Vercel Blob or S3-compatible storage. Storage helpers must preserve prefix isolation and return unprefixed keys to registry callers.
Self-hosted settings resolve in this order:
registry/settings.json- Upstash Redis key
self-hosted:settings - S3 environment variables
SaaS settings resolve by org slug from Postgres first, then local fallback JSON in development, then the legacy Upstash Redis metadata path. Hosted SaaS should use Postgres as the source of truth for org settings, memberships, invitations, API tokens, audit events, and Stripe identifiers. Org deletion must remove the current org's control-plane rows and only bulk-delete registry objects when the org uses managed storage under s3_prefix=orgs/{orgSlug}. INTERTOOL_STORAGE_DRIVER=vercel-blob uses Vercel Blob through @vercel/blob; the default s3 driver uses the AWS SDK.
Auth and permissions
Web sessions use NextAuth v5 in lib/auth.ts. GitHub and Google providers are enabled only when credentials are configured. OAuth credentials can come from admin settings or environment variables.
API routes use authenticateApi from lib/api-auth.ts. It accepts:
- a NextAuth session for browser requests
- per-user bearer tokens with the
itk_prefix - legacy
INTERTOOL_API_KEYfallback
RBAC lives in lib/rbac.ts. Roles are owner, admin, and member. Permission checks should use hasPermission instead of duplicating role logic in routes.
Governance audit events use appendAuditEvent from lib/audit-log.ts. Audit writes are best effort and should not block the primary user action unless a future compliance mode explicitly requires that.
Billing integrations should update RegistrySettings.plan and RegistrySettings.subscription_status. Hosted Stripe billing uses owner-only POST /api/billing/checkout for subscription Checkout Sessions and POST /api/webhooks/stripe for signed subscription lifecycle events. PATCH /api/billing/plan remains owner-only and is intended for back-office corrections or migrations.
CLI commands
The CLI is in cli/src/index.ts and cli/src/commands/.
Commands:
loginlogoutwhoamisearchinstallremovelistinfopublishupdateinitcompletions
When changing command behavior, update content/docs/cli-reference.mdx and run the CLI build from cli/.
Development commands
npm run dev
npm run lint
npm run typecheck
npm run test
npm run test:e2e
npm run buildCLI checks:
cd cli
npm run build
node dist/index.js --helpInstall Playwright browsers before the first E2E run:
npm run test:e2e:installChange rules for LLM agents
- Read the relevant route, component, library module, CLI command, and docs before editing.
- Preserve existing uncommitted work. Do not revert unrelated changes.
- Keep behavior changes close to their owning module.
- Prefer existing helpers in
lib/andcomponents/ui/over new abstractions. - Use role, permission, and validation helpers instead of duplicating checks.
- If changing CLI, API, auth, publishing, install behavior, or user-facing UX, update
content/docs/. - If changing publish review, item status semantics, or audit events, update
content/docs/publishing.mdx,content/docs/api/overview.mdx, and this page. - If changing plan limits, managed storage, Stripe billing, Postgres control-plane behavior, security scan semantics, or distribution manifests, update
content/docs/architecture.mdx,content/docs/deployment.mdx,content/docs/api/overview.mdx, and this page. - If changing browser-visible behavior, add or update Playwright coverage where practical.
- If changing public routes, docs, canonical origins, metadata, or machine-readable discovery output, update the SEO/AEO helpers and deployment docs together.
- If changing storage shape, update
lib/types.ts, registry read/write logic, docs, and CLI consumers together.
High-risk areas
- Auth callback behavior, cookies, org routing, and OAuth provider setup.
- Postgres control-plane schema changes and migrations.
- Stripe webhook signature verification and subscription state mapping.
- Object storage keys, registry indexing, file downloads, and package file limits.
- RBAC permission gates for publish, edit, delete, members, tokens, and settings.
- CLI install/update paths that write into user projects.
- SaaS path rewriting in
proxy.tsand org cookie fallback for API requests. - Docs and LLM endpoints, because
/llms-full.txtdepends on Fumadocs source metadata and MDX files.