> For the complete documentation index, see [llms.txt](https://docs.holons.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.holons.io/software/federation.md).

# Federation (Core Domain)

The **`@holons/core/federation`** module is the implementation behind the [federation](/getting-started/glossary.md#federation) concept. It is the layer that takes an item from one holon and makes it visible in another—or to many others, or to a specific geographic cell—under the rules each side has set for itself.

This is distinct from [HoloSphere federation](/software/holosphere/federation.md), which is about **data sharing between spaces**. The core federation domain sits one level up: it decides *what gets published, to whom, and how* before HoloSphere is asked to propagate it.

## The mental model

Two questions answered by every federation publish:

1. **What's being published?** An item, wrapped in a **hologram**—a propagation-ready envelope with provenance metadata (`publishedAt`, source attribution, original `id`).
2. **Where is it going?** A **target**, expressed as one of three shapes:

| Target                         | When to use it                                                               |
| ------------------------------ | ---------------------------------------------------------------------------- |
| `{ kind: 'all' }`              | Broadcast to every federated partner — the default for general announcements |
| `{ kind: 'partner', holonId }` | Send to one specific partner holon                                           |
| `{ kind: 'hex', cell }`        | Drop into a geographic H3 cell (regional / bioregional flows)                |

Same operation, three reach patterns. A holon publishing a quest to its sibling co-op uses `partner`. A bioregional hub publishing observations to everyone in its region uses `hex`. A holon announcing a new offering uses `all`.

## The publish surface

```ts
function publishToFederation(
  ctx: PublishContext,
  target: PublishTarget,
  options?: PublishOptions
): Promise<PublishOutcome>
```

### `PublishContext`

What's being published:

```ts
interface PublishContext {
  holosphere: HoloSphere;
  holonId: string;     // home holon (the source)
  lens: string;        // which lens — tasks, expenses, …
  item: { id: string; [k: string]: any };
}
```

The `id` is **required**: the publisher needs a stable identifier so receivers can resolve the hologram back to its origin.

### `PublishOptions`

How to publish:

```ts
interface PublishOptions {
  /** Also write to settings.hex if one is configured. Default true. */
  includeSettingsHex?: boolean;

  /** Federation source identity (e.g. nostr pubkey). Defaults to `holonId`. */
  federationSourceId?: string;

  /** Called when a put is rejected by HoloSphere ACL. */
  onWriteDenied?: (info: {
    target: string;
    lens: string;
    message: string;
  }) => void;
}
```

`federationSourceId` is the escape hatch for holons that key federation off something other than the home holon ID—typically a Nostr public key. UIs resolve their identity layer and pass it in.

`onWriteDenied` is how the UI gets notified when a target rejects the publish for permission reasons. The publish doesn't abort on a single denial; it continues with the other destinations and records the denial in the outcome.

### `PublishOutcome`

What happened:

```ts
interface PublishOutcome {
  publishedTo: number;      // count of successful destinations
  destinations: string[];   // their IDs
  errors: string[];         // per-destination failures
  usedHolograms: boolean;
}
```

A publish never throws on a single bad destination; it accumulates errors and lets the caller decide how to surface them.

## Settings-hex integration

A holon can configure a **settings hex** — an H3 cell that acts as its public bulletin board. When `includeSettingsHex` is `true` (the default), every "publish to all" also drops the hologram into that cell.

This is what enables **geographically-keyed discovery**: a regional aggregator subscribed to the hex sees every published item from every member holon in its region without those holons needing to know about it individually.

`readSettingsHex(holosphere, holonId)` reads the configured cell for a given holon. If unset, the cell-write side of the publish is skipped silently.

## Snapshots

`getFederationSnapshot(holosphere, holonId, federationSourceId?)` is the read-only view of a holon's federation state:

```ts
interface FederationSnapshot {
  federated: string[];                     // partner IDs
  partnerNames: Record<string, string>;    // ID → display name
}
```

This is what powers UI lists ("who am I federated with?") and what `publishToFederation` itself consults when target is `{ kind: 'all' }`.

## The hologram pattern

Every publish wraps the source item in a **hologram** before propagating. The hologram includes:

* a copy of the item,
* the origin holon ID,
* the origin lens,
* a published-at timestamp,
* the federation source ID (often a Nostr pubkey).

Why wrap? Because the **same item** may be in the origin holon's lens **and** in a partner's lens **and** in a hex cell—and consumers downstream need to know which copy they're looking at, who published it, and whether updates should track back to a canonical source.

The caller is responsible for stamping the source item with `published` / `publishedAt` / `publishedTo` markers (this is intentional—UIs often want to update their own item rendering at the same moment). The hologram itself is computed inside `publishToFederation`.

## How permission denials surface

HoloSphere's federation uses ACLs at the destination: a partner can refuse writes to particular lenses. When the publisher hits a denial:

1. The error is detected by name (`AuthorizationError`) or message (`Write access denied`).
2. A short message is built (`Unable to publish to <prefix>… — no write permission for <lens>`).
3. The `onWriteDenied` callback fires (UIs use this to show a toast).
4. The denial goes into `PublishOutcome.errors` as a short string.
5. The publish continues to the remaining destinations.

This is what makes federation **safely best-effort**: a misconfigured partner doesn't block other partners from receiving the publish.

## MCP tool surface

The [MCP server](/software/mcp-server.md) exposes **3 tools** in the `federation` domain:

* `publish_to_federation` — the core publish, with full target/options support
* `get_federation_snapshot` — read partner list and names
* `read_settings_hex` — read the configured discovery cell

An MCP-connected agent can therefore make a holon publish, inspect its federation, and discover where its broadcasts land—all without UI involvement.

## See also

* [Glossary: federation](/getting-started/glossary.md#federation) — the protocol concept this implements
* [HoloSphere Federation](/software/holosphere/federation.md) — the substrate layer beneath this domain
* [Tasks](/software/tasks.md) — most publishes are Quests; the federation flow is the same shape
* [MCP Server](/software/mcp-server.md) — the tool surface


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.holons.io/software/federation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
