## Summary
Follow-up to #3358. The `.transform()` added on the `connectedAccounts`
Zod schema made the inferred TypeScript type resolve to the
**post-transform output** (`Record<string, string[]>`), so TS users
still hit `error TS2322: Type 'string' is not assignable to type
'string[]'` even though the runtime accepted strings. The runtime fix
landed; the public TS surface didn't follow.
This PR moves the coercion out of the schema and into
`ToolRouter.create`, mirroring the Python implementation. The public
type is now `Record<string, string | string[]>` and runtime behavior is
unchanged.
## Why CI didn't catch this in #3358
The PR's own test file (`toolRouter.test.ts`) already assigns a `string`
to `ToolRouterCreateSessionConfig`, but `ts/packages/core/tsconfig.json`
has `"include": ["src/**/*.ts"]` — `test/` is not typechecked. So `tsc
--noEmit clean` was technically true while masking the issue. Verified
empirically by dropping a typecheck file into `src/` on `next`:
```
src/__type_check.ts(8,7): error TS2322: Type 'string' is not assignable to type 'string[]'.
```
After this PR, the same file compiles cleanly.
## Changes
- **`ts/packages/core/src/types/toolRouter.types.ts`**: drop
`.transform()` from the `connectedAccounts` schema; `z.infer` now
exposes `Record<string, string | string[]>`.
- **`ts/packages/core/src/models/ToolRouter.ts`**: coerce `string →
[string]` inside `create` before sending to the backend (which expects
arrays). Preserves the original `connected_accounts: undefined` behavior
when the field is omitted (the parent schema's `.partial()` strips the
`default({})`).
- **`ts/packages/core/src/types/toolRouter.types.ts`**: fix stale
`@param {Record<string, string>}` JSDoc on the same field.
- **`.changeset/v31-connected-accounts-array.md`**: drop the inaccurate
*"Bumps `@composio/client` to `0.1.0-alpha.70`"* line — that bump landed
in a separate commit on `next` (`7c1443838`), not in #3358's diff (`git
diff 2bbd791de^1 2bbd791de` shows zero `pnpm-lock.yaml`/`package.json`
changes).
- **`.changeset/fix-connected-accounts-string-type.md`**: new `patch`
changeset for `@composio/core`.
## Test plan
- [x] `pnpm exec tsc --noEmit -p tsconfig.json` clean on
`@composio/core`
- [x] `pnpm exec vitest run` — 883/883 tests pass (incl. 110 in
`toolRouter.test.ts`)
- [x] `pnpm prettier --check` clean on touched files
- [x] Spot-checked: assigning `{ connectedAccounts: { gmail: 'ca_xxx' }
}` to `ToolRouterCreateSessionConfig` now typechecks; assigning the
array form still typechecks.
The Zod `.transform()` added in #3358 made the inferred type of
`ToolRouterCreateSessionConfig['connectedAccounts']` resolve to
`Record<string, string[]>` (the post-transform output), so TypeScript
users still hit `Type 'string' is not assignable to type 'string[]'`
even though the runtime accepted strings. The runtime fix landed; the
public TS surface didn't follow.
Drop the schema transform and coerce inside `ToolRouter.create` instead,
mirroring the Python implementation. The public type is now
`Record<string, string | string[]>` and behavior is unchanged.
While here:
- fix the JSDoc on `connectedAccounts` (was `Record<string, string>`)
- drop the inaccurate `@composio/client 0.1.0-alpha.70` bump line from
the v31-connected-accounts-array changeset (this PR didn't perform
that bump; it landed in a separate commit on `next`)
Non-breaking: existing callers passing a single string per toolkit
continue to work. The string is silently coerced to a single-element
array to match the v3.1 wire format.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
Composio tools whose JSON Schema uses internal `$ref` pointers
(`#/$defs/...` or the legacy `#/definitions/...`) used to lose all type
information when wrapped by `MastraProvider.wrapTool`. The schema would
silently round-trip `raw → applyCompatLayer → convertSchemaToZod (drops
$ref → permissive anyOf) → zodToJsonSchema (no recovery)`. Customers
reported the user-visible surface as *"schema validation error: can't
resolve reference"* — AJV (bundled inside `@mastra/schema-compat`)
refusing to compile the schema downstream when validating tool input.
This PR pre-processes the schema with a new `dereferenceJsonSchema`
utility from `@composio/core` *before* it reaches
`@mastra/schema-compat`, preserving the type information from
`$defs`/`definitions` and avoiding the AJV failure entirely.
Closes
[PLEN-2244](https://linear.app/composio/issue/PLEN-2244/mastra-provider-schema-validation-error-cant-resolve-reference).
## What changed
- **`@composio/core`** — new `dereferenceJsonSchema(schema)` helper (and
`JsonSchemaRefResolutionError`):
- walks the schema reflectively (no JSON-Schema-keyword allow-list, so
future applicators are covered automatically),
- inlines internal `$ref` pointers transitively, with a 100-hop depth
cap,
- shallow-merges sibling keywords next to `$ref` per Draft 2020-12
semantics (siblings win on collision — preserves caller's `description`
/ `default` / `title`),
- breaks recursive cycles with `{ type: 'object', additionalProperties:
true }` (matches upstream guidance in
[mastra-ai/mastra#15341](https://github.com/mastra-ai/mastra/issues/15341)),
- strips `$defs` / `definitions` from the returned root once everything
reachable is inlined,
- leaves external (`http://`/`https://`) `$ref` pointers untouched so
callers can still forward them,
- throws `JsonSchemaRefResolutionError` on malformed pointers, missing
targets, and over-cap chains.
- **`@composio/mastra`** — `wrapTool` now runs `dereferenceJsonSchema`
over both `inputParameters` and `outputParameters` before calling
`applyCompatLayer`.
- **`@mastra/schema-compat`** floor bumped to `^1.2.9` so consumers
automatically pick up upstream [PR
#15400](https://github.com/mastra-ai/mastra/pull/15400)'s
recursive-`$ref` handling and [PR
#14530](https://github.com/mastra-ai/mastra/pull/14530)'s Draft-2020-12
AJV switch.
- Changeset: `.changeset/fix-mastra-ref-dereference.md` (patch bump for
`@composio/core` and `@composio/mastra`).
## Test plan
Red → green TDD across two commits — the `test:` commit reproduces
PLEN-2244 against the real `@mastra/schema-compat` (no `vi.mock`), the
`fix:` commit makes the regression tests pass.
- [x] `ts/packages/core/test/utils/jsonSchema.test.ts` — 14 unit tests
for `dereferenceJsonSchema` covering: basic resolution, chained refs,
container coverage (items / oneOf / anyOf / allOf / not /
additionalProperties / patternProperties / prefixItems), legacy
`definitions` (Draft 7), `$defs`/`definitions` mixed transitively,
sibling-keyword merge per Draft 2020-12, cycle break,
`$defs`/`definitions` strip, missing-target error, depth-cap error,
external `$ref` preserved, no input mutation, JSON Pointer escape
decoding (`~0`/`~1`), array-index pointers.
- [x] `ts/packages/providers/mastra/test/mastra-ref.test.ts` — un-mocked
integration tests against real `@mastra/schema-compat`: wrapping does
not throw, type info from `$defs` survives the round-trip (the `id`
field stays `type: 'string'` instead of degrading to permissive
`anyOf`), same for Draft-7 `definitions` on output schema, no remaining
`$ref` in the produced schemas.
- [x] `pnpm --filter @composio/core test` — 852/852 green.
- [x] `pnpm --filter @composio/mastra test` — 43/43 green (39 legacy + 4
new).
- [x] `pnpm --filter @composio/core --filter @composio/mastra typecheck`
— clean.
- [x] Existing `mastra.test.ts` (which mocks `@mastra/schema-compat`) is
**untouched** and still green.
- [x] Secret-hygiene scan: `git diff next..HEAD | grep -E
'sk-[A-Za-z0-9_-]{20,}|OPENAI_API_KEY=[A-Za-z]'` returns empty.
## Why it's a Mastra-only fix
The Mastra path is unique in routing JSON Schema through
`@mastra/schema-compat`, which embeds AJV. Sibling providers (`openai`,
`anthropic`, `vercel`, `langchain`, `google`, `llamaindex`) forward
Composio's JSON Schema through `@composio/json-schema-to-zod`, which
silently no-ops on unknown nodes. They are not affected today; expanding
pre-processing across providers is a separate PR if it ever becomes
needed.
## Caveats
- The cycle-break sentinel weakens type information for genuinely
recursive tool schemas. This is the same trade-off Mastra itself made in
[#15341](https://github.com/mastra-ai/mastra/issues/15341); without it
the agent crashes entirely.
- External `$ref` (`http://`/`https://`) is intentionally left
untouched. If a real customer schema ever needs them resolved, that's an
incremental follow-up that calls into
`@apidevtools/json-schema-ref-parser` only when needed.
- The cycle-break currently uses a single sentinel for any cycle; if
review prefers the higher-fidelity "keep first expansion, only break on
the recursion edge" pattern (mentioned in the research as a refinement),
that's a small follow-up.
## Summary
End-to-end work to help SDK and direct API users move off the legacy
`POST /api/v3/connected_accounts` path for **Composio-managed OAuth**
ahead of the [2026-04-24 changelog
announcement](/docs/changelog/2026/04/24) — cutover dates **2026-05-08**
(new orgs) and **2026-07-03** (all orgs). Pairs with the backend
deprecation signals in
[ComposioHQ/hermes#9622](https://github.com/ComposioHQ/hermes/pull/9622).
Custom auth configs (your own OAuth app) and non-OAuth schemes (API key,
bearer, basic) are unaffected throughout.
## SDK changes
### TypeScript (`@composio/core`)
- **New error class**
`ComposioLegacyConnectedAccountsEndpointRetiredError` in
`errors/ConnectedAccountsErrors.ts` — extends `ComposioError`, status
400, with `possibleFixes` pre-populated to point at `link()` and the
migration guide.
- **`initiate()` wraps the create call** in try/catch and re-throws the
new typed error when the response message indicates the retiring path.
The match is conservative — substring on stable backend message text,
with everything else flowing through unchanged.
- **One-time-per-process deprecation warning** via `logger.warn` when
the response indicates `OAUTH1` / `OAUTH2` / `DCR_OAUTH`. Wording is
conditional ("If this auth config is Composio-managed...") so
custom-OAuth users can ignore it without ambiguity.
- **JSDoc** on `initiate()` flags the deprecation explicitly with both
cutover dates and a link to the migration guide.
### Python (`composio` core)
- Mirror exception class
`ComposioLegacyConnectedAccountsEndpointRetiredError` in
`composio/exceptions.py`.
- `initiate()` catches `BadRequestError` from `composio_client`,
inspects the message text, and re-raises as the typed exception
(preserves `__cause__`).
- One-time-per-process `warnings.warn(..., DeprecationWarning,
stacklevel=2)` on the redirectable-OAuth response path.
- Docstring carries a `.. deprecated::` block with the dates.
## Doc changes
| File | Change |
|---|---|
| `docs/content/docs/tools-direct/authenticating-tools.mdx` | Add a
`<Callout type="warn">` to the `OAuth Connections` subsection of `Direct
SDK Setup`. The Hosted Authentication section already shows `link()`
first; this surfaces the retirement on the `initiate()` subsection where
readers most need it. |
| `docs/content/docs/auth-configuration/connected-accounts.mdx` |
Promote the `Multiple accounts` callout from `info` to `warn`, pin the
cutover dates, and route readers to the migration guide. |
| `docs/content/docs/auth-configuration/custom-auth-configs.mdx` | Add
an `info` callout clarifying that the `initiate()` example shown is
*intentionally* fine here (custom auth configs are exempt). Avoids
copy-paste confusion. |
| `docs/content/reference/errors.mdx` | New section `## Specific error
codes` → `### Error 600` with anchor `#error-600`. The `suggested_fix`
URL emitted by the backend in the 400 response
(`/reference/errors#error-600`) now resolves to real content instead of
404'ing. |
| `docs/content/docs/auth-configuration/migrating-initiate-to-link.mdx`
| **New page.** Dedicated migration guide. Side-by-side before/after for
both languages, the `allow_multiple` replacement pattern, an
`is_composio_managed` routing recipe for mixed integrations, notes on
detecting the deprecation via SDK warning vs RFC 8594 response headers,
and a transition-friendly try/except example. |
| `docs/content/docs/auth-configuration/meta.json` | Wire the new
migration guide into the Authentication sidebar. |
## Why this scope
In the audit before this PR the SDK was the biggest gap —
`composio.connectedAccounts.initiate()` (TS) and
`composio.connected_accounts.initiate()` (Python) both call the legacy
endpoint, so every doc that teaches `initiate()` for OAuth was teaching
a path that breaks at cutover. The SDK changes give existing users a
typed deprecation path (warning before cutover, typed error after)
without forcing a behavior change on the custom-auth-config and
non-OAuth users who are unaffected. The doc changes target the two
highest-traffic teaching pages for OAuth flows, plug the broken
`error-600` URL the backend already references, and add a focused
migration guide that consolidates everything callers need.
## How did I test this PR
- **TS**: `pnpm tsc --noEmit` in `ts/packages/core` — error count
unchanged vs `next` (baseline 53 → 53; all pre-existing, none touch the
modified files). The new error class follows the existing
`ComposioFailedToCreateConnectedAccountLink` template; the typed-error
wrap reuses the `BadRequestError` import and pattern from
`errors/ComposioError.ts:13`.
- **Python**: confirmed `BadRequestError` is exported from
`composio_client` and `connection_data.auth_scheme` is a valid attribute
on the response model
(`composio_client.types.connected_account_create_response.ConnectionDataUnionMember0`
declares `auth_scheme: Literal["OAUTH1"] =
FieldInfo(alias="authScheme")` — same shape across all union members).
- **Docs**: all internal links use the relative-path convention
(`/docs/...`, `/reference/...`) and follow the format used by existing
changelog cross-links (e.g., `/docs/changelog/2026/04/24`). The new
`#error-600` anchor matches the URL the backend's `suggested_fix`
already emits.
- **Manual trace**: walked the four decision branches against the
modified `initiate()` code paths in both languages — custom auth configs
and non-OAuth schemes never trigger either the warning or the
typed-error path; managed OAuth triggers the warning on success and the
typed error on the eventual 400.
Pre-cutover the SDK warning is the loudest signal; post-cutover the
typed error is the cleanest catch point. Both are scoped strictly to the
affected combination.
## Summary
- Add experimental CLI local tools behind `local_tools` (beta-on,
stable-off unless `composio config experimental local_tools on`).
- Add reusable `@composio/cli-local-tools` package: declarations,
metadata, readiness, command/MCP/native/FFI runtimes, bundled-binary
resolution, and Tool Router search/execute/schema integration.
- Add first-class local toolkits for:
- `BEEPER_IMESSAGE` backed by `imessage-cli` from the ComposioHQ
`platform-imessage` fork.
- `CHROME_DEVTOOLS` backed by the official `chrome-devtools-mcp@0.24.0`
npm/npx package.
- `PEEKABOO` backed by upstream Peekaboo CLI.
- Remove generated native executables from git: Beeper and Peekaboo
binaries are now ignored, pinned via git submodules, and generated
during CLI binary release jobs.
- Update CLI binary workflow so Linux artifacts skip native sidecars,
while macOS artifacts run on macOS runners and build only the matching
`darwin-x64` or `darwin-arm64` Beeper/Peekaboo sidecars before
packaging.
## Native binary policy
- No generated `imessage-cli` or `peekaboo` binary blobs are committed
in this PR history.
- Beeper source is pinned as
`ts/packages/cli-local-tools/vendor/platform-imessage` at
`364445a1b3089ad9fe293d5951efe160c5677c42` from
`https://github.com/ComposioHQ/platform-imessage`.
- Peekaboo source is pinned as
`ts/packages/cli-local-tools/vendor/peekaboo` at
`31e66e8d02656141d18f60bf3b46b24c2b9bc785` from
`https://github.com/steipete/Peekaboo`.
- Build commands:
- `pnpm --filter @composio/cli-local-tools build:local-tool-binaries --
--target darwin-arm64`
- `pnpm --filter @composio/cli-local-tools build:local-tool-binaries --
--target darwin-x64`
- Chrome DevTools is an npm/npx integration and is pinned as a dev
dependency (`chrome-devtools-mcp@0.24.0`) instead of using native
sidecars.
## Validation
- `pnpm --filter @composio/cli-local-tools build:local-tool-binaries --
--target darwin-arm64`
- `pnpm --filter @composio/cli-local-tools build:peekaboo -- --target
darwin-x64`
- `pnpm --filter @composio/cli-local-tools build:beeper-imessage --
--target darwin-x64`
- `pnpm --filter @composio/cli-local-tools typecheck:tsc`
- `pnpm --filter @composio/cli-local-tools test`
- `COMPOSIO_REAL_LOCAL_TOOLS_TESTS=1 pnpm --filter
@composio/cli-local-tools test -- src/toolkits/beeper-imessage.test.ts
src/toolkits/peekaboo.test.ts`
- `pnpm --filter @composio/cli typecheck:tsc`
- `pnpm --filter @composio/cli build`
- `COMPOSIO_CACHE_DIR=<tmp-config-with-local_tools-enabled> bun
ts/packages/cli/dist/bin.mjs local-tools doctor --json`
- `pnpm turbo build`
- Verified rewritten branch has no >1MB objects relative to
`origin/next` and no native executable paths in the PR diff.
## Notes / risks
- Beeper iMessage and Peekaboo are macOS-only and depend on local
permissions.
- Peekaboo requires macOS 15+; GUI tools require Screen Recording,
Accessibility, and sometimes Automation.
- Beeper send/reaction behavior can still depend on upstream Messages
automation reliability.
- Chrome DevTools can inspect/modify browser contents; avoid sensitive
browser sessions.
Required by the TS release flow — without a changeset entry, merging
to next won't open or update the Release: update version PR and the
new exported error class won't reach npm.
`minor` because the new exported error class is additive but
user-facing. Python is tag-driven and doesn't need a changeset.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Composio tools whose JSON Schema uses internal `$ref` pointers (`#/$defs/...`
or the legacy `#/definitions/...`) used to lose all type information when
wrapped by `MastraProvider.wrapTool`. The schema went through:
raw JSON Schema (with $ref) → applyCompatLayer
→ convertSchemaToZod (silently drops $ref, becomes a permissive anyOf)
→ zodToJsonSchema (no way to recover the lost types)
Customers reported this surface as "schema validation error: can't resolve
reference" — AJV (bundled inside @mastra/schema-compat) refusing to compile
the schema downstream when validating tool input.
Fix: pre-process the schema with a new `dereferenceJsonSchema` helper before
handing it to `applyCompatLayer`. The helper:
- walks the schema reflectively (no JSON-Schema-keyword allow-list, so future
applicators are covered automatically),
- inlines internal `$ref` pointers transitively, with a 100-hop depth cap,
- shallow-merges sibling keywords next to `$ref` per Draft 2020-12 semantics
(siblings win on collision — preserves caller's `description`/`default`),
- breaks cycles with `{ type: 'object', additionalProperties: true }`,
matching upstream guidance in mastra-ai/mastra#15341,
- strips `$defs`/`definitions` from the returned root once everything
reachable is inlined,
- leaves external (`http://`/`https://`) `$ref` pointers untouched,
- throws `JsonSchemaRefResolutionError` on malformed pointers, missing
targets, or chains over the cap.
Bumps the `@mastra/schema-compat` dependency floor to `^1.2.9` so users also
pick up upstream PR #15400's recursive-`$ref` handling.
The new red regression tests (committed in 5300bf8ba) now pass.
Bring `link()` to parity with `initiate()` so the duplicate-connection
guard moves with customers as Composio-managed redirectable-OAuth
callers migrate from `connected_accounts/create` to
`connected_accounts/link` (SEC-339).
- TS: add `allowMultiple?: boolean` to `CreateConnectedAccountLinkOptions`.
`link()` now pre-flights `connectedAccounts.list({ statuses: ['ACTIVE'] })`
and throws `ComposioMultipleConnectedAccountsError` when an active
connection exists and `allowMultiple` is not `true`.
- Python: add `allow_multiple: bool = False` to `connected_accounts.link()`
with the same guard and the same `ComposioMultipleConnectedAccountsError`.
- Tests: existing `link()` tests now mock `list` returning empty (default
no-existing-connection path); new tests cover the raise path and the
opt-in `allowMultiple=True` skip path. Also add multi_account parity
tests on the Python tool_router create() to mirror the TS suite.
Behavior change is intentional and patched separately with
`.changeset/sdk-link-allow-multiple.md`. The user-facing changelog entry
is split into a separate docs PR alongside the sandbox-size docs.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Expose `workbench.sandboxSize` (TypeScript) / `workbench.sandbox_size`
(Python) on `ToolRouter.create()` so callers can pick the workbench
sandbox compute tier (`standard`, `medium`, `large`, `xlarge`).
Optional; the server defaults to `standard` (1 vCPU / 1 GB) when
omitted, so existing callers keep current behavior.
- Bump stainless clients to pick up the field on the wire:
- `@composio/client` 0.1.0-alpha.66 -> 0.1.0-alpha.67
- `composio-client` 1.33.0 -> 1.34.0
- TS: extend `ToolRouterCreateSessionConfigSchema.workbench` with
`sandboxSize` and forward it as snake_case `sandbox_size`. Export
`SandboxSize` type and `SandboxSizeSchema` zod enum.
- Python: extend `ToolRouterWorkbenchConfig` TypedDict with
`sandbox_size` and forward it on the create payload. Export
`SandboxSize` literal alias.
- Changeset: `@composio/core` patch.
- Tests: cover the snake_case forwarding and zod enum rejection.
Docs (Configuring Sessions / Workbench / changelog) are split into a
separate PR so they can land alongside the SDK release.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
## Summary
`pnpm changeset version` consumed `.changeset/fluffy-kids-lose.md` (the
auto file upload/download opt-in changeset for `@composio/core`). The
mechanical run bumped every dependent provider package to **`1.0.0`**,
which would surface as a spurious major bump on packages whose public
API didn't change. This PR corrects the provider bumps to **`0.8.0`** so
the version line stays aligned with `@composio/core` across the release
train.
> **Note:** Earlier revisions of this PR targeted `0.7.0`. After release
planning, the train was bumped to `0.8.0` (see commit `efc63ca6f`) —
`0.7.0` was published briefly and has since been **deprecated on npm**
in favor of `0.8.0`.
## Changes
| Package | Before | After |
| ------- | ------ | ----- |
| `@composio/core` | 0.6.11 | **0.8.0** (minor — see PR #3260) |
| `@composio/anthropic` | 0.6.11 | **0.8.0** |
| `@composio/claude-agent-sdk` | 0.6.11 | **0.8.0** |
| `@composio/cloudflare` | 0.6.11 | **0.8.0** |
| `@composio/google` | 0.6.11 | **0.8.0** |
| `@composio/langchain` | 0.6.11 | **0.8.0** |
| `@composio/llamaindex` | 0.6.11 | **0.8.0** |
| `@composio/mastra` | 0.6.11 | **0.8.0** |
| `@composio/openai` | 0.6.11 | **0.8.0** |
| `@composio/openai-agents` | 0.6.11 | **0.8.0** |
| `@composio/vercel` | 0.6.11 | **0.8.0** |
| `@composio/cli` | 0.2.25 | 0.2.26 (unchanged from `changeset version`;
CLI keeps its own version line) |
`.changeset/fluffy-kids-lose.md` is consumed.
## What changed in each provider's CHANGELOG.md
- `## 1.0.0` → `## 0.8.0`
- `### Patch Changes` → `### Minor Changes` with a one-line entry:
`Bumped to align with @composio/core@0.8.0 for the file-upload allowlist
release train. No public-API change in this package.`
- The duplicate `- Updated dependencies` line was deduped to a single `-
Updated dependencies [ebc9778]\n - @composio/core@0.8.0`.
## What changed in `@composio/core`'s CHANGELOG.md
- Removed the stray `- [BREAKING] Disable auto file upload / download`
bullet (an artifact of an earlier changeset that doesn't apply on
`next`); the long-form entry from `fluffy-kids-lose.md` already covers
the breaking nature in detail.
- The closing paragraph now says providers are bumped to `0.8.0`
alongside core (matching reality) instead of "automatic patch bumps via
`updateInternalDependencies: \"patch\"`".
## Notes
- `pnpm-lock.yaml` doesn't need updating — internal deps use
`workspace:*`.
- `pnpm typecheck` on `@composio/core` is clean (now reports
`@composio/core@0.8.0`).
- `pnpm build:packages` failed locally on a tsdown config-loader bug
under Node 24; the repo is pinned to Node 20.19.0 in `.nvmrc`, and the
build works fine there. Verified by stashing this PR's diff and
reproducing the same failure on clean `next` — pre-existing
local-environment issue, unrelated to the version bumps.
## Published & deprecated
Published to npm:
-
`@composio/{core,anthropic,claude-agent-sdk,cloudflare,google,langchain,llamaindex,mastra,openai,openai-agents,vercel}@0.8.0`
Deprecated on npm (all `@0.7.0`) with the message: *"0.7.0 has been
superseded by 0.8.0. Please upgrade: npm install <package>@0.8.0"*.
## Test plan
- [x] CI passes (build, typecheck, tests on Node 20.19.0).
- [x] After merge, `changesets-release/next` PR is generated cleanly
with no leftover changesets.
- [x] Verify the release publishes `@composio/*@0.8.0` (not `1.0.0`).
- [x] `@composio/*@0.7.0` deprecated on npm, redirecting users to
`0.8.0`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
Automatic tool file upload/download for `file_uploadable` fields is
**off by default** in TypeScript and Python. Callers must explicitly opt
in, and uploads from local paths are constrained by a fail-closed
allowlist.
## Changes
- **Removed (breaking):** `autoUploadDownloadFiles` (TS) /
`auto_upload_download_files` (Python) — the legacy default-on flag is
gone, not just deprecated.
- **New opt-in:** `dangerouslyAllowAutoUploadDownloadFiles` (TS) /
`dangerously_allow_auto_upload_download_files` (Python). When `true`,
`tools.get(...)` collapses `file_uploadable` schemas to `{ type:
'string', format: 'path' }` and the SDK stages local paths/URLs at
execute time.
- **New:** `fileUploadDirs?: string[] | false` — fail-closed allowlist
for local upload paths. `undefined` → `[<home>/.composio/temp]`; `false`
→ reject all local paths (URLs / `File` objects unaffected); explicit
`string[]` replaces the default. Components are matched on a path
boundary after `realpath`.
- **New:** `fileDownloadDir?: string` — directory where
`file_downloadable` results are staged.
- **New:** `beforeFileUpload` hook receives `source: 'path' | 'url' |
'file'` (TS) / `'path' | 'url'` (Python) so it can branch on input type.
- **New (TS):** when auto-upload is **off** and an LLM-driven
`tools.execute` is called against a tool with `file_uploadable` inputs,
the SDK emits a one-shot warning per tool slug pointing at
`composio.files.upload()` for manual staging.
## Migration
To restore previous behavior:
```ts
new Composio({
apiKey: process.env.COMPOSIO_API_KEY!,
dangerouslyAllowAutoUploadDownloadFiles: true,
// Optional: tighten the allowlist beyond the default ~/.composio/temp
fileUploadDirs: ['/srv/uploads'],
});
```
```python
Composio(api_key="...", dangerously_allow_auto_upload_download_files=True)
```
If you previously passed the legacy flag, remove it. There is no
transitional warning — TS and Python both reject the unknown property at
the type/keyword-arg level.
## Versioning
| Package | Bump |
| ------- | ---- |
| `@composio/core` | minor |
| `composio` (Python) | minor |
| Other `@composio/*` packages | patch (via changesets
`updateInternalDependencies: "patch"`) |
See
`docs/content/changelog/04-24-26-legacy-auto-upload-config-removal.mdx`
for the full migration writeup.
## Summary
Security-hardening for automatic file upload in `@composio/core` (patch
release per changeset).
### Changes
- **Default denylist** for local paths before auto-upload /
`files.upload`: blocks common credential directories (e.g. `.ssh`,
`.aws`) and credential-like filenames (e.g. `.env`, default SSH private
keys). Resolves symlinks when the path exists.
- **Config:** `sensitiveFileUploadProtection`,
`fileUploadPathDenySegments` on `Composio`.
- **`beforeFileUpload`** hook (e.g. with `composio.tools.get` /
`tools.execute`): rewrite path, return `false` to abort, or throw.
- **Errors:** `ComposioSensitiveFilePathBlockedError`,
`ComposioFileUploadAbortedError`; file modifier errors exported from
`@composio/core` errors entry.
- **Changeset:** patch bump for `@composio/core`.
### Notes
- URLs and `File` blobs are not subject to the path denylist
(unchanged).
- Opt out of path checks only if required:
`sensitiveFileUploadProtection: false`.
### Tests
- `pnpm test` in `ts/packages/core` (799 tests) passed locally before
commit.
Made with [Cursor](https://cursor.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/cli@0.2.23
### Patch Changes
- 4df06d2: feat: add `simple`, `default`, and `verbose` help verbosity
modes to root and subcommand help (`--help simple|verbose`); compact
simple mode and richer verbose mode with additional commands (#3205)
feat: add `composio connections list` command that groups connected
accounts by toolkit and displays aliases (#3206)
feat: migrate API key storage from plaintext
`~/.composio/user_data.json` to OS keyring (macOS Keychain / Linux
Secret Service); env var > keyring > legacy plaintext precedence with
one-shot migration and `dangerouslySaveApiKeyInUserConfig` opt-out for
headless environments (#3202)
feat: turn `composio dev` into a real developer-mode toggle backed by
CLI user config; gate the `init`, `tools execute`, `triggers listen`,
`logs`, `toolkits`, `auth-configs`, `connected-accounts`, `triggers`,
and `projects` subcommand tree behind the toggle, and remove deprecated
destructive `delete`/`info` commands now covered by the dev-mode gate
(#3181)
feat: enable `multi_account` experimental feature by default for stable
CLI builds and centralize default experimental-feature behavior so
runtime config and skill reference schema stay in sync (#3163)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Changes
Patch release bundling four CLI features merged since 0.2.22:
### Features
- **`composio connections list`** (#3206) — new command grouping
connected accounts by toolkit with aliases
- **OS keyring API key storage** (#3202) — migrate plaintext
`~/.composio/user_data.json` API keys to macOS Keychain / Linux Secret
Service; one-shot migration on first run;
`dangerouslySaveApiKeyInUserConfig` opt-out for headless/CI environments
- **`composio dev` mode toggle** (#3181) — `--mode on|off` switch backed
by CLI user config; gates `init`, `tools execute`, `triggers listen`,
`logs`, `toolkits`, `auth-configs`, `connected-accounts`, `triggers`,
`projects` subcommands; removes deprecated destructive `delete`/`info`
commands now covered by the gate
- **Multi-account by default on stable** (#3163) — `multi_account`
experimental feature enabled by default for stable CLI builds;
centralized default-feature wiring so runtime config and skill reference
schema stay in sync
## Changeset
- Bump: `@composio/cli` patch (0.2.22 → 0.2.23)
- File: `.changeset/cli-0-2-23-patch.md`
## Testing
⏳ Full CLI test pipeline in progress...
_Test results will be updated once `/full-cli-test` completes._
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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/cli@0.2.20
### Patch Changes
- 4e36db8: feat: add `composio listen` command for real-time trigger
event monitoring
feat: add top-level `composio triggers` command (list, info subcommands)
fix: pre-existing CI failures across CLI and e2e suites
docs: document `--file` support for CLI skill uploads
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Changes since 0.2.18
### Features
- Add `composio listen` command for real-time trigger event monitoring
(#3115)
- Add top-level `composio triggers` command with `list` and `info`
subcommands (#3115)
### Fixes
- Fix pre-existing CI failures across CLI and e2e suites (#3102)
### Docs
- Document `--file` support for CLI skill uploads (#3114)
## Changeset
- Bump: `@composio/cli` patch
- File: `.changeset/cli-0219-release.md`
## Testing
⏳ Full CLI test pipeline in progress...
_Test results will be updated once `/full-cli-test` completes._
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 (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/cli@0.2.18
### Patch Changes
- f49e0af: feat: add `--beta` flag to `composio upgrade` for prerelease
channel support
feat: preload custom auth connections into tool router sessions for
seamless custom-auth toolkit execution
improve: beta-channel CLI release promotion flow in CI workflow
improve: expanded test coverage for upgrade binary and custom auth
session creation
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Changes
### Features
- Add `--beta` flag to `composio upgrade` for prerelease channel support
- Preload custom auth connections into CLI tool router sessions for
seamless custom-auth toolkit execution
### Improvements
- Beta-channel CLI release promotion flow in CI workflow (beta tag
validation, promotion to stable)
- Expanded test coverage for upgrade binary and custom auth session
creation
- Updated release documentation and CLI README for new beta/stable
release model
## Changeset
- Bump: `@composio/cli` patch
- File: `.changeset/cli-beta-flow-and-custom-auth.md`
## Testing
### Phase 1: CI Types/Lint
- Status: ✅ Passed (verified on merged PRs #3077 and #3089)
### Phase 2: Local Binary Test
- `composio version`: ✅ `0.2.17`
- `composio whoami`: ✅ `rahul@composio.dev`
- `composio --help`: ✅ Full output rendered
- Slack integration test: ✅ Passed (`execute()` +
`experimental_subAgent()` with structured output)
### Phase 3: Bundled Binary Test
- Status: ⏳ Deferred — will run automatically when the "Release: update
version" PR is opened
- The new beta release flow (shipped in #3089) triggers binary builds on
the release PR, not the changeset PR
### Slack Integration Test Details
- `SLACK_FIND_CHANNELS`: ✅ Found `#buzz-skill-based-cli-testing`
- `SLACK_SEND_MESSAGE`: ✅ Posted test start message
- `SLACK_FETCH_CONVERSATION_HISTORY`: ✅ Retrieved 20 messages
- `experimental_subAgent()` with `z.object` schema: ✅ Returned
structured summary
- `SLACK_SEND_MESSAGE`: ✅ Posted summary back to channel
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 (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/cli@0.2.17
### Patch Changes
- e3322e6: fix: hydrate file_uploadable tool inputs and add temp-file
handling for execute payloads
fix: surface in-band tool errors as warnings without overriding
successful execution results
fix: resolve 8 TypeScript strict-mode errors blocking CLI build in
run-helpers-runtime
refactor: extract run helper runtime (~650 lines) from run.cmd.ts into
run-helpers-runtime.ts
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.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/cli@0.2.16
### Patch Changes
- b763753: fix: bundle bun support files into CLI binary so standalone
builds work without external bun dependencies
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary
- bundle the shipped `composio run` companion services with direct
`Bun.build(..., target: "bun")` output instead of reusing the shared
`dist` graph
- rebuild the Claude ACP support files as Bun-bundled runtime assets and
invalidate the cached adapter layout so stale raw files are not reused
- add runtime validation for shipped support files, wire the MCP helper
through the workspace `@composio/json-schema-to-zod` package, and cover
the static-import expectation in tests
## Why
Standalone binaries were still relying on external runtime dependencies
from companion support files. On a clean machine this surfaced as
failures like `Cannot find package 'decompress'` from the generated
companion modules. The fix is to make every shipped support file
self-contained for Bun and package exactly that tree into the binary
archives.
## Validation
- `pnpm run typecheck`
- `pnpm exec vitest run
test/src/services/run-subagent-output-mcp.test.ts
test/src/services/run-subagent-acp.test.ts`
- `pnpm run build:binary:all`
- `pnpm run build:binary:package`
- unpacked `dist/binaries/composio-darwin-aarch64.zip` and verified
`experimental_subAgent(..., { target: "codex", schema: ... })`
- unpacked `dist/binaries/composio-darwin-aarch64.zip` and verified
`experimental_subAgent(..., { target: "claude", schema: ... })`
---------
Co-authored-by: Claude Opus 4.6 (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/cli@0.2.15
### Patch Changes
- 51c4e09: fix: bundle MCP server into subagent helper via static
imports so it works with standalone CLI binaries without repo-local
node_modules; fix codact failures not being reported by dispatching them
through a dedicated background worker and wiring up the `tools execute`
command to capture wrong-slug and wrong-param failures
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.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/cli@0.2.14
### Patch Changes
- 5a3c661: Change `composio install` to skip shell completions by
default and require `--completions` to install them explicitly. Also
keep the skipped-completions logging consistent.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary
- Make `composio install --no-completions` consistently log that
completions were skipped.
- Keep the existing completion-install and unavailable-shell messages
unchanged.
- Add a changeset for the `@composio/cli` patch release.
## Testing
- Not run (not requested).
- Confirmed the install command now logs `Completions: skipped
(--no-completions)` when `--no-completions` is set, even if completion
setup would otherwise be available.
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/cli@0.2.13
### Patch Changes
- cb02575: fix(cli): harden run subagent structured output and logfile
path propagation
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>