Unified · Split
| @@ -12,7 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | }, |
| 13 | 13 | "apps/executor": { |
| 14 | 14 | "name": "executor", |
| 15 | − "version": "1.1.8", | |
| 15 | + "version": "1.1.9", | |
| 16 | 16 | "bin": { |
| 17 | 17 | "executor": "bin/executor", |
| 18 | 18 | }, |
| @@ -79,6 +79,9 @@ · 60 unmodified lines | ||
| 79 | 79 | "vite": "^7.3.1", |
| 80 | 80 | }, |
| 81 | 81 | }, |
| 82 | + "docs": { | |
| 83 | + "name": "@executor/docs", | |
| 84 | + }, | |
| 82 | 85 | "packages/ai-sdk-adapter": { |
| 83 | 86 | "name": "@executor/ai-sdk-adapter", |
| 84 | 87 | "dependencies": { |
| @@ -475,6 +478,8 @@ · 390 unmodified lines | ||
| 475 | 478 | |
| 476 | 479 | "@executor/control-plane": ["@executor/control-plane@workspace:packages/control-plane"], |
| 477 | 480 | |
| 481 | + "@executor/docs": ["@executor/docs@workspace:docs"], | |
| 482 | + | |
| 478 | 483 | "@executor/executor-mcp": ["@executor/executor-mcp@workspace:packages/executor-mcp"], |
| 479 | 484 | |
| 480 | 485 | "@executor/kitchen-sink": ["@executor/kitchen-sink@workspace:packages/kitchen-sink"], |
| @@ -0,0 +1,96 @@ | ||
| 1 | +--- | |
| 2 | +title: "Adapters And Formats" | |
| 3 | +description: "How executor supports multiple integration types without hardwiring the core to one protocol." | |
| 4 | +--- | |
| 5 | + | |
| 6 | +Adapters are the main extensibility boundary in executor. | |
| 7 | + | |
| 8 | +They let executor support multiple integration styles without turning the control plane into a long chain of provider-specific branches. | |
| 9 | + | |
| 10 | +## What an adapter does | |
| 11 | + | |
| 12 | +An adapter owns the format-specific or protocol-specific behavior for a source. | |
| 13 | + | |
| 14 | +That includes: | |
| 15 | + | |
| 16 | +- connect payload shape | |
| 17 | +- binding config serialization and decoding | |
| 18 | +- source validation | |
| 19 | +- source config extraction | |
| 20 | +- materialization | |
| 21 | +- manifest parsing | |
| 22 | +- operation description | |
| 23 | +- invocation | |
| 24 | + | |
| 25 | +The control plane owns the generic lifecycle around that. | |
| 26 | + | |
| 27 | +## Why adapters exist | |
| 28 | + | |
| 29 | +Executor needs to support integrations that do not all look the same at the source boundary: | |
| 30 | + | |
| 31 | +- OpenAPI specs | |
| 32 | +- GraphQL APIs | |
| 33 | +- MCP servers | |
| 34 | +- future Google Discovery imports | |
| 35 | +- future Postman collections | |
| 36 | +- future snippet bundles | |
| 37 | + | |
| 38 | +If the core storage model were shaped around one of those directly, every new integration family would cause another redesign. | |
| 39 | + | |
| 40 | +Adapters prevent that. | |
| 41 | + | |
| 42 | +## Family vs format | |
| 43 | + | |
| 44 | +It is important not to confuse the integration family with the import format. | |
| 45 | + | |
| 46 | +Examples: | |
| 47 | + | |
| 48 | +- OpenAPI and GraphQL are both broadly `http_api`-style integrations in executor | |
| 49 | +- MCP is still its own family because it has distinct session and discovery semantics | |
| 50 | + | |
| 51 | +This lets executor share broad runtime behavior where appropriate without pretending every source is identical. | |
| 52 | + | |
| 53 | +## What gets stored | |
| 54 | + | |
| 55 | +Adapters do **not** get to invent arbitrary top-level storage models. | |
| 56 | + | |
| 57 | +They compile into the same canonical layers: | |
| 58 | + | |
| 59 | +- recipe | |
| 60 | +- revision | |
| 61 | +- raw documents | |
| 62 | +- schema bundles | |
| 63 | +- operations | |
| 64 | + | |
| 65 | +That means the control plane can stay generic while adapters remain flexible. | |
| 66 | + | |
| 67 | +## Why binding config is adapter-owned | |
| 68 | + | |
| 69 | +Adapter-owned binding config is one of the most important anti-churn decisions in the codebase. | |
| 70 | + | |
| 71 | +Instead of adding more and more provider columns to the source model, the adapter carries its own binding payload and version. | |
| 72 | + | |
| 73 | +That makes it much cheaper to evolve formats without reopening the core schema for every field addition. | |
| 74 | + | |
| 75 | +## Why provider-specific detail still exists | |
| 76 | + | |
| 77 | +Executor does still store some provider-shaped detail in operation metadata and bundle/document kinds. | |
| 78 | + | |
| 79 | +That is intentional, but the direction is: | |
| 80 | + | |
| 81 | +- keep the generic IR thin | |
| 82 | +- keep provider-specific detail in adapter code or typed provider metadata | |
| 83 | + | |
| 84 | +The goal is not to erase differences between formats. The goal is to stop those differences from dominating the core architecture. | |
| 85 | + | |
| 86 | +## What a good new adapter should do | |
| 87 | + | |
| 88 | +A good new adapter should: | |
| 89 | + | |
| 90 | +- compile into the canonical recipe/revision/operation model | |
| 91 | +- use adapter-owned binding config | |
| 92 | +- avoid requiring new generic tables or provider columns unless truly necessary | |
| 93 | +- expose stable tool paths and search text | |
| 94 | +- make auth needs explicit through the existing auth slot model | |
| 95 | + | |
| 96 | +If an integration needs a whole new top-level execution family, that is a sign it may not belong as just another `http_api` adapter. | |
| @@ -0,0 +1,59 @@ | ||
| 1 | +--- | |
| 2 | +title: "CLI" | |
| 3 | +description: "How the executor CLI fits into the system and why it stays thin." | |
| 4 | +--- | |
| 5 | + | |
| 6 | +The CLI lives in `apps/executor`. | |
| 7 | + | |
| 8 | +Its job is to be the installed user-facing shell around the local daemon, not the place where product logic is implemented. | |
| 9 | + | |
| 10 | +## Responsibilities | |
| 11 | + | |
| 12 | +The CLI is responsible for: | |
| 13 | + | |
| 14 | +- starting and stopping the local daemon | |
| 15 | +- checking daemon health and installation state | |
| 16 | +- submitting executions | |
| 17 | +- resuming paused interactions | |
| 18 | +- packaging and distribution concerns for the installed binary | |
| 19 | + | |
| 20 | +## What it should not own | |
| 21 | + | |
| 22 | +The CLI should not own: | |
| 23 | + | |
| 24 | +- source persistence rules | |
| 25 | +- auth workflows | |
| 26 | +- tool discovery | |
| 27 | +- execution state machines | |
| 28 | +- tool invocation behavior | |
| 29 | + | |
| 30 | +Those belong in the control plane. | |
| 31 | + | |
| 32 | +## Why this boundary matters | |
| 33 | + | |
| 34 | +This split is intentional. | |
| 35 | + | |
| 36 | +It means the browser UI, CLI, and local MCP entrypoint all talk to the same product core instead of each carrying their own business logic. That keeps behavior consistent across entrypoints and avoids reimplementing source, credential, and execution rules in multiple places. | |
| 37 | + | |
| 38 | +## How it talks to the rest of the system | |
| 39 | + | |
| 40 | +At a high level, the CLI: | |
| 41 | + | |
| 42 | +1. ensures the local daemon is available | |
| 43 | +2. calls the local HTTP API exposed by `packages/server` | |
| 44 | +3. hands off real work to `packages/control-plane` | |
| 45 | + | |
| 46 | +That makes the CLI a stable shell over a shared local runtime rather than a second product core. | |
| 47 | + | |
| 48 | +## Why this is flexible | |
| 49 | + | |
| 50 | +Because the CLI is thin, new product capabilities usually do not require redesigning the CLI architecture. | |
| 51 | + | |
| 52 | +Most new work lands in: | |
| 53 | + | |
| 54 | +- control-plane runtime logic | |
| 55 | +- source adapters | |
| 56 | +- codemode packages | |
| 57 | +- server/API surfaces | |
| 58 | + | |
| 59 | +The CLI mostly needs new commands or command wiring on top of those primitives. | |
| @@ -0,0 +1,69 @@ | ||
| 1 | +--- | |
| 2 | +title: "Code Mode" | |
| 3 | +description: "The shared tool abstractions and adapter packages that connect sources to execution." | |
| 4 | +--- | |
| 5 | + | |
| 6 | +The codemode packages are the bridge between imported integrations and executable tools. | |
| 7 | + | |
| 8 | +They provide the shared tool abstractions that both the control plane and runtime can depend on. | |
| 9 | + | |
| 10 | +## Core role | |
| 11 | + | |
| 12 | +The codemode layer is where executor turns "some external thing" into a discoverable and invokable tool surface. | |
| 13 | + | |
| 14 | +That is why it exists as a separate layer instead of being buried directly inside each product surface. | |
| 15 | + | |
| 16 | +## Main packages | |
| 17 | + | |
| 18 | +### `packages/codemode-core` | |
| 19 | + | |
| 20 | +This package holds the common tool model: | |
| 21 | + | |
| 22 | +- tool definitions | |
| 23 | +- tool catalogs | |
| 24 | +- tool invokers | |
| 25 | +- discovery helpers | |
| 26 | +- schema-aware tool contracts | |
| 27 | +- shared system-tool concepts | |
| 28 | + | |
| 29 | +This is the main abstraction boundary that other layers build on. | |
| 30 | + | |
| 31 | +### `packages/codemode-openapi` | |
| 32 | + | |
| 33 | +This package handles OpenAPI-specific extraction and tool generation. | |
| 34 | + | |
| 35 | +Its job is to understand OpenAPI and compile it into the shared codemode tool model, not to own workspace persistence or auth lifecycle. | |
| 36 | + | |
| 37 | +### `packages/codemode-mcp` | |
| 38 | + | |
| 39 | +This package handles MCP-specific tool discovery and invocation behavior and adapts remote MCP tools into the same shared tool model. | |
| 40 | + | |
| 41 | +## Why this layer exists | |
| 42 | + | |
| 43 | +Without the codemode layer, the control plane would have to understand every source format and execution detail directly. | |
| 44 | + | |
| 45 | +Instead, executor keeps the core model broad and pushes format-specific transformation logic into focused packages. | |
| 46 | + | |
| 47 | +That is what makes the system extensible: | |
| 48 | + | |
| 49 | +- new adapters can target the same internal tool model | |
| 50 | +- the runtime can execute against one logical tool surface | |
| 51 | +- the same abstractions can be reused outside the control plane, including SDK-style consumers | |
| 52 | + | |
| 53 | +## How it fits with the control plane | |
| 54 | + | |
| 55 | +The control plane owns: | |
| 56 | + | |
| 57 | +- bindings | |
| 58 | +- credentials | |
| 59 | +- revisions and materialization | |
| 60 | +- tool indexing | |
| 61 | +- policy and invocation lifecycle | |
| 62 | + | |
| 63 | +The codemode layer owns: | |
| 64 | + | |
| 65 | +- how external formats become tools | |
| 66 | +- how those tools are described | |
| 67 | +- how format-specific invocation helpers are implemented | |
| 68 | + | |
| 69 | +That boundary is what keeps the architecture adapter-based instead of turning the control plane into one large protocol-specific switch statement. | |
| @@ -0,0 +1,130 @@ | ||
| 1 | +--- | |
| 2 | +title: "Core Model" | |
| 3 | +description: "The main data and runtime concepts in executor today." | |
| 4 | +--- | |
| 5 | + | |
| 6 | +The most important thing to understand about executor is that it does **not** model the system as one flat `source` row. | |
| 7 | + | |
| 8 | +The current model has a few separate concepts that each exist for a different reason. | |
| 9 | + | |
| 10 | +## The primary concepts | |
| 11 | + | |
| 12 | +### Source binding | |
| 13 | + | |
| 14 | +A source is the workspace-local installation record. | |
| 15 | + | |
| 16 | +It answers: | |
| 17 | + | |
| 18 | +- what is this integration called in this workspace? | |
| 19 | +- is it enabled? | |
| 20 | +- what namespace should its tools use? | |
| 21 | +- what install-local config does it have? | |
| 22 | + | |
| 23 | +This is why a source carries local concerns like name, namespace, enabled state, binding config, and status. | |
| 24 | + | |
| 25 | +### Recipe | |
| 26 | + | |
| 27 | +A recipe is the shareable integration identity. | |
| 28 | + | |
| 29 | +It answers: | |
| 30 | + | |
| 31 | +- what integration definition is this? | |
| 32 | +- what adapter produced it? | |
| 33 | +- what family does it belong to? | |
| 34 | + | |
| 35 | +A recipe is meant to converge across workspaces when the underlying integration definition is the same. | |
| 36 | + | |
| 37 | +### Revision / materialization | |
| 38 | + | |
| 39 | +A recipe revision is the compiled result of an import. | |
| 40 | + | |
| 41 | +It answers: | |
| 42 | + | |
| 43 | +- what source config produced this compiled shape? | |
| 44 | +- what manifest, documents, schema bundles, and operations belong to it? | |
| 45 | + | |
| 46 | +This is the durable execution artifact layer. | |
| 47 | + | |
| 48 | +### Operation IR | |
| 49 | + | |
| 50 | +Operations are the canonical callable tool index. | |
| 51 | + | |
| 52 | +They answer: | |
| 53 | + | |
| 54 | +- what tools exist? | |
| 55 | +- how should they be searched and described? | |
| 56 | +- how does invocation find the right persisted operation quickly? | |
| 57 | + | |
| 58 | +The operation layer exists because raw upstream documents are not a good direct query surface for search, policy, and invocation lookup. | |
| 59 | + | |
| 60 | +### Credential | |
| 61 | + | |
| 62 | +Credentials are private auth bindings. | |
| 63 | + | |
| 64 | +They answer: | |
| 65 | + | |
| 66 | +- who can authenticate for this binding? | |
| 67 | +- for which slot? | |
| 68 | +- using what auth kind and secret refs? | |
| 69 | + | |
| 70 | +Credentials are actor-scoped by default because two users in the same workspace may connect different identities to the same source. | |
| 71 | + | |
| 72 | +## Why the split matters | |
| 73 | + | |
| 74 | +This split fixes a few old problems: | |
| 75 | + | |
| 76 | +- shareable definition is no longer confused with workspace-local installation | |
| 77 | +- auth is no longer implicitly one-token-per-source | |
| 78 | +- materialized tool content is no longer stored directly under one workspace source | |
| 79 | +- provider-specific import details do not need to become universal top-level columns | |
| 80 | + | |
| 81 | +## Binding config | |
| 82 | + | |
| 83 | +Source-specific connection config now lives in adapter-owned binding payloads: | |
| 84 | + | |
| 85 | +- `bindingVersion` | |
| 86 | +- `binding` | |
| 87 | + | |
| 88 | +That means the core model does not need built-in fields forever for every provider-specific connection knob. | |
| 89 | + | |
| 90 | +Examples: | |
| 91 | + | |
| 92 | +- OpenAPI binding can carry `specUrl` and `defaultHeaders` | |
| 93 | +- MCP binding can carry `transport`, `queryParams`, and `headers` | |
| 94 | +- internal bindings can be empty | |
| 95 | + | |
| 96 | +The adapter owns serialization, decoding, defaults, and validation for that payload. | |
| 97 | + | |
| 98 | +## Families vs adapters | |
| 99 | + | |
| 100 | +Executor separates broad runtime families from adapter keys. | |
| 101 | + | |
| 102 | +Broad families: | |
| 103 | + | |
| 104 | +- `http_api` | |
| 105 | +- `mcp` | |
| 106 | +- `internal` | |
| 107 | + | |
| 108 | +Adapters are more specific: | |
| 109 | + | |
| 110 | +- `openapi` | |
| 111 | +- `graphql` | |
| 112 | +- `mcp` | |
| 113 | +- future `google_discovery` | |
| 114 | +- future `postman_collection` | |
| 115 | +- future `snippet_bundle` | |
| 116 | + | |
| 117 | +This distinction keeps the runtime model broad and stable while still allowing importer-specific behavior. | |
| 118 | + | |
| 119 | +## Why this is the right shape | |
| 120 | + | |
| 121 | +The current model is designed so that new support usually means: | |
| 122 | + | |
| 123 | +- add or evolve an adapter | |
| 124 | +- compile into the same recipe/revision/operation layers | |
| 125 | + | |
| 126 | +and not: | |
| 127 | + | |
| 128 | +- redesign how source persistence fundamentally works | |
| 129 | + | |
| 130 | +That is the main goal of the current architecture. | |
| @@ -0,0 +1,100 @@ | ||
| 1 | +--- | |
| 2 | +title: "Credentials And Auth" | |
| 3 | +description: "How executor models auth, interactive flows, and actor-scoped credential ownership." | |
| 4 | +--- | |
| 5 | + | |
| 6 | +Auth in executor is not treated as a side detail on the source row. | |
| 7 | + | |
| 8 | +It is modeled as its own layer because auth has different ownership and lifecycle semantics from source bindings and recipe materialization. | |
| 9 | + | |
| 10 | +## Auth ownership | |
| 11 | + | |
| 12 | +Credentials are scoped to: | |
| 13 | + | |
| 14 | +- workspace | |
| 15 | +- source binding | |
| 16 | +- actor | |
| 17 | +- slot | |
| 18 | + | |
| 19 | +This is important because different users in the same workspace may connect different identities to the same source. | |
| 20 | + | |
| 21 | +## Auth slots | |
| 22 | + | |
| 23 | +Executor distinguishes where auth is used. | |
| 24 | + | |
| 25 | +Important current slots: | |
| 26 | + | |
| 27 | +- `runtime` | |
| 28 | +- `import` | |
| 29 | + | |
| 30 | +Why this matters: | |
| 31 | + | |
| 32 | +- some integrations use the same auth for both | |
| 33 | +- some need auth only to fetch or generate the materialization | |
| 34 | +- some may eventually need setup/bootstrap-specific auth | |
| 35 | + | |
| 36 | +This is why source auth is more than a single token field. | |
| 37 | + | |
| 38 | +## Static credentials | |
| 39 | + | |
| 40 | +The common case today is still static auth backed by secret references. | |
| 41 | + | |
| 42 | +Examples: | |
| 43 | + | |
| 44 | +- bearer token | |
| 45 | +- OAuth access token | |
| 46 | +- OAuth refresh token | |
| 47 | + | |
| 48 | +The control plane stores secret refs, not raw secret values inline on the source or credential rows. | |
| 49 | + | |
| 50 | +## Interactive auth sessions | |
| 51 | + | |
| 52 | +Interactive auth, such as OAuth flows, is modeled separately from stored credentials. | |
| 53 | + | |
| 54 | +That separation exists because: | |
| 55 | + | |
| 56 | +- a pending auth flow has state and lifecycle of its own | |
| 57 | +- it may be tied to an interaction or execution | |
| 58 | +- it is not the same thing as a resolved credential | |
| 59 | + | |
| 60 | +This is why executor has auth sessions and credentials as separate concepts. | |
| 61 | + | |
| 62 | +## Why actor scope matters | |
| 63 | + | |
| 64 | +The old one-token-per-source assumption does not hold once: | |
| 65 | + | |
| 66 | +- multiple users share a workspace | |
| 67 | +- each user connects their own Google account, GitHub account, or other external identity | |
| 68 | + | |
| 69 | +Actor-scoped ownership is the durable fix for that. | |
| 70 | + | |
| 71 | +## The next auth primitive | |
| 72 | + | |
| 73 | +One important extension area is dynamic credentials. | |
| 74 | + | |
| 75 | +Static secret refs are not always enough for integrations that: | |
| 76 | + | |
| 77 | +- derive short-lived auth by calling login or refresh endpoints | |
| 78 | +- need app-specific runtime headers | |
| 79 | +- require token renewal logic | |
| 80 | + | |
| 81 | +The likely next auth-layer primitive is an auth provider or auth material resolver: | |
| 82 | + | |
| 83 | +- configured with secret refs and stable inputs | |
| 84 | +- produces runtime auth material on demand | |
| 85 | +- caches it with expiry metadata | |
| 86 | + | |
| 87 | +That is broader than sources and should be reusable by future source adapters, tool providers, and code bundles. | |
| 88 | + | |
| 89 | +## Why auth is separated from recipes | |
| 90 | + | |
| 91 | +Recipes are shareable integration definitions. | |
| 92 | +Credentials are private installation-specific state. | |
| 93 | + | |
| 94 | +That separation is important both for correctness and for shareability: | |
| 95 | + | |
| 96 | +- a recipe can be portable | |
| 97 | +- a source binding can be local | |
| 98 | +- credentials stay private | |
| 99 | + | |
| 100 | +This is the main reason auth is not modeled as part of the shareable recipe layer. | |
| @@ -0,0 +1,83 @@ | ||
| 1 | +--- | |
| 2 | +title: "Extending Executor" | |
| 3 | +description: "How to add new source support without breaking the current architecture." | |
| 4 | +--- | |
| 5 | + | |
| 6 | +The best way to extend executor is to respect the current boundaries instead of stretching the core model. | |
| 7 | + | |
| 8 | +## First question: is it really a source? | |
| 9 | + | |
| 10 | +Not every new integration should be modeled as a source. | |
| 11 | + | |
| 12 | +Use the source model when the thing is: | |
| 13 | + | |
| 14 | +- a persistent external system | |
| 15 | +- with install-local configuration | |
| 16 | +- with auth state | |
| 17 | +- that materializes into callable tools | |
| 18 | + | |
| 19 | +If the new thing is really: | |
| 20 | + | |
| 21 | +- a local tool library | |
| 22 | +- a package bundle | |
| 23 | +- a browser automation runtime | |
| 24 | + | |
| 25 | +then it may need a different top-level primitive instead of being shoved into the source model. | |
| 26 | + | |
| 27 | +## If it is a source, add an adapter | |
| 28 | + | |
| 29 | +The happy path for a new integration is: | |
| 30 | + | |
| 31 | +1. define the adapter key and family | |
| 32 | +2. define the connect and binding config shape | |
| 33 | +3. materialize into documents, schema bundles, and operations | |
| 34 | +4. implement invocation | |
| 35 | +5. add tests against the canonical model | |
| 36 | + | |
| 37 | +The adapter should absorb provider-specific logic so the core does not have to. | |
| 38 | + | |
| 39 | +## What a new adapter should not do | |
| 40 | + | |
| 41 | +Avoid these patterns: | |
| 42 | + | |
| 43 | +- adding new provider-specific columns to generic tables because one adapter wants them | |
| 44 | +- storing expanded presentation output as canonical truth | |
| 45 | +- bypassing the operation layer and invoking directly from raw documents | |
| 46 | +- treating auth as provider-specific ad hoc fields on the source row | |
| 47 | + | |
| 48 | +Those are the patterns that lead back to churn. | |
| 49 | + | |
| 50 | +## The standard for a good extension | |
| 51 | + | |
| 52 | +A good new adapter should make the core system feel boring. | |
| 53 | + | |
| 54 | +That means: | |
| 55 | + | |
| 56 | +- persistence still looks like recipe/revision/operations | |
| 57 | +- auth still flows through the same credential/session primitives | |
| 58 | +- discovery and inspection still work through the same catalog ideas | |
| 59 | +- execution still delegates through the same tool and adapter boundaries | |
| 60 | + | |
| 61 | +If a new adapter needs deep new behavior in all of those places, that is usually a sign it may be a new primitive, not just a new adapter. | |
| 62 | + | |
| 63 | +## What feels like the next natural extensions | |
| 64 | + | |
| 65 | +The current architecture is well-suited to future additions like: | |
| 66 | + | |
| 67 | +- Google Discovery imports | |
| 68 | +- Postman collection imports | |
| 69 | +- snippet bundles | |
| 70 | +- richer auth material providers | |
| 71 | + | |
| 72 | +Those should mostly be adapter and auth-layer work, not another persistence redesign. | |
| 73 | + | |
| 74 | +## Why this is the best setup | |
| 75 | + | |
| 76 | +The current setup is not trying to be abstract for its own sake. | |
| 77 | +It is trying to keep the codebase in a state where: | |
| 78 | + | |
| 79 | +- core concepts stay stable | |
| 80 | +- new support lands as extensions | |
| 81 | +- source support does not require philosophy rewrites every few weeks | |
| 82 | + | |
| 83 | +That is the real reason the system is shaped around adapters, recipes, revisions, operations, and actor-scoped credentials. | |
| @@ -0,0 +1,51 @@ | ||
| 1 | +--- | |
| 2 | +title: "MCP" | |
| 3 | +description: "How executor uses MCP both as a source family and as an external interface." | |
| 4 | +--- | |
| 5 | + | |
| 6 | +MCP shows up in executor in two different ways. | |
| 7 | + | |
| 8 | +## 1. Executor can connect to MCP servers | |
| 9 | + | |
| 10 | +This is the source side of MCP. | |
| 11 | + | |
| 12 | +When a user connects an MCP endpoint, executor treats it as a source family with MCP-specific connection, discovery, and invocation behavior. The control plane persists the binding and credential state, while MCP-specific execution behavior lives behind the adapter and codemode layers. | |
| 13 | + | |
| 14 | +This is why MCP is modeled as its own broad family instead of being treated like just another HTTP format. | |
| 15 | + | |
| 16 | +## 2. Executor can expose itself as an MCP server | |
| 17 | + | |
| 18 | +This is the outward-facing side of MCP. | |
| 19 | + | |
| 20 | +`packages/executor-mcp` and the `/mcp` route in `packages/server` let external MCP clients talk to the local executor runtime. | |
| 21 | + | |
| 22 | +That means external MCP hosts can: | |
| 23 | + | |
| 24 | +- discover executor tools | |
| 25 | +- trigger executions | |
| 26 | +- resume paused interactions | |
| 27 | +- work against the same local workspace state as the CLI and browser UI | |
| 28 | + | |
| 29 | +## Why the distinction matters | |
| 30 | + | |
| 31 | +These two roles are related, but they are not the same thing: | |
| 32 | + | |
| 33 | +- inbound MCP means executor is acting as a client to a remote MCP server | |
| 34 | +- outbound MCP means executor is acting as a server for external MCP clients | |
| 35 | + | |
| 36 | +Keeping that distinction clear avoids collapsing very different responsibilities into one vague "MCP integration" concept. | |
| 37 | + | |
| 38 | +## Where the logic lives | |
| 39 | + | |
| 40 | +Broadly: | |
| 41 | + | |
| 42 | +- control plane owns workspace state, bindings, credentials, and execution lifecycle | |
| 43 | +- `packages/codemode-mcp` owns MCP tool loading and invocation helpers | |
| 44 | +- `packages/executor-mcp` owns the local MCP server surface | |
| 45 | +- `packages/server` mounts the `/mcp` handler | |
| 46 | + | |
| 47 | +## Why MCP stays flexible in this model | |
| 48 | + | |
| 49 | +Because MCP is handled as a family with its own adapter/runtime behavior, executor can support protocol-specific features such as sessions, elicitation, and resume without bending the generic `http_api` model to fit them. | |
| 50 | + | |
| 51 | +That is the main reason MCP is a first-class category in the architecture. | |
| @@ -0,0 +1,108 @@ | ||
| 1 | +--- | |
| 2 | +title: "Control Plane Overview" | |
| 3 | +description: "How the control plane is structured today and how the major pieces fit together." | |
| 4 | +--- | |
| 5 | + | |
| 6 | +Executor is built around one central idea: | |
| 7 | + | |
| 8 | +- turn connected systems into a durable, discoverable tool catalog | |
| 9 | +- run TypeScript against that catalog inside a controlled runtime | |
| 10 | +- keep connection state, auth, execution, and inspection in one local control plane | |
| 11 | + | |
| 12 | +## One-line architecture | |
| 13 | + | |
| 14 | +Executor is a local control plane that: | |
| 15 | + | |
| 16 | +1. stores connected integrations as sources | |
| 17 | +2. materializes those sources into callable tools | |
| 18 | +3. exposes those tools to the runtime, the UI, and MCP clients | |
| 19 | +4. resolves auth and policy at invocation time | |
| 20 | + | |
| 21 | +## Major packages | |
| 22 | + | |
| 23 | +### `apps/executor` | |
| 24 | + | |
| 25 | +The CLI and daemon manager. | |
| 26 | + | |
| 27 | +Responsibilities: | |
| 28 | + | |
| 29 | +- start and stop the local daemon | |
| 30 | +- submit executions | |
| 31 | +- resume paused interactions | |
| 32 | +- seed and inspect sources in development flows | |
| 33 | + | |
| 34 | +### `packages/server` | |
| 35 | + | |
| 36 | +The local server shell around the control plane. | |
| 37 | + | |
| 38 | +Responsibilities: | |
| 39 | + | |
| 40 | +- mount the HTTP API at `/v1` | |
| 41 | +- mount the local MCP server at `/mcp` | |
| 42 | +- serve the web UI | |
| 43 | + | |
| 44 | +### `packages/control-plane` | |
| 45 | + | |
| 46 | +The product core. | |
| 47 | + | |
| 48 | +Responsibilities: | |
| 49 | + | |
| 50 | +- source connection and lifecycle | |
| 51 | +- auth and credential state | |
| 52 | +- persistence | |
| 53 | +- tool discovery and inspection | |
| 54 | +- execution management | |
| 55 | +- policy-aware invocation | |
| 56 | + | |
| 57 | +### Runtime and codemode packages | |
| 58 | + | |
| 59 | +These packages provide the execution and tool abstractions: | |
| 60 | + | |
| 61 | +- `packages/runtime-ses` | |
| 62 | +- `packages/codemode-core` | |
| 63 | +- `packages/codemode-openapi` | |
| 64 | +- `packages/codemode-mcp` | |
| 65 | +- `packages/react` | |
| 66 | + | |
| 67 | +## The mental model | |
| 68 | + | |
| 69 | +The current architecture is easiest to understand if you think of it as an adapter-based compiler pipeline: | |
| 70 | + | |
| 71 | +- adapters ingest external formats and protocols | |
| 72 | +- the control plane stores a canonical internal representation | |
| 73 | +- the runtime executes against that representation | |
| 74 | + | |
| 75 | +That is why executor has strong internal concepts like: | |
| 76 | + | |
| 77 | +- source bindings | |
| 78 | +- recipes and revisions | |
| 79 | +- materialized operations | |
| 80 | +- schema bundles | |
| 81 | +- actor-scoped credentials | |
| 82 | + | |
| 83 | +Those are not UI concepts. They are the durable internal model that lets executor support multiple integration styles without rewriting the core every time. | |
| 84 | + | |
| 85 | +## What is intentionally centralized | |
| 86 | + | |
| 87 | +Executor intentionally centralizes a few things that many products split across multiple services: | |
| 88 | + | |
| 89 | +- local identity and workspace bootstrap | |
| 90 | +- source connection state | |
| 91 | +- secret material references | |
| 92 | +- tool inspection data | |
| 93 | +- execution history | |
| 94 | +- interaction/resume state | |
| 95 | + | |
| 96 | +This is why the UI, CLI, and local MCP entrypoint can all behave like one system instead of separate tools bolted together. | |
| 97 | + | |
| 98 | +## Why the architecture is shaped this way | |
| 99 | + | |
| 100 | +The current implementation optimizes for: | |
| 101 | + | |
| 102 | +- local-first operation | |
| 103 | +- strong schema-aware tool usage | |
| 104 | +- reusable connected integrations | |
| 105 | +- minimal provider-specific logic in the control plane core | |
| 106 | +- extensibility through adapters instead of one-off execution paths | |
| 107 | + | |
| 108 | +The rest of the developer docs explain how those goals show up in the current model. | |
| @@ -0,0 +1,86 @@ | ||
| 1 | +--- | |
| 2 | +title: "Persistence And Migrations" | |
| 3 | +description: "How executor stores source state today and how migration logic is intended to work." | |
| 4 | +--- | |
| 5 | + | |
| 6 | +Executor persistence is designed around durable runtime state, not just CRUD storage. | |
| 7 | + | |
| 8 | +That means the database stores: | |
| 9 | + | |
| 10 | +- installation and workspace identity | |
| 11 | +- source bindings | |
| 12 | +- recipes and revisions | |
| 13 | +- raw documents | |
| 14 | +- schema bundles | |
| 15 | +- operations | |
| 16 | +- credentials and auth sessions | |
| 17 | +- executions and interactions | |
| 18 | + | |
| 19 | +## Why the storage is layered | |
| 20 | + | |
| 21 | +The storage model is layered because these concerns have different reuse and ownership semantics. | |
| 22 | + | |
| 23 | +Examples: | |
| 24 | + | |
| 25 | +- raw documents are provenance | |
| 26 | +- revisions are compiled materializations | |
| 27 | +- operations are the hot-path query surface | |
| 28 | +- source bindings are workspace-local | |
| 29 | +- credentials are private and actor-scoped | |
| 30 | + | |
| 31 | +Trying to collapse those into one table or one document shape causes churn quickly. | |
| 32 | + | |
| 33 | +## What is normalized vs serialized | |
| 34 | + | |
| 35 | +Executor intentionally uses both relational columns and serialized JSON. | |
| 36 | + | |
| 37 | +Normalized: | |
| 38 | + | |
| 39 | +- ownership | |
| 40 | +- ids and references | |
| 41 | +- search and lookup fields | |
| 42 | +- status and visibility | |
| 43 | +- auth/session ownership | |
| 44 | + | |
| 45 | +Serialized: | |
| 46 | + | |
| 47 | +- adapter-owned binding config | |
| 48 | +- source config blobs | |
| 49 | +- provider metadata | |
| 50 | +- some session payloads | |
| 51 | + | |
| 52 | +This is deliberate. | |
| 53 | +The rule is to normalize what the core system queries and enforces, and serialize what belongs to adapter-specific contracts. | |
| 54 | + | |
| 55 | +## Migrations philosophy | |
| 56 | + | |
| 57 | +The intended migration model is: | |
| 58 | + | |
| 59 | +- SQL migrations move structural schema into the new shape | |
| 60 | +- one-shot code migrations repair or rebuild data that SQL cannot derive sanely | |
| 61 | +- steady-state runtime paths should not carry compatibility branches forever | |
| 62 | + | |
| 63 | +That last point matters. | |
| 64 | +Compatibility logic belongs in upgrade code, not in normal reads and writes. | |
| 65 | + | |
| 66 | +## What is still acceptable in migration code | |
| 67 | + | |
| 68 | +One-shot rebuilds are still acceptable when: | |
| 69 | + | |
| 70 | +- the old data shape is structurally valid but not yet in the best compiled form | |
| 71 | +- the rebuild can be derived from already-stored documents | |
| 72 | +- the logic is ledgered and run once | |
| 73 | + | |
| 74 | +What is not acceptable: | |
| 75 | + | |
| 76 | +- provider-specific legacy fallbacks in steady-state runtime logic | |
| 77 | +- carrying old columns indefinitely because one path still reads them | |
| 78 | + | |
| 79 | +## Why this supports extensibility | |
| 80 | + | |
| 81 | +This persistence shape is meant to let new integrations land in one of two ways: | |
| 82 | + | |
| 83 | +- add a new adapter that compiles into the same source model | |
| 84 | +- add a genuinely new top-level primitive if the thing is not really a source | |
| 85 | + | |
| 86 | +That is how executor avoids turning every new integration into another schema redesign. | |
| @@ -0,0 +1,81 @@ | ||
| 1 | +--- | |
| 2 | +title: "Tool Catalog And Execution" | |
| 3 | +description: "How source materialization becomes callable tools and how invocation works." | |
| 4 | +--- | |
| 5 | + | |
| 6 | +Executor turns connected integrations into a workspace tool catalog. | |
| 7 | + | |
| 8 | +That catalog is the thing the runtime actually executes against. | |
| 9 | + | |
| 10 | +## How tools are produced | |
| 11 | + | |
| 12 | +At a high level: | |
| 13 | + | |
| 14 | +1. an adapter materializes a source | |
| 15 | +2. the materialization writes documents, schema bundles, and operations | |
| 16 | +3. the control plane loads those persisted operations into a workspace tool index | |
| 17 | +4. the runtime invokes one tool at a time through the control plane | |
| 18 | + | |
| 19 | +This means executor does not rebuild every integration from scratch on every execution. | |
| 20 | + | |
| 21 | +## Why operations exist as a separate layer | |
| 22 | + | |
| 23 | +The operation layer exists to support: | |
| 24 | + | |
| 25 | +- search | |
| 26 | +- inspection | |
| 27 | +- policy | |
| 28 | +- fast tool lookup | |
| 29 | +- tool description without loading huge raw documents every time | |
| 30 | + | |
| 31 | +Raw upstream documents are still kept, but they are not the best hot-path query surface. | |
| 32 | + | |
| 33 | +## Schema transport | |
| 34 | + | |
| 35 | +Executor uses compact operation-root schemas plus shared schema bundles. | |
| 36 | + | |
| 37 | +This is better than storing expanded per-tool schema blobs because it avoids: | |
| 38 | + | |
| 39 | +- massive duplicate schema payloads | |
| 40 | +- slow formatting and rendering | |
| 41 | +- treating presentation output as canonical storage | |
| 42 | + | |
| 43 | +The result is: | |
| 44 | + | |
| 45 | +- smaller payloads | |
| 46 | +- more reusable schema graphs | |
| 47 | +- cleaner tool detail responses | |
| 48 | + | |
| 49 | +## Tool catalog shape | |
| 50 | + | |
| 51 | +The tool catalog is built from: | |
| 52 | + | |
| 53 | +- persisted source tools | |
| 54 | +- built-in executor tools | |
| 55 | + | |
| 56 | +That lets executor present one unified discovery and invocation surface even though the underlying tools come from different places. | |
| 57 | + | |
| 58 | +## Invocation flow | |
| 59 | + | |
| 60 | +At a high level, invocation works like this: | |
| 61 | + | |
| 62 | +1. resolve the persisted operation by tool path | |
| 63 | +2. run policy and approval checks | |
| 64 | +3. resolve auth material for the correct slot | |
| 65 | +4. load the manifest and schema bundle needed for the call | |
| 66 | +5. delegate actual invocation to the adapter | |
| 67 | + | |
| 68 | +This is the key point: | |
| 69 | + | |
| 70 | +- the control plane orchestrates | |
| 71 | +- the adapter performs the protocol-specific call | |
| 72 | + | |
| 73 | +## Why this is flexible | |
| 74 | + | |
| 75 | +This architecture is flexible because it keeps a stable middle: | |
| 76 | + | |
| 77 | +- the runtime only needs tools and invokers | |
| 78 | +- the control plane only needs the canonical operation and auth model | |
| 79 | +- adapters can vary widely at the source boundary without changing the runtime contract | |
| 80 | + | |
| 81 | +That is what makes it possible to add more source types without constantly rewriting execution logic. | |
| @@ -9,10 +9,52 @@ · 8 unmodified lines | ||
| 9 | 9 | "dark": "#0D9373" |
| 10 | 10 | }, |
| 11 | 11 | "navigation": { |
| 12 | − "groups": [ | |
| 12 | + "tabs": [ | |
| 13 | 13 | { |
| 14 | − "group": "Getting Started", | |
| 15 | − "pages": ["introduction"] | |
| 14 | + "tab": "Product", | |
| 15 | + "groups": [ | |
| 16 | + { | |
| 17 | + "group": "Introduction", | |
| 18 | + "pages": [ | |
| 19 | + "introduction" | |
| 20 | + ] | |
| 21 | + } | |
| 22 | + ] | |
| 23 | + }, | |
| 24 | + { | |
| 25 | + "tab": "Developer", | |
| 26 | + "groups": [ | |
| 27 | + { | |
| 28 | + "group": "Control Plane", | |
| 29 | + "pages": [ | |
| 30 | + "developer/overview", | |
| 31 | + "developer/core-model", | |
| 32 | + "developer/adapters-and-formats", | |
| 33 | + "developer/credentials-and-auth", | |
| 34 | + "developer/tool-catalog-and-execution", | |
| 35 | + "developer/persistence-and-migrations", | |
| 36 | + "developer/extending-executor" | |
| 37 | + ] | |
| 38 | + }, | |
| 39 | + { | |
| 40 | + "group": "CLI", | |
| 41 | + "pages": [ | |
| 42 | + "developer/cli" | |
| 43 | + ] | |
| 44 | + }, | |
| 45 | + { | |
| 46 | + "group": "MCP", | |
| 47 | + "pages": [ | |
| 48 | + "developer/mcp" | |
| 49 | + ] | |
| 50 | + }, | |
| 51 | + { | |
| 52 | + "group": "Code Mode", | |
| 53 | + "pages": [ | |
| 54 | + "developer/codemode" | |
| 55 | + ] | |
| 56 | + } | |
| 57 | + ] | |
| 16 | 58 | } |
| 17 | 59 | ] |
| 18 | 60 | }, |
| @@ -4,3 +4,17 @@ description: "A local-first execution environment for AI agents." · 3 unmodified lines | ||
| 4 | 4 | --- |
| 5 | 5 | |
| 6 | 6 | `executor` is a local-first execution environment for AI agents. It gives an agent a TypeScript runtime, a discoverable tool catalog, and a single local place to connect external systems such as MCP servers, OpenAPI APIs, and GraphQL APIs. |
| 7 | + | |
| 8 | +This docs site is split into two documentation surfaces: | |
| 9 | + | |
| 10 | +- product-facing docs for how to install and use executor | |
| 11 | +- developer-facing docs for how executor is built and how to extend it | |
| 12 | + | |
| 13 | +The product-facing section will come later. The current docs start with the developer-facing architecture and implementation model. | |
| 14 | + | |
| 15 | +If you are trying to understand the current system shape, start with: | |
| 16 | + | |
| 17 | +- [Control Plane](/developer/overview) | |
| 18 | +- [CLI](/developer/cli) | |
| 19 | +- [MCP](/developer/mcp) | |
| 20 | +- [Code Mode](/developer/codemode) | |
| @@ -0,0 +1,10 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor/docs", | |
| 3 | + "private": true, | |
| 4 | + "type": "module", | |
| 5 | + "scripts": { | |
| 6 | + "dev": "bunx --bun mint dev --no-open --port 3337", | |
| 7 | + "typecheck": "echo 'No typecheck for @executor/docs'", | |
| 8 | + "validate": "bunx --bun mint validate" | |
| 9 | + } | |
| 10 | +} | |
| @@ -5,7 +5,8 @@ · 4 unmodified lines | ||
| 5 | 5 | "packageManager": "bun@1.2.22", |
| 6 | 6 | "workspaces": [ |
| 7 | 7 | "packages/*", |
| 8 | − "apps/*" | |
| 8 | + "apps/*", | |
| 9 | + "docs" | |
| 9 | 10 | ], |
| 10 | 11 | "catalog": { |
| 11 | 12 | "@effect/cli": "^0.73.2", |
| @@ -19,7 +20,8 @@ · 7 unmodified lines | ||
| 19 | 20 | "zod": "^4.3.6" |
| 20 | 21 | }, |
| 21 | 22 | "scripts": { |
| 22 | − "dev": "turbo run dev --filter=@executor/web", | |
| 23 | + "dev": "turbo run dev", | |
| 24 | + "docs:dev": "turbo run dev --filter=@executor/docs", | |
| 23 | 25 | "test": "turbo run test", |
| 24 | 26 | "executor": "./apps/executor/bin/executor", |
| 25 | 27 | "typecheck": "bun run --filter='*' typecheck", |