Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
145 commits
Select commit Hold shift + click to select a range
84ad401
Fix onboarding UI jank: no Loading flash, no canonicalize double-hop …
RhysSullivan Jun 13, 2026
b998f8d
Org slugs: mint at insert, drop lazy minting, make the column NOT NUL…
RhysSullivan Jun 13, 2026
64b3544
Self-host MCP OAuth: connect-card path, approval screen, real-agent e…
RhysSullivan Jun 13, 2026
7237bf2
Self-host: share one libSQL connection with Better Auth (fix WAL data…
RhysSullivan Jun 13, 2026
cd2a38b
Version Packages (#1009)
RhysSullivan Jun 13, 2026
ce39ffc
Remove all git submodules; develop the forks as standalone repos (#1010)
RhysSullivan Jun 13, 2026
be5e1bb
Document Pi bridge (#1001)
gvkhosla Jun 13, 2026
013fa38
Connect card: pin the MCP install URL to the URL's org (fix wrong-org…
RhysSullivan Jun 14, 2026
7fb9220
host-mcp: shared browser-approval primitives + cloud browser e2e (#1014)
RhysSullivan Jun 14, 2026
534b32c
self-host: browser approval of gated MCP actions (#1015)
RhysSullivan Jun 14, 2026
73f2c2b
cloudflare self-host: browser approval + a Cloudflare e2e target (#1016)
RhysSullivan Jun 14, 2026
19c2657
harden local auth (#1012)
RhysSullivan Jun 14, 2026
554a714
Add busy_timeout to the local libSQL connection (#1003)
RhysSullivan Jun 14, 2026
2c1be33
Add executor service to supervise the local gateway daemon (#1004)
RhysSullivan Jun 14, 2026
9564174
Desktop: attach to the supervised daemon instead of a private sidecar…
RhysSullivan Jun 14, 2026
211fa52
e2e: cross-OS supervised-daemon reboot survival (real VMs, recorded) …
RhysSullivan Jun 14, 2026
994e5b9
e2e: packaged-desktop target — the real bundle attaches to the superv…
RhysSullivan Jun 14, 2026
1e1567e
desktop: import the local bearer helpers from a lightweight subpath (…
RhysSullivan Jun 14, 2026
498e4a6
Fix copy buttons on non-secure origins; move API keys into the sideba…
RhysSullivan Jun 14, 2026
c8faad7
Self-host + cross-host: consistent public-origin resolution (platform…
RhysSullivan Jun 15, 2026
42c0da4
Give the Connect-an-agent card header room at the top (#1024)
RhysSullivan Jun 15, 2026
130d0e9
Make tool failures visible telemetry: span outcome attributes, derive…
RhysSullivan Jun 15, 2026
aa148a2
Fix supervised/local regressions (#1020)
RhysSullivan Jun 15, 2026
2b797e2
Curate integration & connection metadata; update OpenAPI specs in pla…
RhysSullivan Jun 15, 2026
1ca0215
Version Packages (#1025)
RhysSullivan Jun 15, 2026
6295e73
Run release smoke test against `web --foreground`
RhysSullivan Jun 15, 2026
04350de
Format wrapped web --foreground args in release smoke test
RhysSullivan Jun 15, 2026
8244fee
Make MCP pause/resume idempotent with collision-proof ids and honest …
RhysSullivan Jun 15, 2026
dcb121d
Split mixed pause-resume changeset so the release plan assembles
RhysSullivan Jun 15, 2026
49e1675
Fix desktop health flaps (#1028)
RhysSullivan Jun 15, 2026
e4db068
Proxy /docs to Mintlify at the worker edge (#1035)
RhysSullivan Jun 15, 2026
93eedce
Retry transient Durable Object relocation on MCP session init (#1034)
RhysSullivan Jun 15, 2026
b039157
Fix billing org selector (#1042)
RhysSullivan Jun 17, 2026
4091f8b
[codex] Fix plugin API org scoping (#1043)
RhysSullivan Jun 17, 2026
2de1804
[codex] Fix Windows service install discovery (#1046)
RhysSullivan Jun 18, 2026
2f06132
Fix main CI release checks (#1047)
RhysSullivan Jun 18, 2026
d24cc09
Version Packages (#1027)
RhysSullivan Jun 18, 2026
e530484
Remove ignored changeset blocking release
RhysSullivan Jun 18, 2026
175c586
Integrate macOS traffic lights into sidebar (#1049)
maria-rcks Jun 18, 2026
af96bae
better svgs for openai, spotify & sentry (#1052)
maria-rcks Jun 19, 2026
cfda0ac
[codex] Fix desktop black screen fallback (#1051)
RhysSullivan Jun 19, 2026
2dac2df
Version Packages (#1053)
RhysSullivan Jun 19, 2026
4313193
Add Mintlify docs site under apps/docs; remove stale root docs scaffold
RhysSullivan Jun 19, 2026
90fb30a
docs: drop apps/docs package.json so it is not a bun workspace member…
RhysSullivan Jun 19, 2026
3e76072
docs: note /docs subpath hosting; redeploy to apply Host-at-/docs
RhysSullivan Jun 19, 2026
acc6ffb
docs: package-manager tabs (npm/pnpm/bun/yarn) for CLI install
RhysSullivan Jun 19, 2026
bdd7b51
docs: remove em-dashes from docs pages; ban them in AGENTS.md
RhysSullivan Jun 19, 2026
272ad3b
[codex] fix MCP OAuth callback path (#1060)
RhysSullivan Jun 21, 2026
65dd600
[codex] Fix signed-out OAuth callback recovery (#1061)
RhysSullivan Jun 21, 2026
6194d34
Handle MCP file and image outputs
RhysSullivan Jun 21, 2026
86a2d4a
Version Packages (#1064)
RhysSullivan Jun 21, 2026
7bd827d
Extract OpenAPI backed plugin helpers (#1056)
RhysSullivan Jun 21, 2026
3263d50
Extract Google provider plugin (#1057)
RhysSullivan Jun 21, 2026
b180c57
Add Microsoft Graph provider plugin (#1058)
RhysSullivan Jun 21, 2026
5cd7a77
mcp: surface auth-gated failures (#1059)
gjermundgaraba Jun 21, 2026
0961773
[codex] Use emit for code mode outputs (#1066)
RhysSullivan Jun 21, 2026
d5b7c46
Version Packages (#1067)
RhysSullivan Jun 22, 2026
a12d743
Trim connections.list output to a lean default with verbose opt-in (#…
RhysSullivan Jun 22, 2026
2b9ed1b
Acknowledge emitted output in the execute result envelope (#1070)
RhysSullivan Jun 22, 2026
1afdb46
docs: add MCP Proxy page, fill deployment pages, desktop screenshot
RhysSullivan Jun 22, 2026
1175ccb
fix(openapi): send a default User-Agent on upstream tool calls (#1071)
RhysSullivan Jun 22, 2026
cb13484
Optimize self-host Docker image size (#1068)
RhysSullivan Jun 22, 2026
6c24784
fix(oauth): redeem authorization codes at the provider's regional hos…
RhysSullivan Jun 22, 2026
7c873ec
CLI device-flow login for hosted accounts (`executor login`) (#1026)
RhysSullivan Jun 22, 2026
3e47752
Add changesets for v1.5.17 patch release (#1076)
RhysSullivan Jun 22, 2026
5a57372
docs: add "Set up with your agent" copy prompt (marketing + docs)
RhysSullivan Jun 22, 2026
8b49285
fix(selfhost): resolve libsql native package by build arch (#1078)
RhysSullivan Jun 22, 2026
9ddf1ff
Version Packages (#1077)
RhysSullivan Jun 22, 2026
164792d
docs: tighten setup prompt + measure the copy button
RhysSullivan Jun 22, 2026
c8eefaf
marketing: avoid double cast in copy-button analytics
RhysSullivan Jun 22, 2026
5f08d68
Fix: accept WorkOS device-login tokens on the /api plane (wrong JWKS)…
RhysSullivan Jun 22, 2026
a00124c
Parse the Microsoft Graph spec with the lean OpenAPI parser to fit th…
RhysSullivan Jun 22, 2026
b74c365
fix(openapi): put the file-emit contract in file-returning tools' des…
RhysSullivan Jun 22, 2026
0f53b5b
marketing: source PostHog key from wrangler vars (match cloud)
RhysSullivan Jun 23, 2026
30a39d3
fix(core-tools): allow no-auth connections via connections.create (#1…
RhysSullivan Jun 23, 2026
9347003
marketing: route posthog proxy under /_astro so it works on executor.sh
RhysSullivan Jun 23, 2026
f46ab13
Redesign marketing homepage (#1082)
RhysSullivan Jun 23, 2026
ac5d095
update tos & privacy
RhysSullivan Jun 23, 2026
b3f5f43
Marketing: drop team-access matrix, restore trace preview (#1087)
RhysSullivan Jun 23, 2026
ae3a162
fix: include org slug in connection handoff URLs (#1085)
RhysSullivan Jun 23, 2026
395ba97
Marketing: serve as build asssets (#1088)
RhysSullivan Jun 23, 2026
09c8190
List a connection's tools from a full OpenAPI spec on Workers without…
RhysSullivan Jun 23, 2026
f9798ce
hide yc badge
RhysSullivan Jun 23, 2026
1085844
Marketing: lead the hero with the MCP-gateway positioning (#1089)
RhysSullivan Jun 23, 2026
4113745
openapi: stream large specs so the full Microsoft Graph spec fits the…
RhysSullivan Jun 23, 2026
7b1bd3a
update executor tools (#1092)
RhysSullivan Jun 23, 2026
bc24d1a
Add changesets for the 1.5.18 patch release (#1093)
RhysSullivan Jun 23, 2026
6232b1b
feat: add the execution-observer foundation (#12)
aryasaatvik Jun 13, 2026
c458766
feat: add the execution-history plugin (#13)
aryasaatvik Jun 13, 2026
831ed53
feat: add the execution-metrics plugin (#14)
aryasaatvik Jun 13, 2026
0fdfbab
feat: JSON-document aggregation + keyset pagination pushdown (#15)
aryasaatvik Jun 14, 2026
25f0974
feat(execution-history): keyset runs API with aggregate meta (#16)
aryasaatvik Jun 14, 2026
30ecfa8
feat(execution-history): openstatus-style runs UI (#17)
aryasaatvik Jun 14, 2026
11838c1
fix(execution-history): align runs columns and slim timeline bars (#18)
aryasaatvik Jun 14, 2026
d4881c5
feat(execution-history): rich run-detail drawer (#19)
aryasaatvik Jun 14, 2026
c4ef40f
fix(execution-history): pad the runs toolbar
aryasaatvik Jun 14, 2026
5fd797b
feat(execution-history): attribute runs to a trigger actor + filter b…
aryasaatvik Jun 14, 2026
2f720fd
feat(execution-history): restore parity gaps from the old runs UI (#21)
aryasaatvik Jun 14, 2026
f9519f1
feat(host-cloudflare): attribute MCP-session runs to a trigger actor …
aryasaatvik Jun 14, 2026
66e883d
fix(execution-history): tolerate runs stored before the actor fields …
aryasaatvik Jun 14, 2026
6509646
feat(execution-history): horizontal-scroll runs table instead of hidi…
aryasaatvik Jun 14, 2026
492d597
chore(selfhost): use peerDependencies for shared singletons
aryasaatvik Jun 10, 2026
68c21ba
feat(sdk): read org plugin-storage outside the runtime
aryasaatvik Jun 13, 2026
32fece2
feat(react): render plugin nav pages as sidebar tabs
aryasaatvik Jun 13, 2026
9276cf0
feat(plugin-service-tokens): add service-token alias plugin
aryasaatvik Jun 13, 2026
4def9c6
feat(host-cloudflare): alias Access service tokens to human subjects
aryasaatvik Jun 13, 2026
587d058
feat(plugin-service-tokens): capture machine name + acting-as identity
aryasaatvik Jun 14, 2026
e9d03fe
feat(host-cloudflare): set a service-token run actor + acts-as identity
aryasaatvik Jun 14, 2026
5097784
fix(plugin-service-tokens): stop the machine-name input from collapsing
aryasaatvik Jun 15, 2026
edfd2c4
style(service-tokens): format plugin + cf-access seam with oxfmt
aryasaatvik Jun 15, 2026
2e775e0
feat(execution-history): move run detail to R2, slim the D1 index (#24)
aryasaatvik Jun 15, 2026
c24e11d
feat(plugin-service-tokens): edit a machine name on an existing alias
aryasaatvik Jun 15, 2026
929c880
feat(execution-history): content-fit runs table columns + centered te…
aryasaatvik Jun 15, 2026
d018c24
refactor(plugin-service-tokens): table layout for the alias list
aryasaatvik Jun 15, 2026
52eefaf
feat(execution-history): render live machine names for run actors
aryasaatvik Jun 15, 2026
8730fc8
feat: semantic tools.search via a Cloudflare Vectorize plugin (#26)
aryasaatvik Jun 15, 2026
b3081bf
feat(plugin-vectorize-search): facet chunking, hybrid RRF, and increm…
aryasaatvik Jun 16, 2026
2131a0b
feat(plugin-vectorize-search): local eval harness with pluggable embe…
aryasaatvik Jun 16, 2026
37d996a
refactor: drop the underscore prefix from unused parameters (#29)
aryasaatvik Jun 16, 2026
682c5c2
refactor(plugin-semantic-search): backend-agnostic rename + decoupled…
aryasaatvik Jun 16, 2026
099847c
test(host-selfhost): quarantine flaky concurrent-identity isolation t…
aryasaatvik Jun 16, 2026
2d7b53c
fix(package): remove duplicate entry for 'effect' in dependencies and…
aryasaatvik Jun 16, 2026
d6487a7
feat(plugin-semantic-search): D1-backed FTS5 lexical store + hybrid r…
aryasaatvik Jun 17, 2026
2ebe106
feat(plugin-semantic-search): operator Search console page + live sea…
aryasaatvik Jun 17, 2026
10e67e1
feat(plugin-semantic-search): paged reindex — reconcileToolCatalogPag…
aryasaatvik Jun 17, 2026
3d87557
feat(sdk): cache TypeScript schema previews (#35)
aryasaatvik Jun 18, 2026
a395c43
fix(cloudflare): use resumable MCP streams (#38)
aryasaatvik Jun 18, 2026
28b8efc
chore(cloudflare): improve MCP session observability (#39)
aryasaatvik Jun 18, 2026
2b3a505
refactor(mcp): use streamable http for remote clients (#40)
aryasaatvik Jun 18, 2026
962f41c
perf(sdk): cache tool schema views (#36)
aryasaatvik Jun 18, 2026
d8d365d
feat(host-cloudflare): serve MCP with Agents (#41)
aryasaatvik Jun 19, 2026
a122268
feat(plugin-semantic-search): add staged reindex pipeline (#37)
aryasaatvik Jun 19, 2026
866b5ca
feat(sdk): add tool schema manifest (#42)
aryasaatvik Jun 19, 2026
b97a579
perf(semantic-search): scan from tool manifests (#43)
aryasaatvik Jun 19, 2026
e24141d
fix(semantic-search): reconstruct queued index work
aryasaatvik Jun 19, 2026
cf4076e
perf(semantic-search): reduce queued index work (#44)
aryasaatvik Jun 19, 2026
5c254c1
perf(semantic-search): batch index storage operations (#45)
aryasaatvik Jun 19, 2026
9cca0f3
perf(storage): batch plugin storage upserts (#46)
aryasaatvik Jun 20, 2026
e9f2014
fix(semantic-search): preserve maxTools across resume (#47)
aryasaatvik Jun 20, 2026
623997d
fix(semantic-search): don't default the search prefix filter to the t…
aryasaatvik Jun 21, 2026
8e32553
perf(sdk): precompile tool-schema TypeScript during indexing (#49)
aryasaatvik Jun 21, 2026
6c0e482
perf(sdk): cache tools.list by catalog + policy revision (#50)
aryasaatvik Jun 21, 2026
4b5a180
perf(web): virtualize long lists behind a shared windowing primitive …
aryasaatvik Jun 21, 2026
564425b
perf(semantic-search): snapshot the tool manifest per run (KV-only sc…
aryasaatvik Jun 22, 2026
7f22595
fix(sync): resolve upstream rebase type fallout
aryasaatvik Jun 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions .changeset/core-tools-no-auth-connections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"executor": patch
---

`connections.create` now accepts no-auth connections (the `none` template with
no credential), which previously failed validation with "Expected exactly one
provider credential origin". Agents can wire up public, no-auth integrations
(public MCP servers, public REST APIs) programmatically instead of bouncing
through the web UI. Templates that take a credential still require exactly one.
13 changes: 13 additions & 0 deletions .changeset/execution-history-content-fit-table.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@executor-js/plugin-execution-history": patch
---

Rebuild the runs list as a real semantic `<table>` with content-fit columns.
Each column now sizes to the maximum width its rows need (browser
`table-layout: auto`), instead of fixed pixel widths — the sticky `<thead>` and
the rows share one column model so they stay aligned for free. Short / numeric /
badge columns (status, duration, tools, interaction, log) are centered; text
columns (started, trigger, actor, code) are left-aligned. The two columns that
can run long — `actor` and `code` — are width-capped and truncated (hover shows
the full value). Removes the fixed-width `COL_*` slot constants and the
`min-w` horizontal-scroll floor.
12 changes: 12 additions & 0 deletions .changeset/execution-history-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@executor-js/plugin-execution-history": minor
---

Add the `@executor-js/plugin-execution-history` plugin — an opt-in execution
history sink built on the ExecutionObserver foundation. It records every run
(plus its tool calls and interactions) into three owner-scoped pluginStorage
collections via a buffered-batch writer (no new tables, no migrations; works on
D1/libSQL/sqlite/postgres), exposes a `list`/`get`/`listToolCalls` read API over
HttpApi (`./api`'s `executionHistoryHttpPlugin`), and ships a Runs page UI
(`./client`) that mounts at `/plugins/executionHistory/`. The base `.` entry is
SDK-only and never loads `@executor-js/api` or React.
18 changes: 18 additions & 0 deletions .changeset/execution-history-r2-detail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
"@executor-js/plugin-execution-history": minor
---

Move per-run detail to an append-only R2 object and slim the D1 index. The
`runs` row now keeps only list/aggregate fields plus a bounded `codePreview` and
denormalized `logErrorCount`/`logWarnCount`, so the runs list renders entirely
from D1 with no per-row blob fetch. Full `code`, `resultJson`, `errorText`,
`logsJson`, `triggerMetaJson`, and the per-tool-call / per-interaction rows now
live in one immutable object per run in the plugin blob store (keyed
`run-detail/<executionId>`) — a code-only stub on `ExecutionStarted`, the full
detail on finish. The detail drawer reads it in a single request (`get`
flat-merges the R2 detail onto the slim run); the separate tool-calls endpoint
and `runToolCallsAtom` are removed, and the `toolCalls`/`interactions`
collections are gone.

Breaking: the runs list/detail response shapes change and past runs are cleared
(no backfill, no compatibility shim — the cutover wipe is authoritative).
15 changes: 15 additions & 0 deletions .changeset/execution-history-rich-list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@executor-js/plugin-execution-history": minor
---

Rework the runs list into a keyset-paginated, aggregate-aware read surface
backed by the storage JSON pushdown. The `list` endpoint now takes an opaque
keyset `cursor` (instead of offset), a sort field (`startedAt`/`durationMs`)
with direction, and a live-tail `after` floor, and returns `{ runs, nextCursor,
meta }`. The `meta` block — computed once per filter set on the first page —
carries status/trigger facet counts (each ignoring its own filter), interaction
counts, a stacked-by-status timeline with a server-chosen bucket width, total
and filtered row counts, and duration min/max plus P50–P99 percentiles. All
counts, buckets, percentiles, and pages are pushed to SQL rather than reducing
the whole collection in memory. Tool-path facets and full-text code search are
intentionally not included yet.
13 changes: 13 additions & 0 deletions .changeset/execution-history-runs-ui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@executor-js/plugin-execution-history": minor
---

Rebuild the runs page as an openstatus-style observability table on the keyset +
aggregate API. The page now has a faceted filter rail (status / trigger /
interaction / time range with live counts), a cmdk filter command palette, a
stacked-by-status timeline chart with drag-to-zoom, live tailing, keyset
infinite scroll, sortable columns, column visibility, keyboard shortcuts, and
the existing 4-tab detail drawer. List data flows through an Effect-atoms hook
(`useRunsList`) that accumulates cursor pages and polls the head for live mode;
the accumulation logic is a pure, unit-tested reducer. Adds `recharts` as an
optional peer dependency (provided by `@executor-js/react`).
13 changes: 13 additions & 0 deletions .changeset/execution-metrics-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@executor-js/plugin-execution-metrics": minor
---

Add the `@executor-js/plugin-execution-metrics` plugin — an opt-in metrics sink
built on the ExecutionObserver foundation. The base plugin drives Effect Metric
counters and an execution-duration histogram from the event stream; `./api`'s
`executionMetricsHttpPlugin` exposes them as an auth-gated `GET
/execution-metrics/metrics` Prometheus scrape for long-lived hosts; and
`./cloudflare`'s `createWaeMetricsObserver` writes Workers Analytics Engine data
points on the Cloudflare host (per-isolate Effect metrics being meaningless on a
Worker fleet). The base `.` entry never loads `@executor-js/api` or
`@cloudflare/workers-types`.
14 changes: 14 additions & 0 deletions .changeset/execution-observer-foundation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@executor-js/sdk": minor
"@executor-js/execution": minor
"@executor-js/api": minor
---

Add the execution-observer foundation. The execution engine now emits a typed
lifecycle stream (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`,
`InteractionStarted`/`Resolved`), plugins can subscribe via the new
`plugin.runtime.executionObserver` hook, and `makeExecutionStack` composes every
registered plugin's observer onto the engine. Behaviour is unchanged when no
plugin observes — this is the opt-in seam the execution-history and
execution-metrics plugins build on. Also exposes `Executor.owner` and enriches
the `mcp.execute` span with the run id and trigger.
16 changes: 16 additions & 0 deletions .changeset/fumadb-json-pushdown.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@executor-js/fumadb": minor
"@executor-js/sdk": minor
---

Push JSON-document aggregation and keyset pagination down to SQL. FumaDB's query
layer gains `jsonCount`, `jsonGroupCount`, `jsonTimeBuckets`, `jsonStats`
(min/max + continuous percentiles), and `jsonPage` (cursor pagination) over a
JSON document column, implemented natively for the memory and Drizzle
(SQLite/Postgres) adapters and failing loudly on adapters that don't support
them. Plugin storage exposes this as `collection.aggregate.{count,groupCount,
timeBuckets,stats}` and `collection.queryKeyset(...)`, translating a
collection's indexed-field `where` into JSON-path predicates while owner/tenant
scoping stays enforced by the storage policy. Aggregates and pages are computed
in the database instead of by fetching the whole collection and reducing in
memory.
8 changes: 8 additions & 0 deletions .changeset/openapi-file-emit-descriptions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"executor": patch
---

OpenAPI tools that return a file now spell out how to emit it directly in the
tool's description, so an agent sees the `emit(result.data)` contract before its
first call instead of only discovering it after a failed attempt or by reading
`describe.tool`. Non-file tools are unchanged.
10 changes: 10 additions & 0 deletions .changeset/semantic-search-manifest-snapshot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@executor-js/sdk": minor
"@executor-js/plugin-semantic-search": minor
---

Snapshot the tool manifest per reindex run instead of re-reading it from D1 on every scan page.

`createExecutor` now exposes its cache `KeyValueStore` on the executor instance as `executor.cache`, so plugins can reach durable cache storage (Cloudflare KV in production) without re-threading a binding — wrap it with `KeyValueStore.toSchemaStore` for typed entries, the same way the internal `tools.list` / schema-view caches do.

The semantic-search scan phase used to call `tools.manifest()` — a full `tool_schema_manifest` table read — once per partition page, so an unchanged catalog cost `O(N² / pageLimit)` cross-region reads. Now `create` reads the manifest once, partitions it, and writes one snapshot per partition to `executor.cache`; `scan` reads only its partition's snapshot (KV-only, with no D1 fallback on the hot path — a miss fails the message so the queue retries). Snapshots are deleted when the run completes. This collapses the scan's manifest reads from `O(N² / pageLimit)` to a single pass and cuts per-message memory from the whole manifest to one partition's slice.
14 changes: 14 additions & 0 deletions .changeset/semantic-search-tenant-namespace-prefix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@executor-js/plugin-semantic-search": patch
---

fix: don't default the operator search prefix filter to the tenant namespace

`executor.semanticSearch.search` (the operator `tools.search` surface) overloaded a
single `namespace` value as both the Vectorize tenant namespace (storage isolation)
and the optional integration/path-prefix filter. With no operator-supplied prefix it
defaulted the filter to the tenant namespace (e.g. `"default"`), so the provider's
`matchesNamespace` required every tool path to start with the tenant id and dropped
every result — search returned nothing for all queries despite a fully populated
index. The integration prefix is now applied only when explicitly provided; the
tenant namespace drives the store query alone and is still reported on the result page.
14 changes: 14 additions & 0 deletions .changeset/tools-list-revision-cache.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@executor-js/sdk": minor
---

Cache `tools.list` by a content-derived catalog revision. `produceConnectionTools` now
records a per-connection `toolset_revision` — a hash of the connection's manifest
`(path, index_fingerprint)` pairs — in `plugin_storage`, and `tools.list` keys a KV cache of
the DB-derived, policy-filtered list on the combined catalog revision plus a policy
revision (both read live, O(connections)/O(policies), not the full `tool` scan). Static tools
are unioned live and the `query` substring filter is applied post-cache, so a distinct query
reuses the same cached set. The cache stays warm through token rotation and unrelated writes
and invalidates exactly when a connection's tool set, a tool's schema, or a `tool_policy`
changes — including OpenAPI/MCP tool additions on refresh (a new manifest row) and
connection/integration removal.
15 changes: 15 additions & 0 deletions .changeset/tools-schema-precompile-typescript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@executor-js/sdk": minor
"@executor-js/plugin-semantic-search": patch
---

Always render the TypeScript preview in `executor.tools.schema` and warm it during
indexing. The `includeTypeScript` option (and the now-empty `ToolSchemaOptions` type) is
removed — the only caller that passed `false` was the reindex pipeline, which did so to
skip the CPU-heavy JSON-schema → TypeScript codegen. It now calls `tools.schema` plainly,
so every reindex pre-warms exactly the schema view the web UI reads on first open (the
codegen is content-addressed in KV), turning first tool-detail views into cache hits
instead of a cold compile. The embedding text is unchanged — the indexer only ever read
the raw schema facets, never the rendered TypeScript. Because `includeTypeScript` is
dropped from the schema-view cache key, existing cached entries are superseded on the next
reindex or view (regenerable derived data).
55 changes: 46 additions & 9 deletions .claude/skills/emulate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ description: Use the @executor-js/emulate service emulators (GitHub, Google, Str

# Emulate: production-fidelity service emulators

`@executor-js/emulate` (our fork of Vercel Labs' emulate, developed in
`vendor/emulate` but ALWAYS consumed as the published npm package — never
import from `vendor/`) provides stateful, wire-level emulators for 16
services: `github vercel google okta microsoft spotify slack apple aws
resend stripe mongoatlas clerk x workos autumn`. These are not mocks: real
SDKs and real product code run against them unmodified — the cloud e2e
target points the actual WorkOS SDK (sealed sessions, JWKS, hosted AuthKit
login) and Autumn billing at emulators and exercises the product's real
auth code.
`@executor-js/emulate` (our fork of Vercel Labs' emulate) provides stateful,
wire-level emulators for 16 services: `github vercel google okta microsoft
spotify slack apple aws resend stripe mongoatlas clerk x workos autumn`.
These are not mocks: real SDKs and real product code run against them
unmodified — the cloud e2e target points the actual WorkOS SDK (sealed
sessions, JWKS, hosted AuthKit login) and Autumn billing at emulators and
exercises the product's real auth code.

**This repo only consumes the published npm package.** There is no
`vendor/emulate` submodule — everything imports `@executor-js/emulate` from
npm. The emulator _source_ is its own standalone project; to change or deploy
an emulator, see "Changing or deploying an emulator" at the bottom.

## Two ways to get one

Expand Down Expand Up @@ -83,6 +86,40 @@ before `createEmulator` so minted MCP access tokens carry the right audience.
app's real dev stack (recipe in `e2e/setup/cloud.boot.ts`), fronted with
tailscale HTTPS.

## Changing or deploying an emulator

The emulators live in their own repo — **not** in executor and **not** a
submodule: `github.com/UsefulSoftwareCo/emulate` (clone it as a sibling of
executor). It's a pnpm + turbo monorepo on node ≥ 24 — a different toolchain
from executor's bun, which is exactly why it's standalone rather than
vendored here.

You have full autonomy over it: **work directly on `main`, and commit, push,
publish, and deploy without asking.** The loop:

1. Edit in the emulate repo, then **rebuild the package you changed.** It
resolves through built `dist`, so a source-only edit does nothing until you
build it — this is the single most common mistake. `@emulators/*` packages
are a `workspace:*` graph, so adding or renaming one needs an install +
rebuild too.
2. Publish a version bump of `@executor-js/emulate` to npm.
3. Deploy the hosted Cloudflare emulators (the `emulate-hosts` worker behind
`*.emulators.dev`) when behavior the hosted instances serve has changed.
4. Back in executor, bump the `@executor-js/emulate` dependency to the version
you just published. Never point a consumer at a local checkout to ship —
publish, then bump.

The emulate repo's own `AGENTS.md` / `README.md` carry the current build,
publish, and deploy commands (npm + Cloudflare creds are in 1Password). Read
them there rather than memorizing flags here — they move.

**A hot deploy can redden other people's e2e.** `*.emulators.dev` service
hosts are shared infrastructure; a control-plane regression there has failed
unrelated PRs' suites before. When a scenario needs isolation or a behavior
that isn't deployed yet, pin to a published package version or mint a private
per-run instance (`POST /_emulate/instances`) instead of mutating the shared
service host.

## Gotchas

- **Secure cookies need HTTPS off-localhost.** Browser-driven flows work on
Expand Down
114 changes: 114 additions & 0 deletions .claude/skills/prod-telemetry/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
name: prod-telemetry
description: Query Executor's production telemetry — Axiom traces (executor-cloud dataset), prod Postgres via PlanetScale, PostHog product analytics — through the Executor MCP. Use when investigating prod errors, latency, usage, churn signals, or verifying a deploy's telemetry; includes the dataset field layout, working APL recipes, and the error-attribution join.
---

# Production telemetry access

All three stores are queryable through the Executor MCP's connected
integrations — no dashboards or credentials needed. Verify the connection
exists with `connections.list` if a call fails.

## Axiom traces (`axiom_mcp`)

Tool: `axiom_mcp.user.axiomMcpOAuth.querydataset` — the argument is `apl`
(NOT `query`). Dataset: `['executor-cloud']` (worker spans; browser spans
join the same traces via traceparent).

**Field layout (the part you'd otherwise rediscover by failed queries):**

- Custom span attributes live under the JSON map `['attributes.custom']`,
NOT as top-level `attributes.*` columns. Read with
`['attributes.custom']['mcp.tool.name']`. A nonexistent top-level field is
a hard query error ("invalid field"), not an empty result.
- Span status: `['status.code']` (`"OK"`/`"ERROR"`), `['status.message']`.
- Exceptions: the `events` column carries `exception.type` /
`exception.stacktrace` JSON.
- OTel basics are top-level: `name`, `trace_id`, `span_id`,
`parent_span_id`, `duration`, `_time`.

**Span names worth querying** (and their custom attrs):

- `executor.tool.execute` — `mcp.tool.name` (full address), and since
PR #992: `executor.tool.outcome` (`ok`/`fail`),
`executor.tool.error_code`, `executor.tool.error_status`,
`executor.tenant`, `executor.subject`.
- `mcp.tool.dispatch` — `mcp.tool.name` (sandbox path),
`mcp.tool.integration`, same outcome attrs.
- `plugin.openapi.invoke` — `plugin.openapi.method` / `path_template` /
`base_url`, and since PR #992 `http.status_code`.
- `mcp.request` (outer) — `mcp.auth.organization_id`,
`mcp.auth.account_id`, `mcp.tool.name`, CF edge fields (`cf.country`…),
MCP client fingerprint (`mcp.client.name`…).

**Recipe — error signatures by class (the daily-digest query):**

```apl
['executor-cloud']
| where _time > ago(1d)
| where ['status.code'] == "ERROR" and name == "executor.tool.execute"
| extend msg = substring(tostring(['status.message']), 0, 120)
| extend tool = tostring(['attributes.custom']['mcp.tool.name'])
| summarize n = count() by msg, tool
| sort by n desc
```

**Recipe — attribute errors to orgs.** Tool spans now carry
`executor.tenant` directly (post-#992). For spans from BEFORE that deploy,
join through the outer request span:

```apl
['executor-cloud']
| where name == "mcp.request" and isnotnull(['attributes.custom']['mcp.auth.organization_id'])
| project trace_id, org = tostring(['attributes.custom']['mcp.auth.organization_id'])
| join kind=inner (
['executor-cloud']
| where ['status.code'] == "ERROR" and name == "executor.tool.execute"
| project trace_id, msg = substring(tostring(['status.message']), 0, 60)
) on trace_id
| summarize n = count() by org, msg | sort by n desc
```

**Recipe — upstream failure rate per integration (post-#992 attrs):**

```apl
['executor-cloud']
| where _time > ago(1d) and name == "mcp.tool.dispatch"
| extend outcome = tostring(['attributes.custom']['executor.tool.outcome'])
| extend integration = tostring(['attributes.custom']['mcp.tool.integration'])
| where isnotnull(outcome)
| summarize calls = count(), fails = countif(outcome == "fail") by integration
| extend failRate = todouble(fails) / todouble(calls)
| sort by fails desc
```

**Known signal caveats** (audited 2026-06-12):

- Pre-#992 spans: `ToolResult.fail` outcomes (upstream 4xx/5xx, auth
rejections) are INVISIBLE — they rode the Effect success channel with no
span marker. Don't conclude "no errors" from old data.
- Many pre-#992 ERROR spans have an EMPTY `status.message` (tagged errors
without a message field) — group those by `events` exception.type instead.
- `[object Object]` status messages are the pre-#992 formatting bug.

## Prod database (`planetscale_mcp`)

Read tool needs `{organization: "answer-overflow", database: "executor",
branch: "main"}`. It returns `ok: true` even when the SQL failed — check the
result text for `Error:`. Use for tenant/integration/connection facts that
spans don't carry (row sizes, config shapes, counts).

## Product analytics (`posthog_api` / `mcp_posthog_com`)

Browser-side events only (the ~60-event typed catalog, PR #987; server-side
events not built). The org-key `posthog_api` connection covers the REST API;
the OAuth MCP connection covers the higher-level tools.

## Verifying a deploy's telemetry (Layer-0 canary)

After deploying telemetry changes: run a known-failing tool call against
prod, then assert the expected attributes arrive in Axiom within ~1 min.
Absence of data looks identical to health — query for the NEW attribute
explicitly rather than eyeballing dashboards. The e2e equivalent runs on
every suite: `e2e/cloud/telemetry-contract.test.ts` via the `Telemetry`
service (motel `/api/spans/search?attr.<key>=<value>`).
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ jobs:
- name: Build web app
run: bun run --filter @executor-js/local build

- name: Build sidecar + stage web UI
- name: Build bundled executor
env:
BUN_TARGET: bun-linux-x64
run: bun ./scripts/build-sidecar.ts
Expand Down
Loading
Loading