Skip to content

Commit 510eb0a

Browse files
authored
Serve /blog and /llms.txt publicly instead of redirecting to login (#1201)
On executor.sh the cloud worker only proxies an allow-list of paths to the marketing worker; everything else falls through to the auth gate. /blog and /llms.txt were not on the list, so unauthenticated visits got redirected to /login?returnTo=..., and session replays show those visitors bouncing immediately (blog ~79%, llms.txt ~90%). Add both to the marketing allow-list. /blog already has marketing routes; add a real llms.txt under marketing/public describing the product and key links. Export isMarketingPath and cover the allow-list with a unit test.
1 parent 9394217 commit 510eb0a

3 files changed

Lines changed: 71 additions & 1 deletion

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { describe, expect, it } from "@effect/vitest";
2+
3+
import { isMarketingPath } from "./marketing";
4+
5+
// On executor.sh the marketing middleware proxies an allow-list of paths to the
6+
// `executor-marketing` worker; everything else falls through to the auth-gated
7+
// cloud app (the sign-in page). `/blog` and `/llms.txt` are public content, so
8+
// they must be on the allow-list: without it an unauthenticated visit redirects
9+
// to `/login?returnTo=...` and the reader bounces.
10+
describe("isMarketingPath", () => {
11+
const marketing = [
12+
"/home",
13+
"/privacy",
14+
"/terms",
15+
"/blog",
16+
"/blog/",
17+
"/blog/some-post",
18+
"/llms.txt",
19+
"/og-image.png",
20+
"/_astro/app.css",
21+
];
22+
for (const pathname of marketing) {
23+
it(`proxies ${pathname} to marketing`, () => {
24+
expect(isMarketingPath(pathname)).toBe(true);
25+
});
26+
}
27+
28+
// App-owned routes must reach the Effect handler, not marketing. `/blogger`
29+
// guards against a bare `startsWith("/blog")` swallowing unrelated words.
30+
const notMarketing = ["/", "/login", "/cloud", "/mcp", "/dashboard", "/blogger"];
31+
for (const pathname of notMarketing) {
32+
it(`leaves ${pathname} alone`, () => {
33+
expect(isMarketingPath(pathname)).toBe(false);
34+
});
35+
}
36+
});

apps/cloud/src/edge/marketing.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ const MARKETING_PATHS = [
1818
"/setup",
1919
"/privacy",
2020
"/terms",
21+
"/blog",
22+
"/llms.txt",
2123
"/api/detect",
2224
"/_astro",
2325
"/og-image.png",
2426
"/pattern-graph-paper.svg",
2527
];
2628

27-
const isMarketingPath = (pathname: string) =>
29+
export const isMarketingPath = (pathname: string) =>
2830
MARKETING_PATHS.some((p) => pathname === p || pathname.startsWith(`${p}/`));
2931

3032
const getMarketingWorker = () => env.MARKETING as { fetch: typeof fetch } | undefined;

apps/marketing/public/llms.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Executor
2+
3+
> 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.
4+
5+
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.
6+
7+
How it works:
8+
9+
- Add an integration: an MCP server, an OpenAPI spec, a GraphQL API, or a Google Discovery document.
10+
- Create a connection: one configured (optionally authenticated) instance of that integration. An integration can have many connections.
11+
- Set policies: decide whether each tool is always allowed, needs approval, or is blocked.
12+
- Use it from any MCP-compatible agent: one catalog of tools, shared across every client.
13+
14+
Run it your way: local CLI, a desktop app, hosted Executor Cloud, or self-hosted on Docker or Cloudflare.
15+
16+
## Docs
17+
18+
- [Documentation](https://executor.sh/docs): guides for adding integrations, connections, policies, and connecting agents over MCP.
19+
20+
## Product
21+
22+
- [Website](https://executor.sh): product overview and getting started.
23+
- [Pricing](https://executor.sh/#pricing): plans for Executor Cloud.
24+
- [Install](https://executor.sh/#install): install the CLI and connect your first agent.
25+
26+
## Source
27+
28+
- [GitHub](https://github.com/UsefulSoftwareCo/executor): source for the integration layer, plugins, and hosts.
29+
30+
## Community
31+
32+
- [Discord](https://discord.gg/eF29HBHwM6): support and discussion.

0 commit comments

Comments
 (0)