Reference pages fall back to the page title for their meta description.
Pass only a real description to the card, and have the route drop any
description that merely repeats the title.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- only catalog toolkit pages ("<Name> - Composio Toolkit") get the
"<Name> Toolkit" card title; the toolkits index and MDX guides keep
their own titles instead of "Toolkits Toolkit"
- the home card description is a shared constant used by the URL
builder, so the /docs index page and the root layout produce the same
image URL and the live app count is never dropped
- update the integration expectation from ?variant=home to the new
section=home URL
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rebuild the /api/og route around a shared shell with a slot per section
(docs, toolkits, API reference, changelog, home) on the docs dark surface,
with a light variant behind theme=light.
- Geist Sans / Mono vendored as TTF (Satori cannot read the site's woff2)
- Composio wordmark and mark sliced from the existing logo SVGs
- toolkit cards link the Composio mark to the toolkit logo; logos only
load from Composio hosts and use the CDN's dark variant
- reference cards show a REST API pill and version; changelog cards show
the date once as an eyebrow
- home card counts apps from the live catalog label
- balanced title and description wrapping, faded pixel-grid background
- assets traced for the build via outputFileTracingIncludes
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Replace the exhaustive `/llms.txt` dump with a short routing map for
product selection, installation, authentication, sessions, execution,
and troubleshooting. Keep the full catalog at `/llms-index.txt`, using
named links and descriptions, and put that catalog and other long-tail
resources under Optional. Current REST v3.1 and legacy v3.0 remain
explicitly separated.
Fixes [DEVREL-34](https://linear.app/composio/issue/DEVREL-34). The
format follows the descriptive-link and Optional conventions in the
[llms.txt proposal](https://llmstxt.org/).
Validation: 551 static tests passed, including bounded routing-map
coverage and route resolution. Typecheck, lint, and link validation
passed. Existing exhaustive-catalog coverage now tests
`/llms-index.txt`; the HTTP version-grouping test follows the new
catalog route. Existing lint warnings remain.
Agents reading individual pages or `/llms-full.txt` could miss the
Markdown changelog. Its dated `.md` links also matched a broad legacy
redirect and landed on HTML instead of release-note Markdown.
Link page Markdown and the full corpus to `/docs/changelog.md`, and
route dated `.md` and `.mdx` requests to the existing Markdown renderer
before the legacy HTML redirects. Add an HTTP regression that follows
quickstart → changelog → dated release and checks both extensions.
Fixes [DEVREL-31](https://linear.app/composio/issue/DEVREL-31).
Validation: typecheck, link validation, and all 551 static tests passed
for discovery. The new HTTP test reproduced the redirect defect locally
and in CI. The corrected combined production build passed. Its full HTTP
suite passed 92 tests with one existing API-key-dependent skip,
including dated .md and .mdx release-note checks. No new feed format or
dependency is added.
## Summary
Applies the top findings from a multi-reviewer code review of #4335
(which merged before these could land on the PR branch). Four validated
findings, all small and behavior-preserving outside the fixes
themselves:
- **Cross-tab theme fight (P1):** #4335 routed the product-derived theme
through next-themes' shared `theme` localStorage key -- written by the
root layout's inline head script on every hard load and by `setTheme` on
every client switch. next-themes listens for cross-tab storage events on
that key, so two docs tabs on different products (Platform dark / For
You light) silently repaint each other with no self-heal (the provider
effect's deps are `[product, setTheme]`, so the flipped tab never
corrects). The product theme is derived state, not a preference: this PR
applies it directly to the document element (`applyProductTheme`) and
passes `forcedTheme: initialTheme` from the server-resolved product so
hydration cannot flip a stale stored value. No `theme` localStorage
writes remain anywhere.
- **theme-color meta (P2):** the two `prefers-color-scheme`-keyed metas
meant mobile browser chrome mismatched the forced page theme (white
chrome over dark Platform pages for light-OS users). Now a single meta
keyed to the product theme.
- **Switcher current-option href (P2):** the popover option marked
`aria-current="page"` resolved to the product landing route, so
middle-click, hover status bar, and copy-link all pointed at the wrong
URL. It now hrefs the current pathname.
- **Explore-card aria-label (P3):** `aria-label` replaced the link's
accessible name, so the product description inside the card was not
announced. Dropped; heading + description now form the name.
## Changes
- `docs/app/layout.tsx` -- inline script no longer writes localStorage
(pre-paint class priming unchanged); single product-keyed `theme-color`
meta; `forcedTheme: initialTheme` on `RootProvider`.
- `docs/components/docs-product-context.tsx` -- `setTheme`/`useTheme`
removed; new `applyProductTheme` used in the product effect and the
flushSync commit.
- `docs/components/product-switcher.tsx` -- `destination = isCurrent ?
pathname : docsProductDestination(...)`.
- `docs/components/home-surfaces.tsx` -- Explore-card `aria-label`
removed.
- `docs/tests/static/product-navigation.test.ts` -- pins the new
invariants (`applyProductTheme`, `forcedTheme: initialTheme`, and a
negative assertion that `localStorage.setItem('theme'` stays out).
## Testing
- `bun test tests/static/` -- 541 pass / 0 fail
- `bun run types:check` -- clean
- `bun run lint` -- only pre-existing warnings (`home-surfaces.tsx:102`
`no-img-element` is in `ForYouVisual`, untouched)
- Worth a manual check: two tabs on different products no longer repaint
each other (static tests cannot prove cross-tab storage isolation)
## Notes
- Docs-only change; no changeset required.
- Review context: follow-up to #4335. Remaining review findings
(navigation state-machine races, theme-scope design call, decision
record) are tracked separately.
## Summary
Composio's new pricing went live on Aug 15, 2026: **Hobby** ($0) /
**Pro** ($29/mo) / **Enterprise** (custom). This PR updates the public
docs to describe only the current offering and reprices premium tools as
pass-through (provider cost + 5% platform fee).
## Principle
- Docs describe the **current** plans only (Hobby / Pro / Enterprise).
No Starter/Growth tables, no dual documentation.
- Where a legacy note is genuinely useful (rate limits), exactly one
sentence pointing pre-Aug-15 customers to
https://composio.dev/pricing/legacy.
- **Link to https://composio.dev/pricing instead of repeating numbers**,
so future price changes are a one-place edit.
## Files changed
- `docs/content/toolkits/pro-tools.mdx` — replaced the "3x the cost"
line and the Totally Free / Ridiculously Cheap / Serious Business tier
table with pass-through pricing copy: paid third-party providers,
provider price + 5% platform fee (no markup), per-call prices on the
pricing page's "Premium tools" section, Hobby includes up to $2/mo of
premium tool usage, prices depend on provider and can change with
advance notice. Retitled the page from "Pro Tools" to "Premium Tools"
(matches the pricing page and avoids confusion with the new Pro plan).
URL slug `/toolkits/pro-tools` is unchanged so no links break. Rest of
the page (what counts as a premium tool, rate limits) intact.
- `docs/content/reference/rate-limits.mdx` +
`docs/content/reference/v3/rate-limits.mdx` (manual copies, updated
identically) — plan table now Hobby 2,000 req/min · Pro 10,000 req/min ·
Enterprise Custom (kept the doc's existing per-minute unit and "Custom"
wording for Enterprise). No legacy/grandfathering note — docs describe
current plans only; grandfathered customers are served by the dashboard
and composio.dev/pricing/legacy.
- `docs/app/llms.mdx/[[...slug]]/route.ts`,
`docs/components/toolkits/toolkits-landing.tsx` — label text "Pro Tools"
→ "Premium Tools" (link targets unchanged).
## Not changed / notes for reviewers
- `docs/content/docs/common-faq.mdx` no longer exists on `next` (removed
in the sessions-first rewrite, #3637); a grep for self-host / on-prem
across `docs/content` found **no** page advertising self-hosting as an
Enterprise feature, so nothing to remove there.
- Grep sweep (case-insensitive) over `docs/content` for: Starter, Growth
plan/tier, Ridiculously, Serious Business, Totally Free, on-prem,
self-host(ed), $229, $599, 20k tool calls, 200k, per seat, per-seat, 3x
the cost. All customer-facing hits were in the three files above and are
fixed. Left alone:
- `changelog/*` — historical entries (self-hosted Supabase/PostHog
instances, "self-hosted deployments need backend version X"); these
refer to third-party instances or historical SDK notes, not to an
Enterprise plan feature.
- `docs/auth-configuration/custom-auth-configs.mdx:23`,
`docs/authentication/custom-app-vs-managed-app.mdx:30` — "self-hosted"
refers to the *customer's* self-hosted third-party app (e.g. Salesforce
subdomain), unrelated to Composio plans.
- `docs/configuring-sessions.mdx`, `docs/sandbox/remote.mdx` —
"Sandboxes are not billed today" note; not part of this change, flagging
in case sandbox billing status changed with the new pricing.
- `pro-tools.mdx` "Rate limits" table: **fixed in `421789d90`** —
dropped the "Standard Tool Calls" column (100/min · 5,000/min
contradicted `reference/rate-limits.mdx`), kept only the
premium-execution limiter mapped to plan names (Hobby 1,000/hr · Pro
10,000/hr · Enterprise Custom) with a note that it is separate from the
org API limit. Also added Pro's premium allowance bullet.
## Validation
- `bun run lint` (oxlint): passes; only pre-existing warnings in
untouched files.
- `bun run lint:links` (`scripts/validate-links.ts`): 0 errors.
## Related PRs
- landing: https://github.com/ComposioHQ/landing/pull/289
- platform: https://github.com/ComposioHQ/platform/pull/12078
- dashboard: https://github.com/ComposioHQ/dashboard/pull/1326🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01P3JgWs8DcjeQTRKoJd8gmQ
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The docs hero, feature cards, site metadata, and llms.txt all hardcoded
"1,000+" apps, while the published catalog is 1,327 toolkits (the length of
docs/public/data/toolkits-list.json, already rendered by the /toolkits page).
Add a server-only helper docs/lib/toolkit-count.ts that imports that same
JSON and exports TOOLKIT_COUNT_LABEL = Math.floor(len/100)*100 -> "1,300+",
with the locale pinned (toLocaleString('en-US')) so the separator is a comma
on any build host. Six server-side files now consume it. No client bundle
cost: none of the importers is a "use client" module, so the JSON never
reaches the browser.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extracting buildReferenceTree() existed only so a module-level memo could reuse
the tree. The memo is gone, so the extraction was scaffolding for nothing and
every reference-layout hunk was pure churn in a PR about adding an event.
Both files go back to their shape on next, plus the same four lines the docs and
examples layouts already take. The non-test diff is now insertions only.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
getNavIndex() awaited buildReferenceTree() on its own while Layout had already
awaited the same tree for DocsLayout, so the first render built and filtered the
reference tree twice. The memo it protected was a module-level singleton with no
key, which is what prompted removing the parameter in the first place.
Dropping the memo resolves both: the index is one traversal over ~64 nodes built
from the tree already in hand, matching how the docs and examples layouts work.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The position assertions pinned absolute indices into the live content tree, so
adding any page to meta.json failed a test named for traversal semantics with
"expected 12, received 13". Assert the invariant instead — a folder occupies one
sibling slot, and its children restart at 1 — which stays green when content
moves and still fails if position starts threading through folders again.
getNavIndex(tree) ignored its argument on every call after the first. The
reference tree is only reachable after an await, so it stays memoized, but the
signature no longer claims to vary with a parameter it never read.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two-ways-to-start hero: cards now lead with the canonical Composio + product-badge lockup (dashboard-parity) and the same product mocks the dashboard onboarding path step uses — a chat composer flanked by client logos for For You, a code panel for Platform. Right link pane width matches a feature-grid card exactly.
Features grid: whole-card links restored, each mock fades into the card edge with a mask-image, cards live on a single flush bg-fd-card surface. Tools mock bumps from an 8×2 grid of 16 tiles to 10×3 = 30 for more impact, Auth becomes a live schematic — one user identity card wired to three connected-account cards via elbow connectors computed from real DOM geometry (`home-auth-diagram.tsx`), Triggers drops the fake LIVE ping in favor of a plain event list, Sandbox drops the workbench chrome + CPU lights for a clean filename + code panel.
Resources: adds a Platform Dashboard link so the 3×2 grid is complete. Drops the "Get started / What you get / Reach for the rest" eyebrows and section heading — headings stand on their own.
Copy: `audience` → `product`, so llms.txt emits `**Platform**` / `**For You**` instead of `**Platform**` / `**For you**`; matched in `home-navigation.test.ts`.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Review follow-ups on the docs_sidebar_click instrumentation.
usePostHog() resolves to the posthog-js module singleton whether or not a
provider is mounted, so the `!posthog` guard never fired: with no
NEXT_PUBLIC_POSTHOG_KEY the listener still attached and every sidebar
click called capture() on an uninitialized instance, logging "You must
initialize PostHog before calling posthog.capture". Gate the effect on
the same env var components/posthog-provider.tsx gates on.
position threaded through folder recursion, so a collapsed folder's
hidden children counted as rows: Triggers is the 4th visible row under
Core concepts but reported 11, which would inflate any "clicks land in
the top N rows" reading — the same inference error this instrumentation
exists to remove. Count per level instead, so a folder occupies one row
for its siblings and its children get their own 1..n sequence. Making
group and position per-level locals also removes the latent collision
where a separator nested in a folder reset the counter for the folder's
siblings; a test pins that case.
Also: capture auxclick (middle button only) so sidebar links opened in a
new tab are not missing while Cmd/Ctrl+click ones are counted; a folder
with a non-string name now reports folder: null rather than inheriting
its parent's label; and both reference layouts memoize the index instead
of rebuilding it on every render.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The docs app had exactly one posthog.capture call ($pageview), so any
question about how people move through the sidebar had to be answered by
reverse-engineering pageview ordering within a session. $referring_domain
is no help either: pageviews are captured manually on client-side route
change, so document.referrer never updates on internal navigation.
Adds a docs_sidebar_click event carrying href, group, folder, depth,
position and from_path. Group/folder/depth are derived from the fumadocs
page tree at build time and the click handler only does an href lookup —
reading them off the rendered sidebar would mean depending on separators
being <p> and folder triggers being <button>, which is fumadocs-internal
and breaks on upgrade.
Mounted on the docs, examples and both reference sidebars. Nothing fires
when PostHog is unconfigured, for non-sidebar links, or for an href that
is not in the index.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four review fixes on the sidebar restore.
Folder headings do not close, so every page emitted after a folder read
as one of that folder's children. Making `authentication` a folder
mid-list swallowed `triggers` and `skills` into `### Authentication`.
Reordering meta.json would fix the output but push Authentication below
Skills in the human sidebar, which is what this PR exists to prevent —
so walkPageTree now buffers each separator section and flushes its plain
pages ahead of its folders. Legacy-separator skipping is unchanged. This
also fixes the pre-existing case where `agent-plugins`, `cli` and
`composio-connect` read as children of `#### Custom providers`.
Drop "index" from authentication/meta.json. Listing it clears
`node.index`, so fumadocs renders the folder as a chevron BUTTON plus a
duplicate child row instead of a SidebarFolderLink — the row a reader
clicks to reach /docs/authentication (1,850 views/month) expanded the
folder instead of navigating. Omitting it matches how `providers` and
`migration-guide` already render. Verified in the built DOM: an A with
href=/docs/authentication, no duplicate row, /docs/authentication.md
still emitted exactly once via node.index.
Rename the ---Security and data--- separator to ---Security---; it
duplicated the folder title directly beneath it, in llms.txt and in the
sidebar.
Point the last three agent/instructions/context.md bullets at canonical
paths rather than redirect-only /docs/authenticating-users/* ones, so
that file is internally consistent.
Extend the llms.txt section test to assert the nearest preceding heading
of any level, and to cover the sibling pages that regressed. It fails
against the old walk.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PR #4099 dropped 8 auth pages from meta.json. That was a net win for
machines (Loop 5 eval: 84/100 vs 77/100, tool-routing failure mode gone)
but it made the pages unreachable by clicking. PostHog, weekday-matched
and control-adjusted, shows the affected pages down 14-64pp beyond the
site-wide baseline drift.
Restore human navigation without touching the machine-facing wins:
- authentication.mdx becomes authentication/index.mdx and the 7 sibling
auth pages move into the folder. /docs/authentication keeps its URL
(fumadocs serves index.mdx at the folder route), so Core concepts
still shows one row and the top-level sidebar row count stays 20.
- shared-connections moves into extending-sessions: it is experimental
and is a session capability, not a core auth concept.
- "Migration and security" splits into "Migration" and "Security and
data" — separator headings, not clickable rows.
- Drop AUTHENTICATION_GUIDE_URLS from app/llms.txt/route.ts. The pages
are back in the page tree, so they emit automatically under Core
concepts -> Authentication; the hardcoded list would now duplicate.
- 8 permanent redirects for the old URLs (36-42% Google entry rate on
most of them), plus existing redirect destinations repointed so none
of them chain.
- ~90 inbound links rewritten across content, api-overviews, app, lib
and agent instructions. lint:links is the gate: 0 errors.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This PR:
- fixes
[UXE-233](https://linear.app/composio/issue/UXE-233/docs-should-explicitly-direct-agents-to-use-v31-apis)
- makes the agent-facing Markdown channels publish concrete REST v3.1
base URLs and endpoint tables while preserving the supported v3.0
reference tree
- centralizes `REST_VERSION_GUIDANCE`, `TOOL_VERSION_GUIDANCE`, and
raw-spec path matching in `lib/api-version-guidance.ts`
- renders `ApiBaseUrl` and `ApiEndpointsTable` in authored MDX and adds
an explicit version pointer to generated OpenAPI operation Markdown
- separates current and legacy REST references in `llms.txt`, excludes
v3.0 page bodies from `llms-full.txt`, and adds v3.1 selection guidance
to Context7
- validates serialized `ApiEndpointsTable` payloads with Zod before
generation while preserving forward-compatible fields
- addresses review feedback for the renamed authentication page,
SDK-reference pointer scope, generator validation behavior, and stale
OpenAPI tool-version descriptions
## Context
REST v3.0 is superseded but remains supported for existing integrations.
This PR changes what new agent-generated code discovers first; it does
not require existing v3.0 callers to migrate.
Authenticated read-only probes against the deployed API confirmed that
the affected v3 endpoints default to `00000000_00`, while their v3.1
counterparts default to `latest`. `POST /tools/scopes/required` is
available only on v3.1 and defaults to `latest`.
This PR does not move public URLs. A future `/reference/v3/` to
`/reference/v3.0/` migration remains separate because it has independent
compatibility and search-indexing risk.
## Verification
- `bun test tests/static/`
- `bun run build`
- `bun run test:integration`
- `bun run types:check`
- `bun run lint`
## Review follow-up
The version-default guidance is intentionally limited to the five
verified tool endpoints. v3.1 is a structural superset of v3, so this PR
does not claim route parity. Static coverage rejects broad non-tool
parity wording in both the shared guidance and Context7 rules.
This PR:
- builds on top of https://github.com/ComposioHQ/composio/pull/3966
- enables `typescript/no-explicit-any` (error, `fixToUnknown`) for docs
in `docs/.oxlintrc.json` and removes every remaining explicit `any` in
docs code
- parses untyped/external data once at the boundary with zod v4 schemas
and lets `z.infer` types flow downstream — no hand-rolled `'x' in obj`
guard chains, no `as`-casts of untyped page data, no
`docs/lib/unknown-value.ts`
- adds domain schema modules: `docs/lib/toolkit-schema.ts` (recursive
JSON-Schema node, raw tool/trigger payloads, list envelopes) and
`docs/lib/reference-page-data.ts` (fumadocs reference page data for both
reference routes)
- rewrites `validate-links.ts`, `generate-toolkits.ts`,
`generate-meta-tools.ts`, the `llms.mdx` route, and
`deprecated-api-sidebar.tsx` on those schemas with identical validation
outcomes
- carries the pure typing improvements from the earlier attempt (typed
reference source in `source.ts`, `LLMPage`/`PageLike`, typed
`ClientLogo[]` in `logo-bar.tsx`, component `any` removals)
- adds `tests/static/toolkit-schema.test.ts` and
`tests/static/generate-toolkits.test.ts` pinning the transform shapes;
no changeset (docs is not published)
## Context
Second of the three-PR split of #3958, replacing its rejected
structural-guard approach with zod schemas at the data boundaries.
Verified with `bun run lint`, `bun run types:check`, `bun test
tests/static/` (125 pass), `bun run lint:links`, and a full `next
build`.
## Review follow-up
Addressed the regressions reported in [the Zod boundary
re-review](https://github.com/ComposioHQ/composio/pull/3967#issuecomment-5105279224):
scalar JSON Schema enums and auth defaults are preserved as strings,
malformed toolkit page envelopes abort generation, and the pre-refactor
empty-string fallbacks are restored. Regression coverage lives in
`tests/static/toolkit-schema.test.ts` and
`tests/static/generate-toolkits.test.ts`.
Verified on `2f26c40be` with `bun test tests/static/` (125 pass), `bun
run types:check`, and `bun run lint` (0 errors; existing warnings only).
This PR:
- replaces ESLint with oxlint across the pnpm workspace and the
Bun-based docs site, porting the rules to `.oxlintrc.json` /
`docs/.oxlintrc.json` with behavior parity (restricted-syntax selectors
kept via `oxlint-plugin-eslint`)
- migrates typecheck to TypeScript 7 (`typescript@^7.0.2` catalog) and
keeps a TS6 pin for JS compiler API consumers via a named `ts6` pnpm
catalog (`ts/scripts/validate-examples.ts`, the `@composio/cli` generate
pipeline). The CLI's `typescript` dependency rebinds only the
compiler-API import — its typecheck still runs the root TS7 `tsc`, since
the alias package only ships a `tsc6` bin (documented in
`ts/packages/cli/AGENTS.md`)
- removes the `paths` mappings that pointed `@composio/core` (and, in
`experimental`, `@composio/json-schema-to-zod` plus core-internal
`#`-imports) at sibling `src` directories: under TS7, tsdown's
tsgo-based dts step emitted stray `.d.ts` files next to those
out-of-root sources on every dependent package build. Workspace deps now
resolve through their built dist types, which turbo's `dependsOn:
^build` already guarantees exist — and which the deep-path exports
(`@composio/core/*`) always used anyway
- renames the cli boundary tooling `eslint-boundaries*` →
`lint-boundaries*` and hardens the scanner to reject `oxlint-disable`
spellings so the disable manifest cannot be bypassed
- rewrites inline `eslint-disable` comments to oxlint rule names
(comment-only; no runtime changes), and adds **one new** declared
boundary: `tool-file-uploads.ts` needs `no-restricted-imports` disabled
for `node:crypto` (MD5 for the presigned-upload checksum is not in Web
Crypto), because oxlint also catches dynamic `await import()` where
ESLint did not. The manifest grows 46 → 47 deliberately
- updates CI path filters, `turbo.jsonc` lint inputs, and the docs
typescript-check workflow (renamed to "Docs - Lint and TypeScript
Validation" since it now lints too); drops `eslint`,
`typescript-eslint`, `eslint-config-next`, and `globals` from the
dependency graphs
- ships no changeset: I built `@composio/core` and `@composio/anthropic`
on this branch and on the pre-migration base and diffed the emitted
`dist/**/*.d.mts`. The provider output is byte-identical. Core's output
is **semantically identical but not byte-identical**: TS7 changes quote
style (`"x"` → `'x'`), object-property and union-member ordering in
inferred types, and picks equivalent shorter re-export alias paths for
five signatures (e.g. `OpenAI.Beta.Threads.Runs.Run` →
`OpenAI.Beta.Threads.Run` — verified both names alias the same type in
the shipped typings). Chunk-name hashes shift as a consequence. No type
gains, losses, or shape changes; `attw` and `publint` pass on the TS7
build
## Context
First of a three-PR split of #3958. The type-safety refactors are
stacked on this branch and merge after it:
- docs: https://github.com/ComposioHQ/composio/pull/3967
- `@composio/core`: https://github.com/ComposioHQ/composio/pull/3968
## Summary
- upgrades `fumadocs-openapi` 10 → 11, `fumadocs-mdx` 14 → 15, and
`fumadocs-core` / `fumadocs-ui` 16.4 → 16.13
- migrates the Fumadocs OpenAPI API while preserving the custom schema
renderer
- restores local `$ref` resolution in both the visible API schema UI and
generated LLM markdown
- reduces API-reference client payloads by slicing the bundled OpenAPI
document to each page's reachable operations and components
- restores required badges for GET parameters
- normalizes the OpenAPI `no_auth` sentinel so explicitly public
endpoints render without authentication
- moves to `getOpenAPIPageProps()` / `OpenAPIPageProps` and removes
obsolete CSS overrides
## Correctness fixes
Fumadocs 11 changed the page contract from a server-resolved document id
to a client-side bundled document. That exposed several silent
regressions:
- **Reference resolution:** bundled documents retain local `$ref`s. The
LLM renderer now dereferences them, including alias chains and cycles,
while the custom schema renderer uses Fumadocs' resolver and retains raw
reference identity for stable deduplication.
- **Dereference reuse:** repeated LLM-page requests reuse the
dereferenced copy for each cached bundled document instead of walking
the complete spec per page.
- **Client payload size:** each API page now receives only its selected
operations and transitively reachable components. The slicer falls back
to the complete document for non-component pointers, deep component
pointers, missing operations, or dangling references.
- **Required badges:** `readOnly` cannot distinguish GET inputs from
responses. The renderer now uses the page hook's client name to identify
responses.
- **Recursive rendering:** schema markdown rendering now caps both
structural recursion and nested array type rendering.
- **No-auth normalization:** the undeclared `no_auth` sentinel is
removed without discarding any real security alternatives that may
accompany it.
- **Contract drift:** code consuming `getSchema()` now treats `bundled`
as required, matching the upstream type.
Review follow-up also replaces the new OpenAPI `any` types with typed
Fumadocs page props and a narrow recursive schema model. Historical
Fumadocs 10/11 migration explanations live here in the PR, not as
version-specific source comments; source comments retain only durable
invariants.
## Payload impact
| | before | after |
| --- | --- | --- |
| bundled document | 451 KB | 7.7 KB avg / 30 KB worst |
| served page HTML | 693 KB | 198 KB |
| 10-page sample | 6.55 MB | 2.02 MB (69% smaller) |
## Verification
- `bun install --frozen-lockfile`
- `bun run test` — 89 pass
- `bun run lint:links` — 0 errors
- `bun run lint` — 0 errors (77 existing warnings)
- `bun run types:check`
- `bun run build`
- production server + `bun run test:integration` — 74 pass, including
v3.1/v3 API pages, redirects, search, and LLM endpoints
The production build has one existing Turbopack NFT tracing warning from
`next.config.mjs`; it does not fail the build.
## Production vs preview checks
A live sample comparison between [production](https://docs.composio.dev)
and the [PR
preview](https://docs-git-chore-docs-fumadocs-11.preview.composio.dev)
found no docs regression:
- all 14 representative routes returned 200 with matching titles,
headings, canonical production URLs, and key content
- redirects for `/`, `/api-reference`, `/tools`, and `/docs/welcome`
matched exactly
- the sampled pages exposed the same 1,137 internal-link targets; a
balanced sample of 29 links resolved successfully on both deployments
- sampled v3 and v3.1 OpenAPI pages retained endpoint paths, required
fields, response schemas, and legacy indicators
- the generated OpenAPI LLM page was byte-for-byte identical
- selecting TypeScript in a hydrated browser rendered both inactive-tab
examples and synchronized the language tab groups
- `llms.txt` retained the same 139 unique lines in a different order
- `/docs/quickstart.md` only added an explicit `[#next]` heading anchor
The sampled OpenAPI HTML was roughly 35–42% smaller in the preview,
consistent with document slicing rather than missing rendered content.
## Summary
Implements the docs half of **PLEN-2793** — renders a typed public
reference for the payloads Composio delivers to customer webhook URLs,
under **API Reference → Webhook Events**.
Pairs with platform PR ComposioHQ/platform#11389, which generates the
spec.
## What's here
- **`docs/public/openapi-webhooks.json`** — the generated OpenAPI
**3.1** spec (top-level `webhooks`: `composio.trigger.message`,
`composio.connected_account.expired`, `composio.trigger.disabled`),
produced from the webhook payload Zod schemas in Apollo (SSOT). Finishes
the earlier untracked WIP: adds the missing `trigger.disabled` event and
reuses shared schemas as `$ref` (`WebhookEventEnvelope`,
`ConnectedAccountDetailed`).
- **`docs/lib/openapi.ts`** — adds the spec as a **second input** to the
v3.1 reference source. Fumadocs (`fumadocs-openapi`) renders the
`webhooks` block natively; operations group under the "Webhook Events"
tag at `api-reference/webhook-events/*`.
- **`webhook-events/index.mdx`** — landing page listing the three
events, cross-linked to the Webhook Subscriptions API and signature
verification.
## Why a separate 3.1 spec
`webhooks` is a 3.1-only top-level field; the main `openapi.json` is
3.0. A separate file keeps the main spec (and its sync pipeline)
untouched and avoids the docs' union-normalisation pass. See the
platform PR for the full rationale.
## Verified locally
- [x] `bun scripts/validate-links.ts` — **0 errors** (the generated
`handle_composio_*` webhook pages resolve; no collision with the
hand-authored `index.mdx`)
- [x] `bun test tests/static/` — 33 pass / 0 fail
- [x] `bun run types:check` — clean
## Notes
- Setup, subscription, and signature-verification docs already exist
(`setting-up-triggers/*`) and are cross-linked, not rewritten.
- Follow-up (optional): auto-sync the webhooks spec from Apollo on prod
deploy (currently committed by hand), mirroring the main-spec
`docs-update-data` pipeline.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: jkomyno <alberto@composio.dev>
This PR:
- follows up on https://github.com/ComposioHQ/composio/pull/3838
- renders the existing `Legacy` badge in v3 and v3.1 endpoint headers
when the OpenAPI operation has `deprecated: true`
- centralizes deprecated-endpoint badge copy across API overview tables
and detail pages
- adds static coverage plus running-server assertions for the reported
routes and active control endpoints
- verifies the fix with `bun run test`, `bun run types:check`, `bun run
lint:links`, `bun run build`, and the focused integration suite
Tag every dashboard.composio.dev link in authored docs content and
components with utm_source=docs plus utm_medium/utm_campaign, and enforce
the convention going forward: an ESLint no-restricted-syntax rule covers
TS/TSX and a static bun test covers MDX (runs in docs-tests CI).
- content links use utm_medium=content and utm_campaign=<page-slug>
- content/reference is excluded (generated upstream)
- delete unused landing-hero/_stub-links.ts
- fix the no-html-link-for-pages errors; downgrade the pre-existing
react-hooks compiler violations to warnings until burned down, so
bun run lint exits with zero errors
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This PR:
- reverts https://github.com/ComposioHQ/composio/pull/3780
- restores the TypeScript `composio.create()` and `composio.use()`
session aliases, with their runtime and type-test coverage
- restores the prior deprecation state for
`BaseProvider.wrapMcpServerResponse`
- removes the pre-v1 breaking-change changeset so the release PR no
longer advertises this removal
The v1 API-freeze change should be recreated later as a draft PR and
kept out of the merge queue until v1 is ready.
## What and why
This makes the intended v1 API cleanup real rather than postponing it to
v2:
- Remove the TypeScript root aliases `composio.create(...)` and
`composio.use(...)`. Session creation and reuse now live only at
`composio.sessions.create(...)` and `composio.sessions.use(...)`. This
is a deliberate breaking change, reflected by a major changeset.
- Retain `BaseProvider.wrapMcpServerResponse` as the stable v1 provider
SPI. Its earlier deprecation pointed to a method that was never
introduced.
The scope is intentionally narrow: it does **not** remove unrelated
deprecated APIs, and Python keeps its supported `Composio.create/use`
API. The TypeScript docs, examples, providers, runtime fixtures,
generated SDK reference, and API-reference indexes now use the
namespaced TypeScript API. Historical changelog examples are left as
history.
## Verification
- `pnpm typecheck`
- `pnpm --filter @composio/core test -- --run test/core/session.test.ts`
(42 files, 1,018 tests)
- `pnpm exec eslint ts/packages/core/src/composio.ts`
- `pnpm --filter @composio/core generate:docs`
- `cd docs && bun run generate:api-index`
- `cd docs && bun run types:check`
- `git diff --check` and targeted scans for removed TypeScript aliases
I also attempted the affected Node and Cloudflare runtime E2E suites.
They cannot initialize in this checkout without `COMPOSIO_API_KEY` (and,
for Cloudflare, `COMPOSIO_BASE_URL` and `OPENAI_API_KEY`); they did not
report a product assertion failure.
## Problem
Google search results show a generic globe instead of the Composio
favicon for docs.composio.dev.
## Root cause
The site violated three of Google's favicon guidelines:
1. **`/favicon.ico` returned 404** — the well-known fallback path
Google's favicon crawler checks didn't exist (only `app/icon.png` was
configured).
2. **The icon was 1350×1350px** — Google wants a square icon that's a
multiple of 48px (48, 96, 192, …).
3. **The favicon URL changed on every deploy** — Next.js emits the icon
link with a per-deploy content-hash query (`/icon.png?icon.<hash>.png`),
so Google never saw a stable URL to index. The favicon shipped in
January and still hadn't been picked up.
Crawlability was fine (robots.txt allows everything; the icon serves 200
to Googlebot), so these were the only blockers.
## Fix
- Add `app/favicon.ico` — multi-resolution ICO (16/32/48px), served by
Next.js at the stable `/favicon.ico` path
- Resize `app/icon.png` 1350×1350 → **192×192** (multiple of 48; 19.5KB
→ 6.8KB)
- Resize `app/apple-icon.png` → **180×180** (Apple's standard touch-icon
size)
All generated from the existing logo artwork; background is fully opaque
so it renders correctly on Google's white results page.
## Verification
Ran the docs dev server locally:
- `GET /favicon.ico` → `200 image/x-icon`, valid ICO containing all
three embedded sizes
- Page head now emits `<link rel="icon" href="/favicon.ico"
sizes="48x48">`, `<link rel="icon" href="/icon.png…" sizes="192x192">`,
and `<link rel="apple-touch-icon" … sizes="180x180">`
After deploy: confirm `curl -sI https://docs.composio.dev/favicon.ico`
returns 200, then request re-indexing of the homepage in Search Console.
Google typically refreshes a site's favicon within days to ~two weeks.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01PSoqxdNGZWD2TiuCaJQyVM
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Follow-up doc fixes from a re-audit of the June "Pi Slack-bot friction"
report against the current docs. Low-risk changes across the migration
guides, the example `.md` output, and legacy handling.
## 1. Migration guides: selective legacy + a "Written {date}" stamp
Migration guides are point-in-time documents, but not all are legacy.
Two mechanisms, decoupled:
- **`legacy: true`** (existing Legacy badge) — only on guides that
migrate off something dead: **new-sdk** (deprecated v1 SDK) and
**tool-router-beta** (removed experimental tool router).
- **`written: "{Month YYYY}"`** (new frontmatter field, dates from git
creation) — renders a standalone **"Written {date}"** stamp on *every*
guide, independent of legacy. So current guides (direct-to-sessions,
mcp-servers-to-sessions, toolkit-versioning, the hub) show their date
without being mislabeled legacy.
Files: `source.config.ts` (new `written` field),
`components/legacy-badge.tsx` (plain badge again), docs page (badge +
date row), 6 migration guides.
## 2. Real example code now in the `.md`/llms output
`<FileBuildup>` / `<RepoBrowser>` render an example's actual source
(`bot.ts`, `install.ts`, …) interactively, but they're React components
that don't serialize to markdown — so
`examples/general-agent-with-pi.md` (what an agent fetches) had all the
prose and **no code**. `mdxToCleanMarkdown` now resolves them from the
`FILE_BUILDS` registry. That example's `.md` grows **6.5 KB → 34 KB**
with the real
`createSessionTools`/`proxyExecute`/`waitForConnections`/`verifyWebhook`
code. Also fixes standup-slackbot and local-workbench.
## 3. Legacy pages: flag in `.md`, skip the current-pattern guardrail
`getLLMText` now prepends "Legacy · written {date}" (or "Written {date}"
for current-dated pages) to the `.md`, and **skips the "enforce ONLY the
current patterns" guardrail block on legacy pages** — appending it to a
legacy guide contradicted the guide's own older content (e.g. new-sdk
showing `tools.execute()` as the v3 target).
## 4. Note that `subscribe()` uses Pusher under the hood
Short aside on the triggers subscribe doc, for readers on runtimes that
restrict WebSocket clients.
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary
- Switch the docs Eve agent from the AI Gateway `openai/gpt-5.4-mini`
string to an Inception Labs Mercury 2 OpenAI-compatible chat model.
- Keep tool calling on the chat-completions path and pass Mercury's
`reasoning_effort=medium` through the AI SDK OpenAI adapter.
- Add `DOCS_AGENT_MODEL_FLOW` so the same agent can run either `mercury`
or the old AI Gateway flow for eval comparisons.
- Add docs-agent eve evals covering grounded docs answers, docs
retrieval, citations, and account-specific support refusal.
- Replace the docs-agent retriever with an in-process BM25-style lexical
ranker that returns bounded full content for the top results, so Mercury
gets rich context in one fast tool call instead of a serial
`search_docs` → `read_doc` round trip.
- Precompute BM25 term counts/document frequencies into the generated
`agent/lib/docs-index.ts` snapshot at build time, removing deployed
cold-start corpus construction while keeping retrieval in-process.
- Add opt-in search perf logging (`DOCS_AGENT_SEARCH_PERF_LOG=1`,
optional `DOCS_AGENT_SEARCH_LOG_QUERY=1`) with timings for tokenization,
corpus load/cache, ranking, hydration, total duration, corpus source,
and top URLs.
- Add `eval:agent` and `eval:agent:flows` scripts; `eval:agent:flows`
can run local model-flow comparisons or remote target comparisons via
`DOCS_AGENT_EVAL_TARGETS`.
- Add `INCEPTION_API_KEY` / optional Mercury and gateway model knobs to
`docs/.env.example`, and move `@ai-sdk/openai` to runtime dependencies
for the agent import.
## Notes
- This is intentionally an experiment to see how Mercury's diffusion
model behaves with Eve tool calling (`search_docs` and `read_doc`).
- Preview/runtime environments need `INCEPTION_API_KEY`;
`INCEPTION_MODEL` and `INCEPTION_BASE_URL` are optional overrides.
- The custom fetch prevents accidentally falling back to
`OPENAI_API_KEY` against Inception's endpoint.
- The docs search is lexical/in-memory, not vector search. The slow path
was mostly serial model/tool round trips and cold index construction,
not embedding lookup.
- The generated BM25 snapshot is process-local once loaded: warm for the
lifetime of the running Node/Vercel function instance, and reset on cold
starts, redeploys, or process restarts. The expensive term-count corpus
is now built at docs build time.
- Perf logs omit raw user queries by default; set
`DOCS_AGENT_SEARCH_LOG_QUERY=1` only when you explicitly want raw
query/term logging.
- Local A/B-style eval run:
```bash
DOCS_AGENT_EVAL_FLOWS=gateway,mercury bun run eval:agent:flows --
--strict
```
- Live target comparison:
```bash
DOCS_AGENT_EVAL_TARGETS=baseline=https://<prod>,mercury=https://<preview>
bun run eval:agent:flows -- --strict
```
## Tests
- `bunx eslint scripts/build-agent-index.ts agent/lib/docs.ts
agent/tools/search_docs.ts`
- `bun scripts/build-agent-index.ts` (wrote 133 pages + 1000 toolkits +
1139 BM25 rows)
- `DOCS_AGENT_SEARCH_PERF_LOG=1 EVE_FORCE_BUNDLE=1 bun -e "const
tool=(await import('./agent/tools/search_docs.ts?log=' +
Date.now())).default; await tool.execute({query:'create a session with
github tools'}); await tool.execute({query:'auth config connected
account'});"` (logs cold and warm timing JSON)
- `EVE_FORCE_BUNDLE=1 bun -e "const tool=(await
import('./agent/tools/search_docs.ts?bundle=' + Date.now())).default;
const started=performance.now(); const r=await
tool.execute({query:'create a session with github tools'});
console.log(r.retrieval, r.results[0].url, r.results[0].content.length,
Math.round(performance.now()-started)+'ms');"` (precomputed bundle path,
~12ms)
- `bun -e "const tool=(await import('./agent/tools/search_docs.ts?live='
+ Date.now())).default; const started=performance.now(); const r=await
tool.execute({query:'create a session with github tools'});
console.log(r.retrieval, r.results[0].url, r.results[0].content.length,
Math.round(performance.now()-started)+'ms');"` (live-content path,
~34ms)
- `EVE_FORCE_BUNDLE=1 bun -e "const tool=(await
import('./agent/tools/search_docs.ts')).default; await
tool.execute({query:'create a session with github tools'}); const
started=performance.now(); const r=await tool.execute({query:'auth
config connected account'}); console.log(r.results[0].url,
r.results[0].content.length,
Math.round(performance.now()-started)+'ms');"` (warm path ~2ms)
-
`PATH=/Users/cryogenicplanet/.vite-plus/js_runtime/node/24.15.0/bin:$PATH
./node_modules/.bin/eve info --json` (reports `status: ready`, `model:
inception/mercury-2`, `errors: 0`)
- `DOCS_AGENT_MODEL_FLOW=gateway
PATH=/Users/cryogenicplanet/.vite-plus/js_runtime/node/24.15.0/bin:$PATH
./node_modules/.bin/eve info --json` (reports `status: ready`, `model:
openai/gpt-5.4-mini`, `errors: 0`)
-
`PATH=/Users/cryogenicplanet/.vite-plus/js_runtime/node/24.15.0/bin:$PATH
./node_modules/.bin/eve eval --list`
-
`PATH=/Users/cryogenicplanet/.vite-plus/js_runtime/node/24.15.0/bin:$PATH
bun scripts/eval-agent-flows.ts --list`
- `bun test tests/static/` (16 passed)
- `bun run types:check` currently fails on existing docs type-generation
errors in `app/(home)/docs/changelog/[...slug]/page.tsx`,
`app/(home)/examples/[[...slug]]/page.tsx`,
`app/(home)/toolkits/[[...slug]]/page.tsx`,
`app/llms.mdx/[[...slug]]/route.ts`, `lib/search-index.ts`, and
`lib/source.ts`; no new eval or `docs/agent/agent.ts` errors were
reported.
## Not run
- Real live model evals, because this local environment does not have
`INCEPTION_API_KEY` or AI Gateway credentials.
## Latest update
- Added default eager docs retrieval in the Eve HTTP channel: the server
runs the same BM25 search on the user's message before the first model
step and injects the results as one-turn context.
- Kept `search_docs` and `read_doc` available so Mercury can still
search/read more when the eager context is weak, ambiguous, or missing.
- Added `DOCS_AGENT_EAGER_SEARCH=0` as an escape hatch and labeled perf
logs with `invocation: "eager_context" | "tool"`.
- Updated the loading copy from “Searching the docs…” to “Thinking with
the docs…” so UI latency is not attributed solely to the search call.
## Latest tests
- `bun run lint -- agent/channels/eve.ts agent/tools/search_docs.ts
agent/lib/docs-search.ts components/eve-chat.tsx
evals/docs-agent/grounded-answers.eval.ts`
-
`PATH=/Users/cryogenicplanet/.vite-plus/js_runtime/node/24.15.0/bin:$PATH
node_modules/eve/bin/eve.js info --json` (reports `status: ready`,
`errors: 0`)
- `DOCS_AGENT_SEARCH_PERF_LOG=1 EVE_FORCE_BUNDLE=1 bun -e "import {
searchDocs } from './agent/lib/docs-search'; const r = searchDocs('How
do I create a session in Composio? Keep it brief.', { invocation:
'eager_context' }); console.log(JSON.stringify({count:r.results.length,
top:r.results[0]?.url, content: !!r.results[0]?.content}, null, 2));"`
- `DOCS_AGENT_SEARCH_PERF_LOG=1 bun -e "import { searchDocs } from
'./agent/lib/docs-search'; searchDocs('How do I create a session in
Composio? Keep it brief.', { invocation: 'eager_context' });
searchDocs('How do I create a session in Composio? Keep it brief.', {
invocation: 'tool' });"`
- `bun run types:check` still fails only on the pre-existing docs
type-generation issues listed above.
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## What
Reworks the `/examples` index into a Modal-style **featured gallery**,
styled to the Composio brand (pulled from `~/composio/landing`): flat
editorial cards, sharp corners, mono uppercase category tags in accent
colors, the signature brand offset-shadow on hover, and real toolkit
logos on white chips.
| Light | Dark |
|---|---|
| Big `font-sans` hero, filter pills with live counts, responsive card
grid | Same, brand-consistent |
### Highlights
- **`<ExamplesGallery>`** — hero, category filter pills (Featured /
General agents / Background agents / Coding agents) with live counts,
responsive 1–3 col grid, staggered load-in.
- **Data-driven from frontmatter.** Card title/description come from
each page's own `title`/`description`. Presentation metadata lives in a
new optional `gallery` block in the frontmatter schema:
```yaml
gallery:
categories: [General agents, Background agents]
logos: [slack]
featured: true
order: 0
```
Examples can belong to **multiple category lanes** (the Pi bot is both
General + Background).
- The index route renders the gallery; nested example pages keep the
standard docs renderer.
### Drive-by fix
`PageActions` lifts a **full-width** row over the page title (`-mt-12`)
to place the "Copy page" button beside it. That invisible overlay sat on
top of the title and blocked selecting/copying it. Fixed by making the
overlay `pointer-events-none` and re-enabling them only on the button
wrapper. Affects every docs page.
## Testing
- `bun run types:check` passes.
- Verified in light + dark: titles/descriptions match page frontmatter,
multi-tag cards, filter counts, logo visibility (GitHub on white chips),
title now selectable, Copy button still clickable.
## Notes
- Category lanes are a fixed enum in two spots (`source.config.ts` enum
+ `CATEGORY_STYLES` color map in `examples-gallery.tsx`) — adding a new
lane is a two-place edit.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Integration branch for the next docs release: a **sessions-first
documentation rewrite** — new and rewritten guides, example pages,
interactive components, and docs tooling — plus the supporting SDK
changes that the new docs describe.
The bulk of this PR is docs (~24k lines across ~150 commits); the SDK
changes (~5k lines) back the new guides.
## Documentation (the bulk)
- **Sessions-first restructure** — reorganized navigation and section
structure (incl. the "Sandbox (prev workbench)" section), with
v3-reorganization redirects so old URLs keep resolving.
- **Rewritten core guides** — quickstart, configuring sessions, triggers
(creating + subscribing to events), proxy-execute, toolkits
enable/disable, and common FAQ, rewritten in the house voice.
- **New example pages** — local-sandbox PR reviewer, daily standup bot,
and slack bot, with runnable build-ups.
- **New interactive components & diagrams** — triggers flow animation,
manage-connections visual, connection-refresh visual, and the
terminal-kit components.
- **Docs tooling** — a docs-graph link-graph connectivity checker,
search reprioritization (deprioritize legacy pages), and SDK-reference
regeneration.
## Supporting SDK changes
**`@composio/core` → 0.13.0 (minor)**
- `composio.sessions.create()` as the first-class sessions API
(`composio.create()` kept as an alias).
- **MCP is opt-in:** default `create()` / `use()` return native-tool
sessions (`SessionWithoutMcp`); pass `{ mcp: true }` to surface
`session.mcp`. _Migration: read `session.mcp` only after creating with
`{ mcp: true }`._
- `session.sandbox` is the canonical resolved config;
`session.workbench` kept as a deprecated alias. `sandbox` is the
preferred session-config key (`workbench` still accepted).
- `connectedAccounts.updateAcl()` graduated from experimental (alias
kept).
- `triggers.parse()` (parse + optionally verify an incoming webhook) and
`triggers.setWebhookSubscription()`.
**`@composio/experimental` → minor** — local-workbench helpers moved
onto the `@composio/experimental/workbench` subpath (out of
`@composio/core/experimental`), keeping the ~14 KB embedded Python
helper out of core. Plus the experimental Pi provider.
**`@composio/slim` → minor.**
**Python → 0.17.0** — mirrors the TS surface: `composio.sessions` mount
(`tool_router` deprecated), `triggers.parse()` /
`set_webhook_subscription()`, the `sandbox` config key, and
`connected_accounts.update_acl()`.
## Review response (#3664)
Addressed the `@composio/core` review:
- **Security:** `triggers.parse()` no longer fails open — a
present-but-empty `verifySecret` (e.g. unset `COMPOSIO_WEBHOOK_SECRET`)
now throws instead of silently skipping verification; omitting it stays
an explicit opt-out (both SDKs).
- Removed snake_case leakage from `transformWebhookSubscription` (+ the
index signature that allowed it).
- **Removed** the TS-only `connectedAccounts.link()` toolkit
auto-resolve (shipped with cancellability / orphaned-auth-config bugs
and was effectively undocumented; to be reintroduced properly later).
- Unified Python error types on `ValidationError`; added `mcp=True`
Python tests; fixed runtime-portability + error-type test assertions.
- Polished deprecation messages; fixed the backwards `/experimental`
`@deprecated` note and the `SessionWithMcp` JSDoc.
## Testing
- **TS:** `@composio/core` + `@composio/experimental` typecheck pass;
vitest green for the touched suites.
- **Python:** `test_tool_router.py` + `test_triggers.py` pass (161
tests).
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Kshitij Jhunjhunwala <kj@composio.dev>
Co-authored-by: Malay Vasa <malayvasa@gmail.com>
Co-authored-by: Sarah Simionescu <sarah@composio.dev>
Co-authored-by: Kshitij Jhunjhunwala <113939507+KJ-11@users.noreply.github.com>