# Vision > The product vision for Executor — what it is, the model it's built on, everything it > should eventually do, and the discipline for getting there. Implementations churn; this is > the destination they're heading toward, applied as incremental changes to the existing > codebase, not a rewrite. ## What Executor is Executor is an **open-source layer for your integrations** — a catalog of every operation across a company's software, plus the auth, scoping, policy, history, and oversight to act on it safely. - It is **not AI-specific.** Agents are a primary consumer, but the layer is a general way to represent and interop between sources of capability. - It is **not code-mode-specific.** Code mode is one way to call tools; it isn't the point. - It is a category of **integration** and a way to **interop between them** through one set of concepts. The bet: as work shifts toward agents acting through software, every company needs one layer where anything a human could do is callable — auditable, across every account — and where new capability is _composed_ on a shared substrate, not rebuilt per integration. One primitive unlocks the whole slice: catalog + auth + tools + scoping + UI + workflows + storage. It runs the same two ways from one codebase: an **in-process SDK** (no server, single-player, instant) and a **hosted service** (multiplayer, cloud). Single-player must feel great; multiplayer must be powerful; neither carries the other's weight. ## Core concepts - **Tool** — an id, an optional input schema, and an optional output schema (JSON Schema today; may grow richer types). The unit of capability. Addressed as `...`. - **Integration** — contains tools. An integration is produced by a plugin from some config (an OpenAPI spec, a GraphQL endpoint, an MCP server, a CLI's install/run). The core never sees the raw config — only a normalized manifest. - **Connection** — a credential, born wired, identified by `(scope, integration, name)`. The `name` is required and load-bearing (the account: `work`, `personal`, `prod`). One integration holds many connections. - **Secret** — never lives in Executor and never reaches the agent. A connection holds a `SecretRef` (a pointer — `op://`, `keychain://`, `env://`, `vault://`); a provider resolves it at call time, in trusted space, behind a proxy. - **Scope** — placement and identity. An ordered, merged set (see _Scopes_). Every record is placed in a scope. - **Policy** — gates execution (allow / require-approval / block). Attached to integrations and connections (see _Policies_). - **Plugin** — registers integrations, tools, providers, storage, surfaces. The one open extension seam (see _The model_). - **Manager / Invoker** — the core runtime roles: a manager owns an integration's tools and config; an invoker executes a tool through the right connection and proxy. ## The model — core, first-party, one seam, surfaces Executor is a **tiny core**, a set of **first-party capabilities** built on it, **one open extension seam**, and **surfaces** that expose it. **The core (the floor):** `execute(path, args)` (the one verb); the **catalog** of tools; **connections**; **scopes**; **policies/guardrails**; and `scope()` — narrow the executor to a subset, the seam everything composes through. **First-party capabilities** are a fixed, known set, included or omitted as modules — _not_ a generic plugin registry: toolkits, the MCP host, generative UI, workflows, storage, skills, audit/runs, the internal-apps catalog. They're separable but they don't go through an abstract plugin contract, because nobody outside you needs to add a new _kind_ of them. **One open plugin seam: integrations.** There are thousands of APIs; you'll never enumerate them; you want others to add them. That is where an open contract (`resolveTools` / `invokeTool`) earns its complexity. Secret **providers** are the one plausible second seam, for the same reason. > The discipline: do not make "everything a plugin." Keep first-party capabilities first-party, > and keep exactly one open seam (integrations, + maybe providers). Reversible — extract a new seam > only when several first-party capabilities demand the same one. **Surfaces / hosts** serve the executor over a wire: MCP, HTTP, CLI, stdio, triggers, the web app. The SDK works fully in-process with none of them. ## Composition — artifacts × surfaces, and the axes Everything you build is a point in a small space of orthogonal axes. New things become coordinates, not bespoke subsystems — this is what keeps the breadth tractable. - **kind** — tool / view (UI) / workflow / skill / store / connection - **lifetime** — ephemeral (a turn/session) / durable (deployed, addressable, re-openable) - **origin** — imported (a spec) / authored (code) / invoked-inline (produced by a call) - **surface** — in-process / MCP / HTTP / CLI / trigger / web - **delivery** — inline value / handle / embedded resource / deep link _(negotiated by client capability)_ Two rules fall out and dissolve most "how does X compose" confusion: 1. **Artifacts vs surfaces.** What you _build_ (kind) is separate from how it's _reached_ (surface). Build once; a surface projects it. A workflow defined once is reachable via cron, MCP, or in-process. A view defined once renders standalone or returns over MCP. Not everything fits every surface (a workflow isn't a slow tool; a UI isn't an HTTP handler). 2. **Rich outputs negotiate delivery.** Too big or too rich for the channel → return a _reference_ the client resolves per its capability. A large result → a **storage handle**. A UI → an **embedded UI resource** if the client renders it (MCP apps), else a **deep link** into the web app. UI is not special; it's a rich output under the same rules as everything. ## Scopes (scope merging) Placement is an **ordered, merged set of scopes**, outer (authority) → inner (actor). You add tools, connections, and policies at a global, workspace, or account level; override secrets and policies per scope; and create temporary scopes. Single-player is one scope; multiplayer is the same model with more entries. Three fixed merge rules, nothing configurable: - **visibility = union** (you see everything placed in any scope you hold); - **guardrails/policy = deny-union, outer-wins** (an outer scope's `block` can't be weakened inward; mandatory flows in); - **scalars/config/secret-overrides = innermost-wins** (the nearest scope to the actor wins). `org | user` is just the **two-element case** of this. The current codebase collapsed scopes to fixed org/user; the direction is to model it as an _ordered list that today has two entries_, so the resolver is already the general one and inserting a "team" or "environment" level later is additive, not a rewrite — added demand-driven, only when a real case needs the middle level. **Why scopes are a dimension, not indirection.** A past mistake (the credential-binding model: credential / slot / binding as separate objects wired together) caused an overcorrection that flattened scopes along with killing bindings. The lesson: **fuse indirection, keep dimensions.** A binding is a layer whose only job is to _connect_ two things — fuse it away (born-wired connections did this). A scope is a property that varies independently and meaningfully — keep it; flatten it and it leaks back as workarounds. Placement stays a **direct, inline property** on each record (the way `scope` already sits on a connection); never reintroduce an object whose job is to _attach_ a record to a scope. ## Connections, secrets & auth - **Connection = a credential, born wired** (secret + account fused; no slot/binding split), identified by `(scope, integration, name)` with `name` required. - **Multiple accounts per integration per scope** (distinct names). Per-member auth (each connects their own) and team-level shared auth (one credential placed in an outer scope) are both just placement. - **Auth template vs credential.** An integration declares _how_ it authenticates (OAuth / bearer / API key — a discriminated set); each connection fills that template. - **Secrets never reach the agent.** Resolved by a provider at call time, in trusted space, behind a **tool-proxy** — credentials never enter agent or sandbox code. **No escape hatch:** a `SecretRef` never appears in a tool's I/O schema or any MCP/host response. - **Heterogeneous backends per member** (1Password / keychain / env / vault), declared separately. **Credential lifecycle** (refresh, rotation, revocation, expiry) handled below the agent. ## Integrations & integration kinds Each kind is added through the **one open seam** (`resolveTools` + `invokeTool`): **OpenAPI**, **GraphQL**, **MCP servers**, **CLI** (install + run, no spec), **direct API / raw-fetch**, and later **direct database** and **email**. The plugin owns the opaque config and raw spec; the core reasons over a **normalized manifest** (schemas, side-effect class, auth template, data labels, required capabilities, an LLM-authored description). **Spec auto-refresh** tracks upstream drift and **must never auto-expand authority** — new operations appear _ungranted until reviewed_. An **integrations registry** lets people discover and add integrations. ## Policies Policies gate **execution** — `approve` / `require_approval` / `block` — and are distinct from toolkits (which gate visibility). Resolution is _most-restrictive-wins_; **plugin defaults** let an integration ship a tool pre-marked `require_approval` (destructive detection), with `approve` as the override when an import wrongly flags a safe action. How people actually use them today (real usage): glob patterns over the address, where _every_ rule targets an **integration** and wildcards the scope/connection (`stripe_api.*.*.disputes.*`, `pscale.*.*.execute_write_query`) — i.e. faking structural targeting because there's nowhere to attach it. The direction: - **Kill the global glob list. Attach policy to the integration and connection records** — the two structural levels. **Connection overrides integration** (innermost-wins), with **scope authority layered on top** (outer/org mandatory, can't be weakened inward). - Fixing a mis-flagged tool becomes `approve` _on that integration/connection_, directly. - **Toolkits carry no policy** — they're pure curation and inherit whatever integration/connection policies apply to the tools they expose. This dissolves the old global-vs-toolkit merge conflict. ## Toolkits & scoping A **toolkit is pure curation** — a named subset of tools (a `ToolSet`) that yields a **scoped view** of the executor. Used for **per-agent capability control**: lock down exactly what an added agent can reach (a background firewall-monitor agent gets _only_ a monitor tool and an update-firewall tool, and nothing that builds). **`toolkits.list` feeds a consent screen** — the grantable slices an agent or OAuth flow requests. Single-player keeps toolkits too. ## Authorization & capabilities One model over a **typed capability namespace**, three layers kept apart: **grants** (positive authority; toolkits are grant bundles), **policy/guardrails** (deny/approval), and **runtime** (object-capability handles only — no ambient executor, no raw secret, no unrestricted fetch). The tool axis stays a **predicate** (`ToolSet`); **meta-capability kinds are typed per-kind** — `author-tools` (effects ceiling), `generate-UI`, `allocate-storage` (quota), `deploy`, `trigger-register`, `egress`. **Capabilities compose transitively, enforced by the `scope()`-narrowed executor as a membrane:** an authored tool runs against its author's captured scope, so a toolkit-X agent's tool calling toolkit-Y fails because Y was never in scope. `scope()` strictly intersects (never widens); delegation routes through a granter; one enforcement surface, no advisory mode — the local isolate and the cloud worker enforce the same membrane. ## Surfaces You build once; surfaces project. - **In-process** — `execute`, the SDK path. No server. - **MCP** — a scoped endpoint (`/mcp?toolkit=...`) over a _scoped executor_; the host authenticates → resolves the toolkit → `scope()` → hands the narrowed executor to the MCP server, which never sees a toolkit. Default shape is **meta-tools** (`search` + `describe` + `execute` + `run_code`) so a huge catalog doesn't blow context, with a direct-tools opt-out. **Authoring tools** (`render`, `create_workflow`, `author_tool`, `skills.create`) appear only when the scope grants the matching meta-capability. - **MCP apps with dynamic UI** — React-flight / RSC + code mode for rich UI returned over MCP (an embedded UI resource on capable clients, a deep link otherwise). - **MCP channels** — talk back to the agent mid-tool-call (the "Claude Code over Discord" pattern), for human-in-the-loop and elicitation. - **HTTP** — any capability projected as a route, after policy/auth/versioning/CORS. - **CLI** — the same operations from the terminal (see _Distribution_). - **Triggers** — a schedule (cron) or an event that fires an artifact. - **Web app** — the UI-capable surface where views render and deep links land. ## What you build - **Custom tools & API gateway.** Write a tool as a function and deploy it; it joins the catalog. **Account-parametric** — a custom function calls a catalog op without baking in an account; the account is passed at invocation. Executor doubles as an **API gateway** with a **generated typed SDK** for everything added. - **Workflows.** Multi-step sequences of tool calls with **durable run semantics**, built ideally on `use workflow` (or Cloudflare Workflows). User-defined entry points; **cron + event triggers**; infrastructure-as-code. A step _is_ a catalog tool call. - **Generative UI.** A **view** governed by lifetime × delivery: ephemeral (the agent calls `render`) or durable (an authored dashboard). Rich UI runs in a sandbox; it calls only the tools its scope grants, proxied server-side, never holding credentials. - **Skills.** Shared, code-authored knowledge — the company knowledge base as code — that agents draw on, that **surfaces in tool search**, and can **run tools inline** to cut round-trips. Served off MCP and from a `.well-known`. File-backed (see _Authoring model_). - **Internal apps catalog & custom UI snippets.** Store and share custom UI and internal apps. - **Configure Executor via Executor** — managing integrations, connections, scopes, policies, toolkits is itself done through tools. ## Authoring model — two paths Every authored artifact (skill, custom tool, workflow, UI) has **two first-class authoring paths**, matched to two contexts: - **File + deploy** (developer, with the CLI): `executor/skills/`, `executor/tools/`, … authored in a repo, `executor deploy` pushes them. Git gives versioning, review, rollback. The canonical, org-shared tier. - **A tool over MCP** (an agent with no CLI, e.g. in a desktop client): `skills.create`, `author_tool`, `create_workflow` write to the runtime directly. Zero friction, no filesystem. These aren't two sources of truth: each artifact has **one master** distinguished by origin and **scope/tier** (a runtime-authored artifact is personal/inner-scope; a deployed one is org/outer-scope, git-backed). **Promotion** is an explicit handoff — `executor pull` materializes a good runtime artifact into files for review and merge, graduating it to canonical. With a git-backed store (below), runtime authoring is literally a commit-from-a-worker and promotion is a branch/namespace merge. ## Storage — two substrates Split by lifetime/kind, not one confused store: - **Authored artifacts** (skills, custom tools, workflows, UI — durable, versioned, reviewed) → **git-backed**: local Git, and in the cloud **Cloudflare Artifacts** (git-over-HTTPS, push commits from a Worker, read at runtime via a Workers binding / ArtifactFS, namespaces ≈ scopes, versioning/pinning/rollback from git for free). "Git stands in for Cloudflare Artifacts" is literal — local == remote with no translation. Both authoring paths commit to one repo. - **Agent state** (data — reactive, high-frequency) → **KV / SQLite / filesystem**. Every chat gets a temporary KV + SQLite + filesystem the agent can use; the agent can also create stores on scopes to persist between calls. Accessed **as ordinary tools** (no side-channel API). Addressed by **handles** + a search-across-stores utility. **Reactive** (Convex-style: a workflow writes, a UI/chat sees it live, with access rules). **Large results land in storage** and return a handle — which is how the MCP context-overflow problem is actually solved. ## The Run model Every execution, on any surface, produces or attaches to a **Run**: id, parent run, artifact version, principal chain, capability set, policy version, input hash, output handle, logs, spans, approvals, retries, cancellation, status. One record **collapses four features into views over it**: audit log, human-in-the-loop approvals, workflow runs, and resumability/debugging. ## Human-in-the-loop Pause a call and require a human before it proceeds: **MCP elicitation**, a **gated `resume` tool** (the user simply doesn't always allow it), a **resume URL**, or an **MCP channel** talk-back mid-call. A gated call returns a _pending_ Run with a resume reference. ## Sandbox & runtime Untrusted code — user plugins, agent-authored tools, generative-UI bundles — runs sandboxed: locally a **V8 isolate** (and the quickjs / dynamic-worker / deno-subprocess runtimes), in the cloud a **Cloudflare Dynamic Worker**. **Default-deny.** Both enforce the **same capability membrane** (the scope-narrowed executor; `env` is the capability set; outbound closed except through the tool-execution binding). Credentials never enter the sandbox. Let the agent write whatever it needs; ship instructions (skills) as part of Executor. ## Distribution, the CLI & remotes The `executor` CLI is **three things at once**: the **local runtime** (run a full instance and start using it), the **control plane** (local _and_ remote, same commands), and an **agent-facing surface**. Distribution surfaces are all "local": `executor` (CLI), `executor service install` (daemon), `executor web` (web app) — one instance, delivered differently. - **Remotes ("cores").** Add remote instances; one shared sign-in; call them identically. Execution **runs where the credential lives** — invoke from machine B, it runs on A with A's credential; nothing crosses machines. - **Merge local + remote** (the "SSH for tools" / OpenTunnel model) — a tool on one machine is callable from anywhere. - **Deploy & dev.** `deploy` (with `--check`) pushes authored artifacts; git-backed `sync`; hot-reload `dev`; local filesystem access. **Configure Executor via Executor** from the CLI. ## Cloud & user-generated extensions The hosted product runs on a **Cloudflare substrate** and lets users **write plugins and load them dynamically, sandboxed** — each in a Worker isolate with a **declared capability manifest** (a plugin asking for specific scopes can do exactly that and nothing else). User plugins ride the **integration seam** and the capability membrane, opened **last and curated**. Local == remote via **substrate substitution**: a local V8 isolate stands in for the dynamic worker, Git for Cloudflare Artifacts, local SQLite for hosted storage. ## Cross-cutting concerns - **Data provenance / tainting** — label data handles (source, connection, scope, sensitivity, retention, allowed readers/egress) so policy can reason as data flows tool → storage → UI → chat. - **Egress / allowed-hosts** — prevents **data** exfiltration (credentials are already safe via the proxy), not credential leakage. A guardrail facet. - **Simulation / emulation** — run tools against the `@executor-js/emulate` emulators (wire-level, stateful, real OAuth + credentials + request ledger) for side-effect-free testing. - **Multiple language targets** — JS now, Python later (data/analysis work). ## Architecture Built on **Effect**. The same SDK is in-memory _and_ client/server; SDK-only users need no server; serving is a standard Web `Request → Response` handler. The discipline that keeps breadth cheap is the **seam discipline**: the platform owns generic concerns (auth, caching, retries, schema, rendering, transport, the Run); a plugin owns only the integration-specific resolve/invoke. ## Principles - **One unifying primitive** — everything reduces to "invoke tool T → typed output." - **Tiny core; compose the rest.** Ship the primitives that build an extendable product. - **No silent defaults; explicit addressing.** The account is always in the path. - **Type the human surface, not the agent surface.** - **Secrets never reach the agent; authority only narrows.** - **Visibility ≠ permission** — curation (toolkits) is separate from governance (policy). - **Share the substrate aggressively; split the surfaces deliberately.** The failure mode of a broad product is too many features in one undifferentiated human surface — keep that surface minimal. - **Fuse indirection; keep dimensions.** (Born-wired connections, not credential bindings; stacked scopes, not flattened ones.) - **One master per record** — file-backed or runtime-authored, never two live masters. ## How we build it - **Don't rewrite — evolve the existing codebase.** This vision is a map you steer toward with incremental, git-shaped changes, not a greenfield rebuild. The wedge already exists. - **The wedge:** be best-in-class at the catalog of imported tools + connections/secrets, exposed through one invocation interface — with zero-token-exposure, the Run/audit record, human approval, the capability membrane, and code-mode/meta-tool search baked in. Then sequence nearest-to-substrate first: MCP → storage → workflows → generative UI → user plugins (curated, last). Three substrate invariants keep composition cheap: one typed invocation primitive; authorization inherited from the substrate, never re-implemented; a hard seam between substrate-generic and integration-specific code. - **Vision mode vs build mode.** This document is vision mode — generativity ("and then you'd want X") is the point. In **build mode, every "and then you'd want X" is a YAGNI to defer**, not a dependency to satisfy. Build the smallest thing useful on its own; let the next be _pulled_ by real pain, not _pushed_ by imagined composition. The tell that you've slipped back to vision mode: the next step needs two other things built first. (Example: v1 skills = read a folder, expose `skills.search` + `skills.get`. No scopes, toolkits, environments, or git required.) ## North-star scenarios - **The shared-data loop.** "Every morning at 9am, load my GitHub issues into SQLite": a scheduled workflow writes to storage; a generative-UI front end reads it live; you chat with the agent over the same data. One substrate, three readers. - **The scoped agent.** "An agent I can message that can _only_ update my calendar." A toolkit exposes a one-tool slice; the agent connects to a scoped MCP endpoint; it physically cannot reach anything else. ## Positioning The open-source alternative to closed integration layers; interops with adjacent projects; one primitive serving both backend-for-customers and internal-team use. The model is to nail a wedge, then grow many composing capabilities on a shared substrate — without letting the human-facing surface bloat with it. ## Open questions - Data provenance/tainting — the label model and how policy consumes it. - Skills ↔ custom functions ↔ specs — where the boundaries sit and how the capability gate follows references. - Typegen ownership — leaning "don't own it; expose as a utility." - Reconciliation UX for merged local+remote catalogs; filesystem overlay vs CLI-routed. - Storage allocation default — which class is the default and how handles are named. - Raw-fetch manifest — how an untyped tool kind declares its capabilities.