This PR:
- is refreshed directly onto the current next branch now that #3966 and
#3967 have merged; the PR contains only its intended type-safety work
- enforces no explicit any through the standard .oxlintrc.json, pnpm
lint, and plain oxlint --fix in lint-staged; docs remain covered by
their nested configuration
- replaces the loose JSONSchemaProperty in @composio/core with a
concrete recursive interface, removing explicit any reachable through
Tool.inputParameters and Tool.outputParameters
- includes a minor changeset documenting the type narrowing for
properties, default, and enum consumers
- adds a compile-only public-contract test for recursive schemas,
known-key validation, extension keywords, and Tool reachability
- removes explicit any from FileToolModifier, ts-builders, core and CLI
tests, provider tests, and json-schema-to-zod tests
- keeps TypeScript ESLint-parity rules enabled and closes the
tool-router example lint/typecheck gap
- makes no lockfile changes and no runtime behavior changes
## Context
Final PR from the original #3958 split. The migration foundations are
already on next via #3966 and #3967, so this branch no longer carries a
stacked base commit.
# Description
Customers evaluating Composio see references to **LLM tokens** and
assume Composio is handing them an agent/LLM that *replaces* their own —
i.e. that they'd be swapping their agent for ours. It isn't: Composio
discovers, authenticates, and executes tools; it never proxies the
customer's model or runs an agent on their behalf.
The one place Composio itself calls a model is **inside the sandbox**
(the optional `invoke_llm` helper + AI-assisted conveniences like error
correction). The sandbox is opt-in per session (`sandbox: { enable: true
}`), so this LLM usage is entirely optional and can be disabled.
This PR adds a short callout to the **Remote sandbox** docs page
(`docs/content/docs/sandbox/remote.mdx`) that says exactly that — placed
right where `invoke_llm` and the sandbox are introduced, with anchor
links to the `invoke_llm` helper, error correction, and session
configuration. It kills the "are they replacing my agent?" misconception
at its source.
The copy is deliberately accurate to today's state: it does **not**
claim we bill LLM tokens (sandbox billing is still upcoming and the
public pricing page only lists Tool Calls). It frames the point
conceptually — *your agent stays yours; the only Composio-side LLM usage
is optional and sandbox-scoped.*
**Follow-up surfaces (not in this PR — see below):** this same
clarification could be mirrored on the dashboard usage/billing UI and
the marketing pricing page when an "LLM tokens" line item actually
surfaces there. Those live outside this repo.
# How did I test this PR
- Docs-only change (single `.mdx` file); no code or dependency surface.
- Verified all anchor targets referenced in the new callout exist on the
same page / site:
- `#built-in-helpers` → `### Built-in helpers` (the `invoke_llm` row)
- `#error-correction` → `### Error correction`
- `/docs/configuring-sessions` (existing page; documents `sandbox: {
enable: true }`)
- Matches the existing `<Callout title="...">` component usage already
on the page (the "Renamed from workbench" callout), so it renders
consistently in Fumadocs.
- Confirmed against source that `invoke_llm` (docs `Built-in helpers`
table) is the Composio-side LLM entry point and that the sandbox is
opt-in via the `sandbox`/`workbench` session key.
# Security
- **Scope:** documentation-only change — one `.mdx` file, no
dependencies, lockfiles, or executable code added/changed.
- **Socket / Grype:** not applicable to this diff (no package manifests
or code paths introduced); no new fixable CRITICAL/HIGH/MEDIUM findings
possible from a Markdown copy addition.
Triggered by: palash@composio.dev | Source: slack
Session: https://zen.corp.composio.io/dashboard/#/chat/zen-f6a81a5a6764
---------
Co-authored-by: Zen Agent <zen@composio.dev>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
## Summary
Automated sync of backend data into the docs site. Triggered by:
`schedule`.
## What changed
- **Toolkit catalog** (`docs/public/data/toolkits.json`,
`toolkits-list.json`) — refreshed list of available toolkits, auth
schemes, and tools from the backend API
- **OpenAPI specs** (`docs/public/openapi.json`,
`docs/public/openapi-v3.json`, `docs/public/openapi-webhooks.json`) —
latest v3.1 and v3.0 API specifications plus the webhook-events spec,
fetched from production
- **API reference pages** (`docs/content/reference/api-reference/`,
`docs/content/reference/v3/api-reference/`) — regenerated index pages
for both API versions
- **Meta tools reference** (`docs/public/data/meta-tools.json`,
`docs/content/toolkits/meta-tools/*.mdx`) — updated meta tool schemas
and reference docs
Co-authored-by: Sushmithamallesh <19796925+Sushmithamallesh@users.noreply.github.com>
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).
Follow-up to https://github.com/ComposioHQ/composio/pull/3885, which is
now merged into `next`.
This PR:
- reports pending-login cache read failures as I/O errors instead of
masking them as decode failures (`composio login --poll`)
- restores pairwise polarity assertions for the `semverComparator`
Array.sort compatibility case
- consolidates the duplicated ephemeral HTTP server test helper in
`test/__utils__/http-server.ts`
- makes server-owned connected-account statuses forward-compatible while
preserving the credential-stripping schema allowlist
- redacts raw payload values from connected-account parse warnings and
adds regression coverage for unknown statuses and secret-bearing
malformed payloads
- documents why the client-singleton test re-derives the consumer cache
cwd hash
## Rebase notes
Rebased onto `origin/next` at `ef1ec9148`.
- Dropped the empty `GITHUB_*` compatibility commit; that contract is
already present on `next` through
https://github.com/ComposioHQ/composio/pull/3880.
- Adapted the connected-account decoder rename to the service extracted
upstream in `connected-account-selection.ts`.
## Context
Fix-forward PR for actionable Cursor Bugbot findings on the guardrails
stack (#3877–#3885). The stale decode-error string match and unused
release helper were already resolved upstream, and the `vi.stubEnv(...,
undefined)` concern is not actionable on Vitest 4.1.10.
Fixes#4030
## Problem
`checkForLatestVersionFromNPM` queried the right package but named the
wrong one in the notice it printed:
```ts
// ts/packages/core/src/utils/version.ts:29
const packageName = '@composio/core';
...
// ts/packages/core/src/utils/version.ts:52
`🚀 Upgrade available! Your composio-core version (${currentVersionFromPackageJson}) is behind. …`
```
`composio-core` is the v2 npm package. A v3 user saw a notice naming a
package they had not installed, and the obvious next step — `npm i
composio-core@latest` — installs the legacy package. That is a downgrade
path, not just a wording slip.
Leftover string from the v2 SDK: the surrounding code was migrated to
`@composio/core`, the message was not.
## Fix
One line — interpolate the constant already in scope, as the issue
suggested:
```diff
-`🚀 Upgrade available! Your composio-core version (${currentVersionFromPackageJson}) is behind. …`
+`🚀 Upgrade available! Your ${packageName} version (${currentVersionFromPackageJson}) is behind. …`
```
I used the constant rather than hardcoding `@composio/core` so the
notice and the registry URL now derive from a single source and cannot
drift apart again.
## Verification
Ran the issue's reproduction against the fix, with the registry response
stubbed and `CI`/`DEVELOPMENT` unset:
```text
🚀 Upgrade available! Your @composio/core version (0.14.1) is behind. Latest version: 0.99.0.
registry URL actually queried: https://registry.npmjs.org/@composio/core/latest
```
The name in the message and the package actually queried now match
exactly.
| Check | Result |
|---|---|
| `tsc --noEmit` | exit 0 |
| Full core suite | 1037 passed / 3 failed — identical to unmodified
`next` |
The 3 failures are pre-existing and environmental on the Windows machine
used here: two `EPERM: symlink` (needs Developer Mode) and one POSIX
path-separator assumption in `fileUtils.test.ts`. Confirmed by stashing
and re-running against `next`.
## Notes
- No test added. Interpolating the constant makes this class of drift
structurally impossible, which is a stronger guarantee than asserting
exact log text. There is also a practical cost: #4026's branch
introduces `ts/packages/core/test/utils/version.test.ts`, so adding that
same new file here would create an add/add conflict between two open
PRs. Happy to add coverage as a follow-up once that one lands.
- Related, deliberately left out of scope.
`ts/packages/cli/src/effects/find-composio-core-generated.ts:38` has the
same stale name, and arguably worse:
```ts
const fix = `Install \`composio-core\` with \`${installCmd} composio-core\`, …`;
```
- The code twelve lines below probes `import composio` — the v3 Python
package — so a user following that message runs `uv pip install
composio-core`, installs v2, and the check still fails. I left it alone
because `@composio/cli` is a separate package with its own release
process (it is excluded from changesets), and the two are independent
string literals with no shared function, so there is no single root to
fix. Worth its own issue.
- I checked the other `composio-core` references repo-wide: the
changelog entries and `docs/content/docs/migration-guide/new-sdk.mdx`
correctly cite v2 as history, and the remainder are CLI test-fixture
directory names. Nothing else needed changing.
Fixes#4032
## Problem
The JSDoc on `getToolkitVersionsFromEnv` documented a precedence order
the function does not implement:
```ts
// ts/packages/core/src/utils/sdk.ts:65-69
* 2. Environment variables (COMPOSIO_TOOLKIT_VERSION_<TOOLKIT_NAME>)
* 3. User-provided toolkit version mappings (defaultVersions object)
```
The implementation spreads user-provided values last, so they win:
```ts
const toolkitVersions = {
...toolkitVersionsFromEnv,
...userProvidedToolkitVersions,
};
```
Three independent sources already agreed the code is right and the JSDoc
was the outlier:
1. The inline comment two lines above the spread — "user provided values
act as overrides" (`sdk.ts:91`).
2. `test/core/versions.test.ts:150` (`'should prioritize user-provided
versions over environment variables'`) and `:395` (`'should demonstrate
priority order: user object > env vars > fallback'`).
3. The Python SDK's docstring for the equivalent `get_toolkit_versions`,
which had the order correct.
This misleads anyone debugging a version pin: someone whose
`COMPOSIO_TOOLKIT_VERSION_GITHUB` appears to be ignored reads this and
concludes the env-var handling is broken, when the real cause is their
own `toolkitVersions` object overriding it.
## Fix
Swapped the two lines. Comment-only — no runtime behaviour changes.
```diff
- * 2. Environment variables (COMPOSIO_TOOLKIT_VERSION_<TOOLKIT_NAME>)
- * 3. User-provided toolkit version mappings (defaultVersions object)
+ * 2. User-provided toolkit version mappings (defaultVersions object)
+ * 3. Environment variables (COMPOSIO_TOOLKIT_VERSION_<TOOLKIT_NAME>)
```
I kept this to a pure swap rather than also rewording. The Python
docstring is the parity target, and the two lists are now item-for-item
identical:
1. If `defaultVersions` is a string, use it as global version for all
toolkits
2. User-provided toolkit version mappings (`defaultVersions` object)
3. Environment variables (`COMPOSIO_TOOLKIT_VERSION_<TOOLKIT_NAME>`)
4. Fallback to `'latest'` if no versions are configured
Adding clarifying prose on the TypeScript side alone would have traded
one cross-SDK drift for another.
## Verification
Exercised all four documented items against real behaviour, not just the
one in the report:
```text
env : COMPOSIO_TOOLKIT_VERSION_GITHUB=from_env_20250101_00, _SLACK=slack_from_env
user : { github: "from_user_20260101_00" }
result: { github: 'from_user_20260101_00', slack: 'slack_from_env' }
github winner : from_user_20260101_00 <- user-provided (doc item 2)
slack winner : slack_from_env <- env var, untouched by user (doc item 3)
string form : 20260101_00 <- doc item 1
empty form : latest <- doc item 4
```
The slack case is the one worth noting: items 2 and 3 are not a strict
either/or fallback — the two maps merge per toolkit, and env vars still
apply for toolkits the user's object does not mention. The numbered list
describes that correctly now, since what it orders is precedence.
| Check | Result |
|---|---|
| `tsc --noEmit` | exit 0 |
| `test/core/versions.test.ts` | 32 passed |
I ran the targeted suite rather than the full one: the change is a
comment and cannot affect anything outside this file, and those 32 tests
are exactly the ones asserting this precedence.
## Notes
- No changeset — comments only, nothing in the published output changes.
- No test added: the existing tests at `versions.test.ts:150` and `:395`
already lock this behaviour in. They are what proved the code was
correct and the doc was wrong, so the doc is now covered by them too.
This PR:
- fixes#4024
- supersedes #4025 with target-filesystem detection instead of
unconditional case folding
- uses `is-fs-case-sensitive` on the nearest existing directory so mixed
mounts and case-sensitive filesystem configurations are handled
correctly
- preserves exact matching on case-sensitive filesystems and falls back
to conservative case-insensitive matching when detection fails
- keeps Node-only detection behind `#platform` and mirrors its runtime
dependency in `@composio/slim`, preserving the workerd-safe bundle and
Slim import
- adds focused Node, workerd, and matcher regressions plus an
`@composio/core` patch changeset
- verifies 1,044 core tests, five CLI upload tests, the Slim
build/import smoke, typecheck, build, ATTW, publint, lint, formatting,
frozen install, and changeset validation
This PR:
- supersedes https://github.com/ComposioHQ/composio/pull/4010 and
credits @MGPOCKY for identifying the stale Cloudflare E2E Node override
- lets Cloudflare E2E resolve the exact Node.js version from mise.lock
through the shared setup action
- retains the release job's explicit Node.js 24.17.0 publishing pin and
corrects its outdated explanation
- verifies the release workflow guard, workflow YAML parsing,
formatting, and whitespace checks
Co-authored-by: MGPOCKY <kkm1447@naver.com>
The **I still need help** section of Composio Connect points users at
`tech@composio.dev`.
It's the only place in the docs that does. Every other reference uses
`support@composio.dev`:
- `docs/content/reference/errors.mdx`
- `docs/content/reference/v3/errors.mdx`
- `docs/content/changelog/12-30-25.mdx`
- `docs/content/changelog/01-29-26-sdk-major-update.mdx`
- `docs/content/changelog/03-25-26-mcp-endpoint-removed.mdx`
Composio Connect is the page consumer users land on when wiring up an
MCP client, so this was the most visible instance of the wrong address.
One line changed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com>
Adds the missing auth-config step to the existing Custom MCP page
(extending-sessions/custom-mcp.mdx): create the config with
`is_enabled_for_tool_router: true`, PATCH guidance for existing configs,
and updates the session + known-gaps sections from "don't rely on
auto-match" to "auto-match works when the flag is set".
Why: session account-matching only considers flagged auth configs, and
after the revert of platform#11223 there is no server-side default for
custom toolkits. A config created without the flag makes every session
execution fail with `NoActiveConnection`. The docs are what stands
between a pilot partner and that dead end.
Draft while the feature is experimental/LD-gated.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Session auto-match only considers auth configs with this flag, and the
custom flow has no default (platform#11223 was reverted), so configs
created without it fail session execution with NoActiveConnection. Adds
the auth-config creation step with the flag, a PATCH note for existing
configs, and updates the session and known-gaps guidance from "don't
rely on auto-match" to "auto-match works when the flag is set".
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The is_enabled_for_tool_router step is load-bearing: after the revert of
platform#11223 there is no default, and configs created without the flag
make session execution fail with NoActiveConnection.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Documents OAuth connection security (same-browser binding + callback
identity verification) as a section in the **connected-accounts API
reference**, next to the `complete_auth` endpoint it describes, rather
than a standalone `/docs` page.
Written in the connected-accounts overview's own house style (prose
sections, backticks, one warning callout, no em-dashes), carrying the
code-verified facts.
## What's here
- New **OAuth connection security** section in
`api-overviews/connected-accounts.mdx`, mirrored into both generated
`index.mdx` files (v3.1 + v3).
- Changelog entry, links pointed at
`/reference/api-reference/connected-accounts#...`.
- Agent concept map repointed, and a stale claim fixed: callback
identity verification is opt-in per project and covers every connection
once set, not custom-auth-config-only.
## Notes
- No standalone docs page or nav entry (an earlier revision of this
branch had one; removed).
- The `index.mdx` files are normally emitted by `generate:api-index`;
its deps don't resolve in my worktree, so I mirrored the section
manually. It matches what the generator would produce from the updated
overview, but a local regen on a full checkout is worth doing before
merge.
- The dashboard "Learn more" link (#1187) is repointed to this section.
The earlier standalone-page version lives in #3987 (left open and
untouched for comparison).
When a verifier URL is set, the OAuth handoff carries only session_uri and the
developer's endpoint owns the final redirect, so a callback_url passed at
connection creation is not used. One clause in the reference; regenerated both
index pages.
Same-browser binding is not enabled, so remove it from the connected-accounts
reference and concept map. Keep the OAuth session fixation definition as the
rationale for callback identity verification, which is now the single control
the section documents. Regenerated both index pages; repointed the concept map
to #callback-identity-verification.
Drop same-browser binding and the session-fixation description from the
changelog. It now announces just the opt-in callback identity verification
feature, framed as a capability, with no attack detail.
## What
Content fixes to the tool-execution docs, driven by a 97-agent docs eval
(findings: ctx.composio.io/soumya/docs-agent-eval/findings-97-run.md).
72/97 agents following the executing-tools page hit
`ToolVersionRequiredError` because the samples either omit versions
entirely or pin a GitHub-only mapping that doesn't transfer to any other
toolkit.
## Changes
**`docs/content/docs/tools-direct/executing-tools.mdx`**
1. Add an explicit callout in Direct Tool Execution: a toolkit version
is **required**, the error you get without one, the three ways to set
it, and a link to the version-lookup section. (Previously the page only
implied this via one sample's constructor; the "required" rule lived on
a separate page.)
2. Replace the hardcoded `{"github": "20251027_00"}` pin with `"latest"`
plus a comment showing how to find versions
(`composio.toolkits.get(slug).meta.available_versions`) — the old sample
only worked for GitHub and taught a stale pin.
3. Add `toolkit_versions` / `toolkitVersions` to every file-handling
sample (upload, download, Gmail attachment, manual staging, upload-hook)
— all previously threw `ToolVersionRequiredError` when copied.
4. Remove `dangerouslySkipVersionCheck: true` from the upload-hook
sample — it was working around the missing version; samples shouldn't
model the dangerous flag.
**`docs/lib/llm-guardrails/direct-execution.ts`**
5. The LLM-facing guardrails block appended to direct-execution pages
showed a version-less `tools.execute()` sample and a "signature rule"
omitting `version` — the exact pattern that produced the eval's top
failure. Samples and rules now state the requirement.
**`docs/content/docs/quickstart.mdx`**
6. State the Python 3.10+ requirement at the install step, naming the
cryptic `typing.TypeAlias` failure older versions produce (matches
`python/pyproject.toml` `requires-python = ">=3.10,<4"`).
## Verification
All sample signatures checked against the installed SDK (composio 0.18.0
/ composio_client 1.42.0): per-call `version=`, constructor
`toolkit_versions=`, lookup via `toolkits.get(slug).meta.version` /
`.meta.available_versions`. Eval evidence: 72/97 independent agent runs
reproduced the error; per-run logs available.
## Raised for docs-team decision (deliberately NOT changed here)
- **The session guardrails block**
(`docs/lib/llm-guardrails/session.ts`, "CRITICAL INSTRUCTIONS FOR AI
MODELS", appended to most pages): capable eval agents flagged it as
prompt injection (verbatim: "a prompt injection I had to identify and
ignore") and its framing contradicts the sessions-vs-direct-execution
page. Deliberate design, so untouched — recommend reconciling (both
paths legitimate, state when each applies) and softening ALWAYS/NEVER
framing.
- **`legacy: true` on executing-tools + toolkit-versioning**: these are
the canonical link targets for direct execution, but the legacy flag
stamps the LLM view with "may describe outdated APIs" and suppresses
guardrails — eroding agent trust in the current canonical page. Either
promote the pages or point canonical links elsewhere.
- **REST vs SDK naming**: REST query param is `toolkit_versions`, SDK
per-call param is `version` — a recurring source of agent confusion
(eval Finding 4); worth aligning or calling out in the reference.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
[PRDE-1153](https://linear.app/composio/issue/PRDE-1153) adds a small
acquisition hint when the bare CLI is running inside Claude Code or
Codex and the Composio plugin is not installed in that host:
```text
Tip: running under Claude Code without the Composio plugin — 'composio setup' installs it.
```
The hint is written only to stderr, including in non-TTY shells, because
agent tool calls commonly capture stderr. It never changes stdout or
command results.
## When the hint appears
All of the following must be true:
- The CLI detects Claude Code via `CLAUDECODE`, or Codex via
`CODEX_THREAD_ID` / `CODEX_SANDBOX`.
- The host's plugin state confidently shows that `composio@composio` is
absent.
- A hint has not been shown for that host within the last 24 hours.
- The current command is not `composio setup`, including when root flags
precede the command.
- The invocation is not a child of `composio run`.
Unreadable or unrecognized plugin state suppresses the hint rather than
risking a false positive.
## Host state and throttling
- Claude Code presence is read from
`~/.claude/plugins/installed_plugins.json`.
- Codex presence is read from `~/.codex/config.toml`.
- `CLAUDE_CONFIG_DIR` and `CODEX_HOME` overrides are honored; blank
overrides fall back to the standard paths.
- Per-host throttle stamps live under `<COMPOSIO_CACHE_DIR or
~/.composio>/plugin-hints/`.
The throttle is best-effort rather than a correctness boundary. Two
processes racing exactly as a stale stamp is replaced may both print the
same tip; the only consequence is a duplicate advisory line.
## Implementation notes
- Detection and presence checks use local environment variables and
small local files only—there is no network request or background worker.
- Shared agent-host names, labels, and the plugin ID are centralized in
`agent-host.ts` and reused by the existing setup flow.
- This PR covers plugin acquisition only. Plugin freshness and CLI
update messaging remain separate concerns.
## Verification
- `plugin-hint.test.ts`: 15 passing tests covering host detection,
plugin presence, suppression rules, per-host throttling, custom/blank
host paths, root flags, concurrency, and non-TTY stderr.
- CLI source typecheck: passed.
- CLI test typecheck: passed.
- Changed-file oxlint and `git diff --check`: passed.
**Stacked on #3927** (A1 — direct-to-PostHog + install→Apollo identity).
Targets that branch; will auto-retarget to `next` when #3927 merges.
Review only this diff.
## What
Makes every CLI event self-describe its funnel stage, so the adoption
funnel can be queried without string-matching event names — which is how
it silently broke in the first place.
- **`journey_stage`** on every event: `install | setup | login | connect
| execute | other`. Declared as an exported typed const plus a single
exhaustive map, `as const satisfies Record<CliAnalyticsEventName,
CliJourneyStage>` — so **the compiler refuses to build if a future event
has no stage**. No per-event literals; stamped in one shared builder.
- **`cli_channel`** alongside `cli_version`, reusing the existing
`inferSkillReleaseChannel()` / `CLI_RELEASE_CHANNELS`. Makes "did this
fix reach stable users?" answerable — the question that went unanswered
in the 0.2.30 assetless-release incident.
- **Installer origin fix:** `install.sh` ran `"$exe" install` *without*
`COMPOSIO_CLI_INVOCATION_ORIGIN=installer` (the `setup` call on line 410
had it), so a genuine install was indistinguishable from a user running
`composio install` by hand. Now tagged, with a regression test that
reads `install.sh` and asserts it.
## Stage mapping (reviewed against 30d volume)
`install` = `CLI_INSTALL_*` · `setup` = `CLI_SETUP_*` + `CLI_PLUGIN_*` ·
`login` = `CLI_LOGIN_*` · `connect` = `CLI_LINK_*` · `execute` =
`CLI_EXECUTE_*` + `CLI_TOOL_INVOCATION_*` · `other` = `CLI_COMMAND_*`,
`CLI_SEARCH_*`, `CLI_PROXY_*`, `CLI_RUN_*`, `CLI_LOGOUT_*`
Judgment calls, made with data rather than by default:
- **`proxy` → `other`.** 2,060 of 2,140 proxy users (96%) already
execute; only 80 are proxy-only. Reclassifying would move the activated
cohort ~1%, so `execute` stays precisely "tool execution".
- **`run` → `other`.** `run` children emit their own execute events
carrying `parent_run_id`; staging the parent as `execute` would
double-count.
- **`search` → `other`.** Not a required funnel stage. Candidate for a
"discovery" step later if the flow page wants one.
## Note for whoever builds the flow page
`CLI_TOOL_INVOCATION_*` and `CLI_EXECUTE_FAILED` can both fire for a
single failure, so the `execute` stage **double-counts at the event
level**. Count **distinct users per stage**, not events.
## Known coverage limit
npm and Homebrew installs don't run `install.sh`, so they emit no
`CLI_INSTALL_*`. The `install` stage means "installed via install.sh",
not all installs.
## Verification
`pnpm typecheck` clean · `validate:boundaries` OK (46 disables, **zero
added**) · CLI suite **107 files / 971 passed** (+15 tests) ·
`dispatch.ts` identity/transport untouched.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## What
Sends CLI telemetry **directly to PostHog** (project 196278) instead of
through Apollo/Segment, and stitches the anonymous install identity to
the Apollo user at login. This unlocks the previously-dark top of the
CLI adoption funnel (install → setup → login → connect → execute).
### Why
Two live funnel breaks in PostHog today:
1. **Install/setup/plugin events were dark.** Pre-login, `dispatch.ts`
had no API base URL (→ endpoint null → dropped), and Apollo's ingest
401s anonymous requests. So `CLI_INSTALL_*`/`CLI_SETUP_*` never arrived.
2. **Identity split.** CLI/server events landed on *email*-keyed PostHog
persons (via Segment); dashboard onboarding on *UUID*-keyed persons —
the two never joined.
The CLI already knows the canonical Apollo UUID (`org_member.id` from
session info), so it can self-stitch with no platform/dashboard change.
## How
- **Direct transport.** New PostHog capture path (`captureToPostHog`)
reusing the existing detached best-effort worker. No dependency on the
API base URL, so **pre-login events send**.
- **Identity.** Pre-login `distinct_id = install_id`; at login
`linkApolloIdentityForAnalytics(org_member.id)` persists the UUID to
`~/.composio/analytics.json` and fires one `$create_alias` (`install_id
→ org_member.id`); post-login events key on the persisted
`apollo_user_id`. Because onboarding is already UUID-keyed, the CLI
funnel now joins web onboarding.
- **Public key, baked at build.** The write-only `phc_` project key is
injected via `bun build --define` from the `COMPOSIO_POSTHOG_KEY` env
(CI Actions **variable**), never committed to source. `--define` (not a
second `--env`) is deliberate — Bun honors only the last `--env`, which
would clobber the existing `DEBUG_OVERRIDE_*` bake. For this OSS repo
this keeps the key out of git history and means **forks / local builds
compile a no-op binary** (only official releases carry the key).
- **Direct-only:** the Apollo `/cli/analytics` send is dropped for CLI
events; the CLI attaches its own `org_id` (project_id is per-session; a
follow-up).
## Guards
No-op (no send, no worker spawn, no identity-file write) when telemetry
is disabled
(`COMPOSIO_CLI_TELEMETRY_DISABLED`/`TELEMETRY_DISABLED`/`COMPOSIO_DISABLE_TELEMETRY`/`CI`/`NODE_ENV=test`)
or when no project key is configured. Alias fires once per install
(idempotent). No user API key or tool-arg values in event properties.
## Verification
- `pnpm typecheck`, `validate:boundaries`, full CLI vitest (**954 passed
/ 1 skipped**) — green.
- Independent code review pass; findings addressed (spawn-gated-on-key,
disabled=no-file, idempotent alias).
- **Live cold-install trace:** built the real compiled binary with the
key baked, ran it from a throwaway `$HOME` → fresh `install_id` → 2
pre-login events delivered to `us.i.posthog.com` with **HTTP 200** →
confirmed queryable in PostHog 196278 within ~10s, keyed by
`install_id`.
## Notes
- CLI is Changesets-ignored; human note added to `CHANGELOG.md`
directly.
- Requires the `COMPOSIO_POSTHOG_KEY` Actions variable to be set for
official release builds (done).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
Automated docs update triggered by SDK source changes on `next`.
- Claude reviewed the SDK diff and updated guides, FAQs, or examples
that reference changed APIs or features.
- The docs `@composio/*` dependencies were realigned to their latest
published releases so Twoslash snippets and example apps validate
against versions users can actually install.
## Review checklist
- [ ] Changes accurately reflect the new SDK behavior
- [ ] No unrelated docs were modified
- [ ] Code examples are correct and complete
- [ ] If a documented feature is not published yet, the Twoslash build
will fail — wait for the release instead of working around it
Generated by Claude Code via GitHub Actions.
Co-authored-by: jkomyno <12381818+jkomyno@users.noreply.github.com>
This PR:
- fixes https://github.com/ComposioHQ/composio/issues/3932
- replaces the private CLI package semver with the non-release
`0.0.0-development` sentinel
- injects the exact GitHub release tag version into every standalone
binary and verifies it during the build
- makes every push to `next` a beta, with explicit semver selection for
intentional minor or major betas and stable releases only through beta
promotion
- resolves skill installation, setup repair, companion repair, and
upgrades from packaged `release-tag.txt` metadata
- adds regression coverage for release selection, compiled version
identity, and packaged-tag asset lookup; all 1,009 CLI tests and the
monorepo typecheck pass
- updates the direct CLI changelog and release guidance; no Changeset is
added because CLI packages are excluded from Changesets
Ran generate:api-index instead of hand-editing. The one shared overview feeds
both version pages, so the OAuth connection security section now renders on the
v3.1 and v3 connected-accounts reference (chosen over a hand-edit the generator
would undo). Generator output is byte-identical to the prior hand-mirror on v3.1;
no other tags changed.
- complete_auth is a v3.1-only endpoint (no v3 route), so drop the OAuth
connection security section from the v3 connected-accounts index; keep it on v3.1.
- status_reason on mismatch is the enum VALUE 'Callback identity verification
failed', not the key IDENTITY_VERIFICATION_FAILED. Fix both files.
- Changelog no longer claims Composio universally 'stops' the attack. It ships
two controls: same-browser binding (automatic on managed) and opt-in callback
identity verification.
Changelog: run through good-docs-writing — remove every em-dash, drop the salesy
'most reliable way', plainer confident voice.
connected-accounts overview + both index files: correct the completion outcomes.
Per completeFromSession, only an identity mismatch fails the connection (FAILED +
status_reason IDENTITY_VERIFICATION_FAILED); any other error leaves it pending so
the flow can be restarted; the session_uri is consumed either way. The old text
read as if the connection always moved to FAILED.
Drop the standalone /docs/oauth-connection-security page and its nav entry. The
content now lives as a section in the connected-accounts API overview
(api-overviews/connected-accounts.mdx), next to the complete_auth endpoint it
documents, in that overview's house style.
- Add the section (same-browser binding + callback identity verification) to the
overview and mirror it into both generated index.mdx files (v3.1 + v3). The
index generator's deps don't resolve in this worktree, so the mirror is manual;
it matches what generate:api-index would emit from the updated overview.
- Repoint the changelog and the agent concept map at
/reference/api-reference/connected-accounts#...
- Fix a stale concept-map claim: identity verification is opt-in per project and
covers every connection once set, not custom-auth-config-only.
This PR:
- fixes
https://github.com/ComposioHQ/composio/actions/runs/30535159056/job/90850055191
by keeping checksum generation independent of unbuilt CLI runtime
packages
- extracts the shared Effect teardown into a dependency-light module
while preserving existing script imports
- adds an executable release regression that generates a checksum
manifest from a clean fixture
- verifies the fix with `pnpm test:release-workflow`, `pnpm
build:packages`, CLI typecheck, the full CLI test suite, and `pnpm
validate:changesets`
Skill-guided rewrite of the OAuth connection security page: direct second-person
voice, no em-dashes, concept-first sentences, no salesy comparatives.
Also corrects four accuracy issues found while verifying against the Apollo code
(these exist in the sibling PR too):
- the ten-minute figure is the session_uri TTL, not a connection-expiry;
- verification covers API + Connect Link redirects, not marketplace-install
acknowledgements (which return before the verifier fork);
- save-time validation is https + SSRF (private/reserved), not a reachability test;
- the rejection message has no trailing period.
## What
Restores the two docs-prose skills that were dropped from the skill
tree:
- `good-docs-writing` — the house documentation style guide (Voice,
Structure, Terminology, Punctuation, Code examples, Formatting), for
drafting or revising docs prose.
- `good-docs-audit` — the review process that audits a doc/README/prose
block against that guide and reports `file:line` findings with concrete
rewrites. Report-only by default.
## Why
Both existed at `d17a268d` under `.claude/skills/` and were deleted in
#3666 (`chore(agents): normalize repo guidance skills`), which renamed
the rest of the tree into the current taxonomy but did not carry these
two over. Nothing replaced them: there is no docs-voice guidance in the
repo today, and `docs-decisions` covers docs-site mechanics (Fumadocs,
changelogs, ADRs), not prose style.
## Shape of the restore
Rule content is restored unchanged from `d17a268d`. Only the file layout
differs, because the old flat single-file form no longer passes
`validate:agent-skills` (SKILL.md is now capped at 80 lines and a linked
`references/` directory is required):
```
.agents/skills/good-docs-writing/SKILL.md # routing + the rules that matter most
.agents/skills/good-docs-writing/references/style-guide.md
.agents/skills/good-docs-audit/SKILL.md # routing + non-negotiables
.agents/skills/good-docs-audit/references/audit-process.md
```
They live under `.agents/skills` (canonical); `.claude/skills` is a
symlink, so there is no second copy.
Wiring, all three places the taxonomy is asserted:
- `ts/scripts/validate-agent-skills.mjs` — added to the `expectedSkills`
gate
- `ts/scripts/test-skill-routing.mjs` — one routing probe each (the
validator fails on any skill without a probe)
- `AGENTS.md` — added to the Skill Routing list
## Test results
- `node ts/scripts/test-skill-routing.mjs` — passes, 18 probes over 18
skills. Both new probes resolve to a unique top match.
- `node ts/scripts/validate-agent-skills.mjs` — zero findings against
tracked files.
- `pnpm lint-staged` — no staged file matches a configured task
(patterns cover `ts/packages/**` and `python/**`).
- Markdown formatted with the repo Prettier config.
Two notes on how those were run. `pnpm validate:*` could not be used
locally: pnpm's pre-run dependency check tries to purge and reinstall
the workspace and aborts without a TTY, so the scripts were invoked
directly with `node` (same entrypoints the pnpm scripts use).
Separately, `validate-agent-skills` reports stale-guidance hits under
`docs/.eve/dev-runtime/snapshots/**` on my machine; those are untracked,
gitignored local eve snapshots, unrelated to this change, and won't
exist in CI. The commit used `--no-verify` because the pre-commit hook
is just the `pnpm lint-staged` wrapper that hits the same pnpm abort;
lint-staged was run manually instead.
No changeset: guidance and tooling only, no published package touched.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to next, this PR will
be updated.
# Releases
## @composio/core@0.14.1
### Patch Changes
- 577a3d4: Replace the backtracking leading/trailing-slash-trim regexes
in the Cloudflare Workers/Edge platform path helpers with index-walk
loops, closing a polynomial-time regular expression denial-of-service
(CodeQL js/polynomial-redos) on long runs of slash characters. Output is
unchanged for every input.
- 503b50a: Refresh runtime dependencies across the TypeScript SDK
packages.
- 2f63fe5: Guard Tool Router session URL uploads against SSRF,
revalidate redirect targets, and enforce a streamed 100 MiB response
limit across TypeScript URL upload paths.
## @composio/experimental@0.2.1
### Patch Changes
- 503b50a: Refresh runtime dependencies across the TypeScript SDK
packages.
## @composio/mastra@0.10.3
### Patch Changes
- 503b50a: Refresh runtime dependencies across the TypeScript SDK
packages.
## @composio/slim@0.14.1
### Patch Changes
- 503b50a: Refresh runtime dependencies across the TypeScript SDK
packages.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This PR:
- prepares Python SDK core and provider packages for `0.18.1`, including
runtime and lockfile metadata
- adds the canonical combined changelog for Python `0.18.1` and the
TypeScript releases tracked by
https://github.com/ComposioHQ/composio/pull/3906
- documents `@composio/core` `0.14.1` so the generated release PR passes
the release-workflow guard
- refreshes `mise.lock` so the TypeScript audit workflow reaches the
dependency audit
- keeps the pending TypeScript Changesets untouched; the generated
release PR remains responsible for npm versioning and publication
- validates Python with Ruff/mypy, 944 tests, all 13 package builds, and
`twine check`
- validates TypeScript/docs with the full 26-task `pnpm test`,
high-severity production audit, 100 docs static tests, link checks, docs
typecheck, and production build
## Summary
Auto-generated Python SDK reference docs from `python/composio/`.
Regenerates pages at `docs/content/reference/sdk-reference/python/` to
reflect changes in the Python package's public API (new methods, updated
signatures, changed types).
Co-authored-by: jkomyno <12381818+jkomyno@users.noreply.github.com>
97-agent docs eval: 72/97 agents hit ToolVersionRequiredError copying
version-less tools.execute() samples. Adds an explicit requirement
callout, uses 'latest' with a lookup pointer instead of a hardcoded
GitHub-only pin, adds versions to all file-handling samples, fixes the
LLM guardrails block's version-less signature, and states the Python
3.10+ requirement in the quickstart.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
## Summary
- add an experimental guide for registering customer-hosted MCP servers
- document supported authentication, the registration and sync flow,
toolkit behavior, and customer-facing workarounds for known gaps
- add the guide to the Extending sessions navigation and cross-link it
from the sessions-over-MCP guide
## Why
Custom MCP toolkits now have a working platform lifecycle, but customers
need one place that clearly distinguishes remote MCP servers from
in-process custom tools. The guide also makes the current pilot
limitations explicit so customers know which API version, sync flow,
account selection, and hosting model to use.
## Validation
- `cd docs && bun run lint:links`
- `cd docs && bun run types:check`
- `git diff --check`
Docs-only change, so no changeset is required.