Egglets

An Egglet is a first-class app that runs inside Egg. The platform provides storage, tools, an LLM router, Gateway services, cross-Egglet messaging, refs, credentials, and headless fetch through a single SDK surface. Each Egglet declares which of those it uses, and the runtime enforces that contract.

If you are familiar with progressive web apps, an Egglet is the closest analogy. The difference is that Egglets are not built on a sandboxed third-party origin: they are first-party code shipped with Egg, with direct access to a richer set of platform services than a browser can safely give a website. In return for that access, every Egglet ships a manifest that declares what it touches.

What is an Egglet

An Egglet is a self-contained app that ships inside Egg. Feed (the RSS and social aggregator), People (the contacts directory), Studio (the media generator), Explore (the research canvas), and Agent (the chat surface) are all Egglets. Each one owns a top-level route, has its own page in the chrome, shows up in the Eggs menu, and has a card in Settings.

You build an Egglet when you want to add a first-class app to Egg, not a website that runs in a tab. The user installs Egg and gets your Egglet alongside everything else.

When to use an Egglet

Both Egglets and ordinary web apps run on the user’s machine. The differences are about where they live, what services they get, and how the user finds them.

DimensionWeb appEgglet
Where it runsIn any browser, isolated by originOn the user’s hardware, inside Egg, with platform access
How users find itA URL, a bookmark, a search resultThe Eggs menu, the Egg landing page, a card in Settings
DistributionYou host and maintain it; the user visitsShips with Egg; updates with the app
Background workService Worker, subject to OS suspensionAlways-on pollers driven by the Gateway daemon, survive a closed window
Where data livesIndexedDB or localStorage in the browser, or your own backendLocal SQL on the user’s disk, never leaves the device unless the user opts into sync
LLM accessBring your own provider, your own API key, your own billingThe user’s configured model slot, often a local Ollama install with zero per-call cost and nothing leaving the machine
Network identityDatacenter IP from your server, or the user’s IP from a tabThe user’s real residential IP for both ctx.fetch and headless fetches, so sites do not block you as scraper traffic
Cross-app surfacespostMessage between same-origin framesTools the agent can call, IPC to other Egglets, shared @kind:id refs
AuthenticationCookies, OAuth flows you implementUser-authorized credential vault, accessed by declared source name

Pick a web app when your audience is the open web and the standard browser surface is enough. Pick an Egglet when the work has to happen on the user’s hardware: their disk holds the data, their machine runs the model (often a local Ollama install, no per-call cost, nothing leaves the device), and their browser does the fetching from a real residential IP that sites do not block as scraper traffic. The agent’s tool catalog, cross-Egglet refs, and cross-device sync are bonuses on top of that local-first foundation.

Chrome extensions answer a different question. They exist to modify other people’s websites in real time. An Egglet cannot do that, but it has a much bigger surface for everything else.

DimensionChrome extensionEgglet
Where it runsSandboxed inside someone else’s browser (Chrome, Edge, Brave)First-class app inside Egg, on the user’s hardware
Page injectionCan inject content scripts into any URL pattern the user grantsCannot inject. Page-level work goes through Browser Automation and the agent’s URL-pattern firewall
UI surfaceA popup, a sidebar, a devtools panel, optional new-tab overrideA full route in the chrome with its own page, its own card in Settings, its own place in the Eggs menu
Background workService worker, killed after about 30 seconds of idle under MV3Always-on pollers driven by the Gateway daemon, survive a closed window
DistributionChrome Web Store review, per-user installShips with Egg; updates with the app
API surfacechrome.* APIs, intentionally restricted; MV3 removed many capabilitiesctx.* SDK with structured storage, an LLM router, refs, IPC, credentials, and headless fetch
Storagechrome.storage with small quotas, or IndexedDBLocal SQL on the user’s disk, with optional cross-device sync
LLM accessBring your own API key, your own server, your own billingThe user’s configured slot, often a local Ollama install with zero per-call cost
Cross-app communicationchrome.runtime.sendMessage between extensions, rarely used in practiceEgglet IPC, shared refs, and a shared tool catalog. Designed for collaboration.

Pick a Chrome extension when your job is to modify other people’s websites in real time. That is the one thing Egglets cannot do. Pick an Egglet for everything else.

Structurally, an Egglet is a folder with a manifest.json and an index.ts. The host loads both at app launch, calls the entry’s activate(), and the Egglet registers its tools, mounts its page, and starts whatever work it needs. The next sections cover what goes in the manifest, what the runtime hands you, and the contract between the two.

What the platform provides

An Egglet receives a single ctx object on activation. Every backing it can reach is on that object.

SurfaceWhat it does
ctx.logTagged logger scoped to the Egglet’s id.
ctx.routesMount the Egglet’s top-level React view at its declared route.
ctx.toolsRegister named tools the agent or other Egglets can call.
ctx.storageRead and write the Egglet’s own tables. SQL placeholders resolve to physical names.
ctx.alwaysOnRegister pollers and other recurring work the platform drives.
ctx.fetchIn-process outbound HTTP through the platform’s HTTP client.
ctx.headlessHidden-browser page fetches for SPAs and login-walled feeds.
ctx.aiModel surface: text (chat / embed / rerank), image, audio, video.
ctx.eggletIpcFire-and-forget messaging between Egglets.
ctx.refsResolve and own @kind:id refs that travel between Egglets.
ctx.credentialsRead user-authorized credentials for declared sources.

Each surface has a corresponding declaration in the manifest’s uses block. The host refuses calls to surfaces the manifest did not declare.

Declaring what you use

Every Egglet’s manifest declares the platform surfaces it uses: which LLM slot, which Gateway services, whether it makes outbound HTTP, whether it sends messages to other Egglets. Those declarations live in a uses block at the top level of the manifest.

This is not a documentation hint. The host checks every ctx.* call at runtime and throws if the manifest did not declare the matching surface. An Egglet that calls ctx.fetch without uses.network.fetch fails on its first call with a clear error naming the field to add.

// Excerpt from a manifest that uses the LLM router and a daemon-driven scheduler.
{
  "id": "myEgglet",
  "version": "0.1.0",
  "label": "My Egglet",
  "route": "/my",
  "entry": "./index.ts",
  "uses": {
    "llm": { "role": "agent-secondary", "capability": "text" },
    "gateway": { "schedules": true, "writes": true }
  }
}

The reason for the rigor is user trust. When someone looks at an Egglet’s card in Settings, they should see a truthful picture of what it does, not a pinky-promise. Making every backing a declared field, then enforcing the declaration where the call happens, means the manifest is something the user (and the platform) can rely on without reading the code.

Full reference for every field in the uses block is on the Manifest page.

Quickstart

The smallest Egglet is a folder with two files. Create them under src/egglets/hello/.

// src/egglets/hello/manifest.json
{
  "id": "hello",
  "version": "0.1.0",
  "label": "Hello",
  "icon": "egg",
  "description": "Demo Egglet with a greeting tool.",
  "route": "/hello",
  "entry": "./index.ts"
}
// src/egglets/hello/index.ts
import { defineEgglet } from "@egg/sdk";

export default defineEgglet({
  async activate(ctx) {
    ctx.log.info("activated v" + ctx.manifest.version);

    ctx.routes.mount(() => import("./HelloPage"));

    ctx.tools.register<{ name?: string }, { greeting: string }>(
      "hello.greet",
      async ({ name } = {}) => ({
        greeting: `Hello, ${name ?? "world"}!`,
      }),
    );
  },
});
// src/egglets/hello/HelloPage.tsx
export default function HelloPage() {
  return <div>Hello from inside Egg.</div>;
}

That is a complete, working Egglet. On the next launch the host discovers manifest.json, calls activate(), mounts the page at /hello, and registers hello.greet as a callable tool. Settings shows the Egglet under the Egglets section, and the route is reachable from the Egg menu.

The example uses no platform backings beyond log, routes, and tools (none of which require a uses declaration). To call the LLM, write to a table, fetch a URL, or send a message to another Egglet, declare the corresponding entry under uses in the manifest first.

Where to go next

The Manifest page is the field-by-field reference, including the full uses block and validation rules. The SDK reference covers every ctx.* surface with signatures and examples. The Storage, Integrations, and Lifecycle pages go into specific topics in more depth.