Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions apps/cloud/src/edge/marketing.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { describe, expect, it } from "@effect/vitest";

import { isMarketingPath } from "./marketing";

// On executor.sh the marketing middleware proxies an allow-list of paths to the
// `executor-marketing` worker; everything else falls through to the auth-gated
// cloud app (the sign-in page). `/blog` and `/llms.txt` are public content, so
// they must be on the allow-list: without it an unauthenticated visit redirects
// to `/login?returnTo=...` and the reader bounces.
describe("isMarketingPath", () => {
const marketing = [
"/home",
"/privacy",
"/terms",
"/blog",
"/blog/",
"/blog/some-post",
"/llms.txt",
"/og-image.png",
"/_astro/app.css",
];
for (const pathname of marketing) {
it(`proxies ${pathname} to marketing`, () => {
expect(isMarketingPath(pathname)).toBe(true);
});
}

// App-owned routes must reach the Effect handler, not marketing. `/blogger`
// guards against a bare `startsWith("/blog")` swallowing unrelated words.
const notMarketing = ["/", "/login", "/cloud", "/mcp", "/dashboard", "/blogger"];
for (const pathname of notMarketing) {
it(`leaves ${pathname} alone`, () => {
expect(isMarketingPath(pathname)).toBe(false);
});
}
});
4 changes: 3 additions & 1 deletion apps/cloud/src/edge/marketing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ const MARKETING_PATHS = [
"/setup",
"/privacy",
"/terms",
"/blog",
"/llms.txt",
"/api/detect",
"/_astro",
"/og-image.png",
"/pattern-graph-paper.svg",
];

const isMarketingPath = (pathname: string) =>
export const isMarketingPath = (pathname: string) =>
MARKETING_PATHS.some((p) => pathname === p || pathname.startsWith(`${p}/`));

const getMarketingWorker = () => env.MARKETING as { fetch: typeof fetch } | undefined;
Expand Down
32 changes: 32 additions & 0 deletions apps/marketing/public/llms.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Executor

> Executor is an open-source integration layer for AI agents. Configure every integration once (MCP servers, OpenAPI specs, GraphQL APIs) with authentication and per-tool policies, then use that one catalog from any MCP-compatible agent.

Every agent you use (Claude Code, Cursor, ChatGPT, and the rest) otherwise needs its own copy of every integration: the same API keys pasted in three places, the same MCP servers wired up again, no shared idea of what each tool is allowed to do. Executor is the layer in between: add a tool once, give it credentials once, set its policy once, and every agent shares it over MCP.

How it works:

- Add an integration: an MCP server, an OpenAPI spec, a GraphQL API, or a Google Discovery document.
- Create a connection: one configured (optionally authenticated) instance of that integration. An integration can have many connections.
- Set policies: decide whether each tool is always allowed, needs approval, or is blocked.
- Use it from any MCP-compatible agent: one catalog of tools, shared across every client.

Run it your way: local CLI, a desktop app, hosted Executor Cloud, or self-hosted on Docker or Cloudflare.

## Docs

- [Documentation](https://executor.sh/docs): guides for adding integrations, connections, policies, and connecting agents over MCP.

## Product

- [Website](https://executor.sh): product overview and getting started.
- [Pricing](https://executor.sh/#pricing): plans for Executor Cloud.
- [Install](https://executor.sh/#install): install the CLI and connect your first agent.

## Source

- [GitHub](https://github.com/UsefulSoftwareCo/executor): source for the integration layer, plugins, and hosts.

## Community

- [Discord](https://discord.gg/eF29HBHwM6): support and discussion.
Loading