From 6ca009a97b256c5f3c459302a4757024e1013088 Mon Sep 17 00:00:00 2001 From: Nikhil Unni Date: Thu, 29 Oct 2026 07:57:55 -0700 Subject: [PATCH 1/4] site: one category phrase, the open source, self-hosted software factory The site, the README, and the docs described engrams three ways. Use one phrase everywhere, name Devin and Factory.ai as the alternatives, and keep E2B, Modal, and Inspect as the sandbox-layer comparison. The landing page also states the product, its maker, and its repository as schema.org JSON-LD. Co-Authored-By: Claude Opus 5.5 --- README.md | 6 ++- site/astro.config.mjs | 2 +- .../docs/docs/getting-started/overview.md | 5 +- site/src/landing/copy.ts | 2 +- site/src/layouts/Marketing.astro | 10 ++-- site/src/pages/index.astro | 48 ++++++++++++++++++- 6 files changed, 62 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b20677c6f..2c8823251 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,11 @@ [![Release](https://img.shields.io/github/v/release/cortexapps/engrams?filter=v*&label=release)](https://github.com/cortexapps/engrams/releases/latest) -engrams is a self-hosted orchestrator for AI coding agents. It runs each agent in its own [Firecracker](https://github.com/firecracker-microvm/firecracker) microVM, snapshots the VM when the agent goes idle, and restores it when the next prompt arrives. +engrams is the open source, self-hosted software factory, by [Cortex](https://www.cortex.io). It is an open source alternative to Devin and Factory.ai that runs in your own cloud. It runs Claude Code, Codex, or your own agent, each in its own [Firecracker](https://github.com/firecracker-microvm/firecracker) microVM, snapshots the VM when the agent goes idle, and restores it when the next prompt arrives. -A session is a plain OCI image plus an agent harness. You build the image with `docker build`, enable it once, and engrams boots it on a host in your own cloud, streams the transcript and tool calls to the dashboard, Slack, or the CLI, and snapshots the VM away when it goes quiet. Claude Code and Codex ship as harnesses. The pattern is the one behind hosted sandbox products like E2B, Modal Sandboxes, and Ramp's Inspect; engrams is the version you run yourself. +A session is a plain OCI image plus an agent harness. You build the image with `docker build`, enable it once, and engrams boots it on a host in your own cloud, streams the transcript and tool calls to the dashboard, Slack, or the CLI, and snapshots the VM away when it goes quiet. Claude Code and Codex ship as harnesses. The sandbox layer is the pattern behind hosted products like E2B, Modal Sandboxes, and Ramp's Inspect; engrams is the version you run yourself. + +Docs: [engramsfactory.com/docs](https://engramsfactory.com/docs/). For agents: [llms.txt](https://engramsfactory.com/llms.txt), and [install engrams with a coding agent](https://engramsfactory.com/docs/getting-started/install-with-an-agent/). ![A session in the engrams dashboard. Asked for a PNG of a pelican riding a bicycle with no image libraries and no internet, the agent wrote a PNG encoder in Python and shared the file in the thread.](site/src/assets/screenshots/session-pelican.png) diff --git a/site/astro.config.mjs b/site/astro.config.mjs index 2b2fa9a68..882a2387a 100644 --- a/site/astro.config.mjs +++ b/site/astro.config.mjs @@ -33,7 +33,7 @@ export default defineConfig({ integrations: [ starlight({ title: "engrams", - description: "Self-hosted sandboxes for AI coding agents, on Firecracker microVMs.", + description: "engrams is the open source, self-hosted software factory. It runs coding agents in Firecracker microVMs in your own cloud.", logo: { src: "./src/assets/engram-trace.svg", alt: "" }, favicon: "/favicon.ico", head: [ diff --git a/site/src/content/docs/docs/getting-started/overview.md b/site/src/content/docs/docs/getting-started/overview.md index 6c2813dfc..9cfda8346 100644 --- a/site/src/content/docs/docs/getting-started/overview.md +++ b/site/src/content/docs/docs/getting-started/overview.md @@ -5,8 +5,9 @@ sidebar: order: 1 --- -engrams is an open-source system that runs AI coding agents in isolated microVMs on your own -infrastructure. It gives people one place to direct their work: start a task, inspect its +engrams is the open source, self-hosted software factory. It runs AI coding agents in isolated +microVMs on your own infrastructure, as an open source alternative to Devin and Factory.ai. It +gives people one place to direct their work: start a task, inspect its changes, and continue the conversation from the dashboard or Slack. Turn repeat work into an automation that starts on a schedule or an event. diff --git a/site/src/landing/copy.ts b/site/src/landing/copy.ts index 0c22c694f..994c4b7f9 100644 --- a/site/src/landing/copy.ts +++ b/site/src/landing/copy.ts @@ -4,7 +4,7 @@ // Each section connects an outcome to the product behavior that makes it possible. export const hero = { - eyebrow: "Stand up a software factory of your own", + eyebrow: "The open source, self-hosted software factory", title: "The open source alternative to", titleAccent: "Devin.", lede: "engrams runs Claude Code, Codex, or your own agent in an isolated microVM on your infrastructure. Start one from a prompt, a schedule, a pull request, or a Slack thread. Walk away mid-task, and pick it up days later with its files and history intact.", diff --git a/site/src/layouts/Marketing.astro b/site/src/layouts/Marketing.astro index fe3700576..10fcdc3b1 100644 --- a/site/src/layouts/Marketing.astro +++ b/site/src/layouts/Marketing.astro @@ -14,8 +14,11 @@ interface Props { /** The landing page runs its own cover hero under the header and its own * Start band above the footer, so it asks the layout to leave both edges open. */ landing?: boolean; + /** schema.org JSON-LD for the page, so search engines and assistants read + * what the product is and who makes it from the page itself. */ + structuredData?: Record; } -const { title, description, landing = false } = Astro.props; +const { title, description, landing = false, structuredData } = Astro.props; const base = import.meta.env.BASE_URL.replace(/\/$/, ""); const canonical = new URL(Astro.url.pathname, Astro.site); // In the header on wide screens, and in the menu on narrow ones. @@ -53,9 +56,10 @@ const ogImage = new URL(`${base}/og.png`, Astro.site); - + + {structuredData && diff --git a/site/src/content/docs/docs/index.mdx b/site/src/content/docs/docs/index.mdx index 9f673cca8..72f0c9c16 100644 --- a/site/src/content/docs/docs/index.mdx +++ b/site/src/content/docs/docs/index.mdx @@ -47,5 +47,8 @@ import HudCard from "../../../components/docs/HudCard.astro"; -If you are reading these docs as an agent, every page is Markdown in the repository under -`site/src/content/docs/docs/`, and the [source on GitHub](https://github.com/cortexapps/engrams/tree/main/site/src/content/docs/docs) is the same text as this site. +If you are reading these docs as an agent, every page is also plain Markdown: put `.md` in +place of the trailing slash, or use the copy markdown button on the page. The index of every +page is at [llms.txt](../llms.txt), and all the docs in one file are at +[llms-full.txt](../llms-full.txt). To install engrams, start with +[Install engrams with a coding agent](getting-started/install-with-an-agent/). diff --git a/site/src/lib/markdown.ts b/site/src/lib/markdown.ts new file mode 100644 index 000000000..8cad64b9d --- /dev/null +++ b/site/src/lib/markdown.ts @@ -0,0 +1,94 @@ +// The docs as plain Markdown, for agents and for the llms.txt files. Each docs +// page is served next to its HTML at .md, and /llms-full.txt is every +// page joined in sidebar order. +import { getCollection, type CollectionEntry } from "astro:content"; + +type Doc = CollectionEntry<"docs">; + +// The sidebar groups in the order astro.config.mjs lists them. The docs home +// has no directory and comes first. +const SECTIONS = [ + ["getting-started", "Getting started"], + ["platform", "Platform"], + ["concepts", "Concepts"], + ["guides", "Guides"], + ["reference", "Reference"], + ["api", "API reference"], + ["contributing", "Contributing"], +] as const; + +export const base = import.meta.env.BASE_URL.replace(/\/$/, ""); + +/** The page's HTML URL path, for example `/docs/getting-started/faq/`. */ +export const pagePath = (doc: Doc) => `${base}/${doc.id}/`; + +/** The page's Markdown URL path, for example `/docs/getting-started/faq.md`. */ +export const markdownPath = (doc: Doc) => `${base}/${doc.id}.md`; + +export const isHome = (doc: Doc) => doc.id === "docs"; + +const sectionOf = (doc: Doc) => doc.id.split("/")[1] ?? ""; + +/** Every docs page grouped by sidebar section, each group in sidebar order. */ +export async function sections(): Promise<{ label: string; docs: Doc[] }[]> { + const docs = (await getCollection("docs")).filter((d) => !d.data.draft); + const order = (d: Doc) => d.data.sidebar.order ?? Number.MAX_SAFE_INTEGER; + return SECTIONS.map(([dir, label]) => ({ + label, + docs: docs + .filter((d) => sectionOf(d) === dir) + .sort((a, b) => order(a) - order(b) || a.data.title.localeCompare(b.data.title)), + })).filter((s) => s.docs.length > 0); +} + +export const SUMMARY = + "engrams is the open source, self-hosted software factory. It runs Claude Code, Codex, or your own coding agent in a Firecracker microVM in your own cloud, starts work from a prompt, a schedule, a pull request, a Slack thread, or a webhook, and snapshots idle sessions to object storage. It is an open source alternative to Devin and Factory.ai, made by Cortex."; + +/** The llms.txt index: what engrams is, then a link and a line for every page. */ +export async function llmsIndex(site: URL): Promise { + const abs = (path: string) => new URL(path, site).href; + const link = (doc: Doc) => + `- [${doc.data.title}](${abs(markdownPath(doc))})${doc.data.description ? `: ${doc.data.description}` : ""}`; + const groups = await sections(); + const main = groups.filter((g) => g.label !== "API reference" && g.label !== "Contributing"); + const optional = groups.filter((g) => !main.includes(g)); + const out = [ + "# engrams", + "", + `> ${SUMMARY}`, + "", + "Every docs page is plain Markdown at its URL with `.md` in place of the trailing slash. The links below point at the Markdown. All the docs in one file are at " + + `${abs(`${base}/llms-full.txt`)}.`, + "", + `If you are a coding agent asked to install engrams, start with ${abs(`${base}/docs/getting-started/install-with-an-agent.md`)}.`, + "", + "## Overview", + "", + `- [engrams](${abs(`${base}/`)}): The landing page: what engrams does and who it is for.`, + `- [engrams vs Devin, Factory, and other options](${abs(`${base}/compare/`)}): How engrams compares to hosted coding agents and sandbox products, and when to pick each.`, + `- [Architecture](${abs(`${base}/architecture/`)}): The processes, the external services, and the storage design.`, + `- [Source code](https://github.com/cortexapps/engrams): The repository on GitHub.`, + ]; + for (const g of main) out.push("", `## ${g.label}`, "", ...g.docs.map(link)); + out.push("", "## Optional"); + for (const g of optional) out.push("", ...g.docs.map(link)); + return `${out.join("\n")}\n`; +} + +/** + * The page body as Markdown that stands on its own: relative links made + * absolute against the page URL, and images replaced by their alt text (the + * build hashes image paths, so the source path leads nowhere). + */ +export function pageMarkdown(doc: Doc, site: URL): string { + const page = new URL(pagePath(doc), site); + const body = (doc.body ?? "") + .replace(/!\[([^\]]*)\]\([^)]*\)/g, (_, alt: string) => (alt ? `(Image: ${alt})` : "")) + .replace(/\]\(([^)\s]+)\)/g, (m, target: string) => + /^(?:[a-z]+:|#)/i.test(target) ? m : `](${new URL(target, page).href})`, + ); + const head = [`# ${doc.data.title}`, ""]; + if (doc.data.description) head.push(`> ${doc.data.description}`, ""); + head.push(`Source: ${page.href}`, ""); + return `${head.join("\n")}\n${body.trim()}\n`; +} diff --git a/site/src/pages/[...slug].md.ts b/site/src/pages/[...slug].md.ts new file mode 100644 index 000000000..6fdf1799b --- /dev/null +++ b/site/src/pages/[...slug].md.ts @@ -0,0 +1,15 @@ +// Each docs page as Markdown at .md, for agents and for "copy as +// Markdown". The docs home is cards in MDX, so its Markdown is the llms.txt index. +import type { APIRoute, GetStaticPaths } from "astro"; +import { getCollection, type CollectionEntry } from "astro:content"; +import { isHome, llmsIndex, pageMarkdown } from "../lib/markdown"; + +export const getStaticPaths = (async () => + (await getCollection("docs")) + .filter((doc) => !doc.data.draft) + .map((doc) => ({ params: { slug: doc.id }, props: { doc } }))) satisfies GetStaticPaths; + +export const GET: APIRoute<{ doc: CollectionEntry<"docs"> }> = async ({ props, site }) => { + const text = isHome(props.doc) ? await llmsIndex(site!) : pageMarkdown(props.doc, site!); + return new Response(text, { headers: { "Content-Type": "text/markdown; charset=utf-8" } }); +}; diff --git a/site/src/pages/llms-full.txt.ts b/site/src/pages/llms-full.txt.ts new file mode 100644 index 000000000..47baa511b --- /dev/null +++ b/site/src/pages/llms-full.txt.ts @@ -0,0 +1,10 @@ +// Every docs page as Markdown in one file, in sidebar order, for an agent that +// wants the whole manual in one request. +import type { APIRoute } from "astro"; +import { SUMMARY, pageMarkdown, sections } from "../lib/markdown"; + +export const GET: APIRoute = async ({ site }) => { + const pages = (await sections()).flatMap((s) => s.docs).map((d) => pageMarkdown(d, site!)); + const text = [`# engrams\n\n> ${SUMMARY}\n`, ...pages].join("\n---\n\n"); + return new Response(text, { headers: { "Content-Type": "text/plain; charset=utf-8" } }); +}; diff --git a/site/src/pages/llms.txt.ts b/site/src/pages/llms.txt.ts new file mode 100644 index 000000000..e927e5280 --- /dev/null +++ b/site/src/pages/llms.txt.ts @@ -0,0 +1,7 @@ +// The llms.txt index (https://llmstxt.org): what engrams is, and a link to the +// Markdown of every docs page. +import type { APIRoute } from "astro"; +import { llmsIndex } from "../lib/markdown"; + +export const GET: APIRoute = async ({ site }) => + new Response(await llmsIndex(site!), { headers: { "Content-Type": "text/plain; charset=utf-8" } }); diff --git a/site/src/pages/robots.txt.ts b/site/src/pages/robots.txt.ts new file mode 100644 index 000000000..f642f997c --- /dev/null +++ b/site/src/pages/robots.txt.ts @@ -0,0 +1,11 @@ +// Every crawler may read the whole site, AI crawlers included. The sitemap +// lists every page; Starlight writes it when `site` is set. +import type { APIRoute } from "astro"; + +export const GET: APIRoute = ({ site }) => { + const base = import.meta.env.BASE_URL.replace(/\/$/, ""); + const sitemap = new URL(`${base}/sitemap-index.xml`, site).href; + return new Response(`User-agent: *\nAllow: /\n\nSitemap: ${sitemap}\n`, { + headers: { "Content-Type": "text/plain; charset=utf-8" }, + }); +}; diff --git a/site/src/styles/starlight.css b/site/src/styles/starlight.css index 6a9c31901..6790b79b4 100644 --- a/site/src/styles/starlight.css +++ b/site/src/styles/starlight.css @@ -351,10 +351,22 @@ site-search button[data-open-modal] { text-transform: uppercase; opacity: 0.75; } -.doc-meta .edit { +.doc-meta .doc-links { + display: flex; + gap: 16px; margin-left: auto; +} +.doc-meta .doc-links a, +.doc-meta .doc-links button { + padding: 0; + border: 0; + background: none; color: var(--ring); + font: inherit; + letter-spacing: inherit; + text-transform: inherit; text-decoration: none; + cursor: pointer; } .doc-eyebrow { display: flex; From c4647f25c7db5166f2637c5a99230dc67ce6c676 Mon Sep 17 00:00:00 2001 From: Nikhil Unni Date: Thu, 29 Oct 2026 07:57:55 -0700 Subject: [PATCH 4/4] site: compare against the other options, and call it open source The compare page adds OpenHands, Claude Code self-hosted environments, Cursor self-hosted cloud agents, Codex cloud, E2B, and Modal, with who runs the control plane and when to pick each. The Devin row now says that its VPC option is one Cognition manages. The FAQ and the table say open source and do not name the license. Co-Authored-By: Claude Opus 5.5 --- .../content/docs/docs/getting-started/faq.md | 6 +- site/src/pages/compare.astro | 57 +++++++++++++++++-- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/site/src/content/docs/docs/getting-started/faq.md b/site/src/content/docs/docs/getting-started/faq.md index e4a9b3217..cefa89966 100644 --- a/site/src/content/docs/docs/getting-started/faq.md +++ b/site/src/content/docs/docs/getting-started/faq.md @@ -66,6 +66,8 @@ migrating a session. A cold start from an image's base snapshot is under a secon pre-warmed pool. These are the numbers from the reference deployment; measure your own fleet before you promise them to anyone. -## What is the license? +## Is it open source? -engrams is free software under the GNU Affero General Public License v3.0. +Yes. The whole system is open source on [GitHub](https://github.com/cortexapps/engrams): the +control plane, the host agent, the dashboard, the CLI, and the Firecracker fork. You can read, +change, and run every line. diff --git a/site/src/pages/compare.astro b/site/src/pages/compare.astro index d46d136bf..7d8ed6ceb 100644 --- a/site/src/pages/compare.astro +++ b/site/src/pages/compare.astro @@ -6,10 +6,10 @@ const docs = `${base}/docs`; // Vendor columns come from the vendors' public product and pricing pages. Keep // them to what those pages state, and update the "as of" line when you revise. -const asOf = "September 2026"; +const asOf = "October 2026"; const rows: [string, string, string, string][] = [ - ["Who runs it", "You, in your own cloud account or on your own hardware", "Cognition; VPC deployment on Enterprise contracts", "Factory; on-premise deployment on Enterprise contracts"], - ["Source code", "Open source. Read it, change it, and run every line (AGPL-3.0)", "Proprietary", "Proprietary"], + ["Who runs it", "You, in your own cloud account or on your own hardware", "Cognition; on Enterprise, a single-tenant VPC that Cognition manages", "Factory; on-premise and air-gapped options on Enterprise contracts"], + ["Source code", "Open source. Read it, change it, and run every line", "Proprietary", "Proprietary"], ["The agent", "Claude Code, Codex, or your own harness, mounted by the host at boot; never baked into your image", "Devin, Cognition's agent", "Droids, Factory's agent"], ["Models", "Whatever your harness calls, on your own provider keys or model router", "From Cognition's model list", "From Factory's model list"], ["Where the work runs", "A Firecracker microVM per session, on your KVM nodes", "A vendor-managed cloud machine per session", "Vendor-managed cloud machines, or your machine through the CLI"], @@ -19,11 +19,21 @@ const rows: [string, string, string, string][] = [ ["Where people work", "Dashboard, Slack threads, GitHub pull request review, CLI, API", "Web app, desktop app, CLI, Slack, Linear", "CLI, IDE, web app, Slack, Linear"], ["What you pay", "No license fee. You pay your cloud provider and your model provider", "Per-seat plans with usage quotas", "Per-seat plans with usage limits"], ]; + +// The other places a team looks. The same sourcing rule applies. +const others: [string, string, string, string][] = [ + ["OpenHands", "Open source agent and runtime; the hosted cloud, or self-hosted on Teams and Enterprise plans", "Docker containers", "You want the OpenHands agent itself, and container isolation is enough"], + ["Claude Code self-hosted environments", "Anthropic runs the control plane and stores transcripts; runners on your hosts do the work (Team and Enterprise, beta)", "Your hosts; isolation is yours to set up", "You use only Claude and accept a control plane at Anthropic"], + ["Cursor self-hosted cloud agents", "Cursor runs the agent loop and inference; your workers run commands and edits (team pools on Enterprise)", "Your machines or Kubernetes pods", "Your team works in Cursor and accepts a control plane at Cursor"], + ["OpenAI Codex cloud", "OpenAI runs everything", "OpenAI-hosted environments", "You pay for ChatGPT, and hosted execution is acceptable"], + ["E2B", "A sandbox SDK, not an agent product; open source infrastructure, or E2B runs it in your account", "Firecracker microVMs", "You are building your own agent product and need only the sandbox layer"], + ["Modal Sandboxes", "Modal runs everything", "gVisor containers or VMs, with GPUs", "You want serverless sandboxes with GPUs and no infrastructure to run"], +]; ---
@@ -57,7 +67,42 @@ const rows: [string, string, string, string][] = [
-
Sec. 1When to pick the others
+
Sec. 1Other options
+
+

Where else teams look.

+
+

+ "Self-hosted" means different things. For most products below, the vendor keeps the + control plane: the agent loop, the session record, and often the transcripts. Only the + execution runs on your machines. engrams runs all of it in your account: the + orchestration, the database, the VMs, and the snapshots. +

+
+
+
+ + + + + + + + + + + {others.map((r) => ( + {r.map((c) => )} + ))} + +
Who runs whatWhere the work runsPick it when
{c}
+
+

From each vendor's public docs and pricing pages as of {asOf}. Plans change; check with each vendor.

+
+
+ +
+
+
Sec. 2When to pick the others

Pick the other thing when it fits.