# How Extensions Manifest and Projection Work in OpenWork Den: A Complete Technical Guide

> Understand how OpenWork Den extensions manifest and project with a technical guide. Learn about JSON manifest generation and policy-filtered projection via MCP endpoints. Explore the different-ai/openwork repository.

- Repository: [Different AI/openwork](https://github.com/different-ai/openwork)
- Tags: deep-dive
- Published: 2026-08-09

---

**OpenWork Den manages extensions through a two-phase workflow: JSON manifest generation stored in the Den database, followed by policy-filtered projection to desktop clients via MCP endpoints.**

The `different-ai/openwork` repository implements a centralized extension management system where OpenWork Den acts as the control plane for all plugins, MCPs, and skills. Understanding how extensions manifest and projection work is essential for developers building custom integrations or deploying self-hosted instances.

## What Is the OpenWork Den Extensions Manifest?

Every extension in OpenWork Den is described by a **JSON manifest** that lives in the Den database. This manifest contains the extension's ID, name, version, description, capabilities, commands, MCP endpoints, and policy flags distinguishing *built-in* from *local* extensions.

When an organization admin publishes an extension, the backend writes the manifest to the `extensions` table. Den exposes this data through the REST API endpoint `/api/v1/extensions/manifest?<orgId>=…`, returning a JSON payload that matches the client's expected schema.

## The Manifest Generation Phase

### Publishing Extension Metadata

Administrators upload extension manifests via the Den UI or API. The manifest captures critical metadata including version constraints and capability declarations. The UI component in `ee/apps/den-web/app/(den)/dashboard/_components/extensions-download-promo.tsx` advertises the download-manifest link to users, connecting the web dashboard to the desktop client ecosystem.

### CLI Retrieval and Validation

The desktop client uses the bootstrap CLI to fetch manifests. In `packages/openwork-bootstrap/bin/openwork.mjs`, the tool performs a `fetch` against the manifest endpoint and validates the response. If the fetch fails, the CLI throws a `manifest_fetch_failed` error, preventing corrupted or unreachable extensions from entering the system.

## The Projection Phase: From Server to UI

### Fetching Capabilities via MCP

Once manifests are stored, clients retrieve them through the Den MCP endpoint `search_capabilities` → `extensions`. This RPC call returns the current manifest data to any OpenWork-compatible agent or desktop client.

### Policy Filtering and Schema Validation

Before rendering, the client validates the manifest against a **Zod schema** defined in [`packages/types/src/openwork-context.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/openwork-context.ts). The projection logic merges the fetched manifest with built-in extensions, then applies **desktop policies** from [`packages/types/src/den/desktop-policies.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/den/desktop-policies.ts). These policies—including `allowExtensions` and `allowBuiltInExtensions`—prune disallowed extensions from the final list.

### Rendering the Extensions Interface

The filtered projection populates three key UI areas: the **Extensions** settings page, the **Marketplace**, and the **Connect** tab. When users navigate to `route.settings.extensions`, the client invokes `window.__openworkControl.execute('extensions.refresh-marketplace')` to trigger a fresh fetch. The `ee/apps/den-web/app/(den)/dashboard/_components/org-dashboard-shell.tsx` component conditionally renders the *Extensions* navigation item when the user has admin rights, as documented in `packages/docs/start-here/add-an-mcp-server.mdx`.

## Step-by-Step Workflow

The complete lifecycle follows these five stages:

1. **Publish** – An admin uploads a manifest (JSON) via the Den UI or API. The backend stores it in the `extensions` table.
2. **Serve** – Den exposes the manifest at `/api/v1/extensions/manifest?<orgId>=…`.
3. **Fetch** – The desktop client runs `openwork extensions list` or calls the MCP `search_capabilities` RPC. Internally, `openwork-bootstrap` performs the HTTP fetch.
4. **Validate & Project** – The client validates the manifest against the Zod schema (`extension` kind) and merges it with built-in extensions. Desktop policies filter the results.
5. **Render** – The filtered list populates the Extensions UI, allowing users to install, enable, or disable extensions.

## Implementation Examples

Fetch and validate a manifest programmatically:

```typescript
const response = await fetch(manifestUrl);
if (!response.ok) throw new Error(`manifest_fetch_failed: ${response.status}`);
const manifest = await response.json();
validateManifest(manifest); // Zod schema in openwork-context.ts

```

List extensions via CLI:

```bash
openwork extensions list --json

```

React component consuming projected extensions:

```typescript
import { useExtensions } from '@/hooks/extensions';

export function ExtensionsPanel() {
  const { extensions, loading } = useExtensions(); // fetches + policy-filters
  if (loading) return <Spinner />;
  return (
    <ul>
      {extensions.map(ext => (
        <li key={ext.id}>
          {ext.name} – {ext.description}
        </li>
      ))}
    </ul>
  );
}

```

## Key Source Files

- **`ee/apps/den-web/app/(den)/dashboard/_components/extensions-download-promo.tsx`** – UI promoting desktop app downloads and manifest links.
- **`packages/openwork-bootstrap/bin/openwork.mjs`** – CLI implementation handling `manifest_fetch_failed` errors and validation.
- **[`packages/types/src/openwork-context.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/openwork-context.ts)** – Zod schema definitions for the `kind` field (`extensions`, `panel`, `voice`).
- **`ee/apps/den-web/app/(den)/dashboard/_components/org-dashboard-shell.tsx`** – Dashboard shell injecting the Extensions navigation for admins.
- **`packages/docs/start-here/add-an-mcp-server.mdx`** – Documentation on the Extensions page and client manifest consumption.
- **[`packages/types/src/den/desktop-policies.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/den/desktop-policies.ts)** – Policy definitions controlling extension visibility.

## Summary

- OpenWork Den uses a **centralized JSON manifest** stored in the `extensions` table to describe all available plugins and capabilities.
- The **manifest generation phase** occurs when admins publish extensions via the Den API or UI.
- **Projection** happens through MCP endpoints (`search_capabilities`) followed by client-side Zod validation and policy filtering (`allowExtensions`, `allowBuiltInExtensions`).
- The desktop client renders only policy-compliant extensions in the **Marketplace** and **Settings** interfaces.
- Key files include the bootstrap CLI (`openwork.mjs`), type definitions ([`openwork-context.ts`](https://github.com/different-ai/openwork/blob/main/openwork-context.ts)), and dashboard components ([`org-dashboard-shell.tsx`](https://github.com/different-ai/openwork/blob/main/org-dashboard-shell.tsx)).

## Frequently Asked Questions

### What format does the OpenWork Den extension manifest use?

The manifest uses **JSON** format containing fields for ID, name, version, description, capabilities, commands, MCP endpoints, and policy flags (built-in vs local). The client validates this structure against a Zod schema defined in [`packages/types/src/openwork-context.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/openwork-context.ts).

### How does the desktop client filter which extensions to display?

The client applies **desktop policies** defined in [`packages/types/src/den/desktop-policies.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/den/desktop-policies.ts), specifically checking `allowExtensions` and `allowBuiltInExtensions` flags. Only extensions passing these policy checks are projected into the UI.

### What happens if the manifest fetch fails?

The bootstrap CLI in `packages/openwork-bootstrap/bin/openwork.mjs` throws a `manifest_fetch_failed` error when the HTTP request to `/api/v1/extensions/manifest` fails or returns invalid data, preventing installation of corrupted extensions.

### Can non-admin users access the Extensions marketplace?

No. The [`org-dashboard-shell.tsx`](https://github.com/different-ai/openwork/blob/main/org-dashboard-shell.tsx) component conditionally renders the Extensions navigation item only when the user has admin rights. However, all users can view projected extensions in the desktop client's Connect tab if policies allow.