> ## Documentation Index
> Fetch the complete documentation index at: https://knitkit.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# knitkit Manifest Spec 0.1: knit.manifest.json Reference

> The knit.manifest.json format: top-level fields, exposes declarations, shared dependency declarations, URL resolution, and versioning rules.

A knitkit manifest (`knit.manifest.json`) is the JSON contract that a federated remote publishes for host applications to consume. It declares which modules the remote exposes for dynamic loading, which packages the remote shares (along with the exact versions and accepted ranges), and the URLs of the prebundled ESM assets for each. Host applications fetch manifests at boot, run version negotiation across all remotes, and emit a single native import map — the manifest is the data that drives every step of that process. The current spec version is `"0.1"`, and it is locked for Phase 1.

***

## Top-level shape

```json theme={null}
{
  "spec": "0.1",
  "name": "checkout",
  "exposes": { ... },
  "shared": { ... },
  "meta": { ... }
}
```

| Field     | Type    | Required | Notes                                                                                                                                                                               |
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `spec`    | `"0.1"` | yes      | Pins the manifest to a specific spec version. The runtime rejects any value other than `"0.1"`.                                                                                     |
| `name`    | string  | yes      | Lowercase alphanumeric identifier matching `[a-z][a-z0-9_-]*`. Used as the prefix in `loadRemote("<name>/<exposeKey>")` and must be unique across all registered remotes in a host. |
| `exposes` | object  | yes      | Map of expose key → `ExposeDecl`. An empty object is valid and means the remote shares packages but exposes no loadable modules.                                                    |
| `shared`  | object  | yes      | Map of package name → `SharedDecl`. An empty object is valid when the remote has no shared dependencies.                                                                            |
| `meta`    | object  | no       | Free-form metadata. Not validated. Suggested keys: `buildTime` (ISO 8601 string) and `framework` (e.g. `"react@18"`).                                                               |

***

## `exposes` object

The `exposes` map declares the modules this remote makes available for dynamic loading by host applications.

```json theme={null}
"exposes": {
  "./CartWidget": {
    "url": "./exposes/CartWidget.js",
    "types": "./types/CartWidget.d.ts"
  },
  "./CheckoutForm": {
    "url": "./exposes/CheckoutForm.js"
  }
}
```

### Key format

Expose keys must start with `./` (e.g. `"./CartWidget"`, `"./utils/format"`). This mirrors the ES module subpath convention and makes keys unambiguous relative paths. When calling `loadRemote`, you may omit the `./` prefix — `loadRemote("checkout/CartWidget")` and `loadRemote("checkout/./CartWidget")` resolve to the same module.

### `ExposeDecl` fields

| Field   | Type   | Required | Notes                                                                                                                                                                 |
| ------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`   | string | yes      | URL to the expose's ESM file. Relative URLs are resolved against the manifest's own URL at runtime. May be an absolute URL.                                           |
| `types` | string | no       | Path or URL to a `.d.ts` declaration file. Populated by `knitkit types generate`. Read by `knitkit types sync` on the host side to generate typed `loadRemote` calls. |

***

## `shared` object

The `shared` map declares the packages this remote contributes to cross-remote version negotiation. For each entry, knitkit selects a single winning version (or a scoped fallback for non-singletons) and maps the bare package name to its ESM URL in the import map.

```json theme={null}
"shared": {
  "react": {
    "version": "18.3.1",
    "requiredVersion": "^18.2.0",
    "singleton": true,
    "url": "./shared/react-18.3.1.js",
    "integrity": "sha384-..."
  }
}
```

### `SharedDecl` fields

| Field             | Type                  | Required | Default | Notes                                                                                                                                                                                               |
| ----------------- | --------------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `version`         | string (semver)       | yes      | —       | The exact version this participant contributes, e.g. `"18.3.1"`. Must be a valid `x.y.z` semver string.                                                                                             |
| `requiredVersion` | string (semver range) | yes      | —       | The range of versions this participant can accept at runtime. See supported range syntax below.                                                                                                     |
| `singleton`       | boolean               | no       | `true`  | Controls conflict behavior when no version satisfies every participant. See singleton semantics below.                                                                                              |
| `url`             | string                | yes      | —       | URL to the prebundled ESM asset for this package. Required by `negotiateShared` even though the TypeScript type marks it optional (the runtime throws `KNIT_ERR_MANIFEST_INVALID` if it is absent). |
| `integrity`       | string                | no       | —       | SRI hash in the format `sha384-<base64>`. Computed automatically by `knitkit build`. Enforcement is planned for Phase 2.                                                                            |

### Semver range syntax

The `requiredVersion` field supports the following range forms:

| Syntax                       | Example              | Meaning                                                             |
| ---------------------------- | -------------------- | ------------------------------------------------------------------- |
| Caret (`^`)                  | `^18.2.0`            | Compatible with; allows patch and minor bumps up to the next major. |
| Tilde (`~`)                  | `~18.2.0`            | Approximately equivalent; allows only patch bumps.                  |
| Greater than or equal (`>=`) | `>=18.0.0`           | Any version at or above the bound.                                  |
| Greater than (`>`)           | `>18.0.0`            | Any version strictly above the bound.                               |
| Less than or equal (`<=`)    | `<=18.3.1`           | Any version at or below the bound.                                  |
| Less than (`<`)              | `<19.0.0`            | Any version strictly below the bound.                               |
| Exact (`=` or bare)          | `18.3.1`             | Exactly this version only.                                          |
| X-range                      | `18.x`, `1.2.x`, `*` | Wildcard for the specified component.                               |

### Singleton semantics

* **`singleton: true` (default)** — the runtime expects every host and remote to share exactly one instance. If no version satisfies every participant's `requiredVersion`, negotiation throws `KNIT_ERR_SINGLETON_CONFLICT`. Use this for packages like React that break when multiple instances exist in one page.
* **`singleton: false`** — a participant whose required range cannot be satisfied by the negotiated winner is silently given its own copy via an import map `scopes` entry, so it loads its own version rather than sharing the winner's. The winner is still used by all compatible participants.

***

## URL resolution

All relative URL values — both `exposes[].url` and `shared[].url` — are resolved against the manifest's own URL using the standard `new URL(ref, manifestBaseUrl).toString()` algorithm. When `registerRemotes` fetches a manifest over HTTP, it uses the resolved response URL (after any redirects) as the base, so relative paths are always correct regardless of whether you passed a relative request path.

For inline manifests (where you pass a `Manifest` object directly rather than a URL string), relative URLs are left as-is and resolved from an empty base — use absolute URLs in inline manifests.

***

## Full example

The following is a complete, valid `knit.manifest.json` produced by `knitkit build` and `knitkit types generate` for a React-based checkout micro-frontend:

```json theme={null}
{
  "spec": "0.1",
  "name": "checkout",
  "exposes": {
    "./CartWidget": {
      "url": "./exposes/CartWidget.js",
      "types": "./types/CartWidget.d.ts"
    },
    "./CheckoutForm": {
      "url": "./exposes/CheckoutForm.js"
    }
  },
  "shared": {
    "react": {
      "version": "18.3.1",
      "requiredVersion": "^18.2.0",
      "singleton": true,
      "url": "./shared/react-18.3.1.js",
      "integrity": "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9r7jQfbYyF3sD5nK8n+dvY3nK0O2uP0kQ=="
    },
    "react-dom": {
      "version": "18.3.1",
      "requiredVersion": "^18.2.0",
      "singleton": true,
      "url": "./shared/react-dom-18.3.1.js",
      "integrity": "sha384-..."
    }
  },
  "meta": {
    "buildTime": "2026-06-12T18:00:00Z",
    "framework": "react@18"
  }
}
```

***

## Versioning

The `spec` field pins the manifest document to a specific revision of this specification. Changes to the spec follow these rules:

| Change type        | Examples                                                                                                        | Version bump                                   |
| ------------------ | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| **Breaking**       | Renaming a required field, removing a required field, changing a field's type, restricting an allowed value set | Major (e.g. `0.1` → `1.0`)                     |
| **Additive**       | New optional fields, new sibling keys under `exposes` or `shared`, new allowed `meta` keys                      | Minor (e.g. `0.1` → `0.2`)                     |
| **Clarifications** | Text edits, corrected examples, improved wording with no behavioral change                                      | Patch (no spec version change; changelog only) |

The runtime in `@knitkit/runtime` uses a strict equality check against the `spec` field (`m.spec !== "0.1"`), so a manifest with a future spec version will fail validation until the runtime is updated to accept it. Always keep the `@knitkit/runtime` and `@knitkit/cli` packages at matching versions to avoid spec skew.

***

## Validation

`@knitkit/runtime` exports `validateManifest(input, sourceLabel)` — the authoritative validator for this spec. It is the same function used by `registerRemotes` at runtime and by `knitkit validate` on the command line. It throws a `FedkitError` with code `KNIT_ERR_MANIFEST_INVALID` and a precise `.message` plus an actionable `.suggestion` on any validation failure. See the [Runtime API reference](/reference/runtime-api#validatemanifest-input-sourcelabel) for full details.
