# Add Model Hub to your plugin

> Find the Hub, register your roles and make a first call, in about twenty lines.

With Model Hub, your plugin holds no keys and names no models. It declares the jobs it needs a model for, and the user decides which models serve them. Spend is credited to your plugin in the user's ledger.

## Before you start

- Model Hub is desktop only, so a plugin that requires it is too.
- The API's types aren't published as a package yet. Until they are, copy [`model-hub-api.d.ts`](https://insurgently.com/docs/model-hub/api/model-hub-api.d.ts) into your plugin: it is every public declaration in one file. `getHub` and `onHubReady` are a few lines each; copy them from [`api/index.ts`](https://github.com/Insurgent-Methods/model-hub/blob/HEAD/api/index.ts).

## Steps

1. **Find the Hub.** `getHub` checks that Model Hub is installed and that its API is new enough for you. If not, it gives a plain message to show the user.

   ```ts
   const found = getHub(this.app, '0.4.0');
   if (!found.hub) return new Notice(found.message);
   const hub = found.hub;
   ```

2. **Register your roles.** A role is named `namespace.name` in lowercase. The first plugin to use a namespace owns it. Each role names a tier (`balanced` if you name none).

   ```ts
   hub.registerRoles(this.manifest.id, [
     { name: 'mine.summarize', description: 'Summaries of a note', tier: 'quick' },
     { name: 'mine.embed', description: 'Vectors for search', tier: 'embedding' },
   ]);
   ```

3. **Make a call.** Pass `for` so the ledger says what the call was about.

   ```ts
   const r = await hub.complete('mine.summarize', [{ role: 'user', content: noteText }], { for: file.path });
   // r.text, r.usage, r.listedUsd, r.billedUsd, r.servedModel, r.fellBack …
   ```

4. **Handle refusals.** Every refusal or failure is an error with a `code` and a message written for the user.

   ```ts
   try {
     await hub.complete('mine.summarize', messages);
   } catch (e) {
     new Notice((e as Error).message); // e.code: 'over-ceiling', 'over-budget', 'provider-unavailable' …
   }
   ```

5. **Let the user remap your roles.** One call opens the Hub's role editor for your plugin, so you have no model settings to build.

   ```ts
   hub.openRoleEditor(this.manifest.id);
   ```

## If the Hub is reloaded

The user may disable and enable Model Hub while your plugin runs. The new Hub fires `model-hub:ready` on the workspace. `onHubReady` runs your callback now and on every reload, so do your registration inside it:

```ts
onHubReady(this.app, this, '0.4.0', (hub) => {
  hub.registerRoles(this.manifest.id, MY_ROLES);
  hub.registerSkills(this.manifest.id, MY_SKILLS);
});
```

Registering roles again is harmless. Registered skills are lost on a reload, so they must be registered again.

## What you get

- Your roles show in **Settings → Model Hub → Roles** under your plugin's name.
- Every call is checked against the user's limits before it is sent, and recorded in the ledger with its cost.
- When a model fails, the Hub falls back along the user's own list and tells you (`fellBack`, `attempts`).

## Related

- [The API, call by call](api.md)
- [Refusal codes](errors.md)
- [API versions](versions.md)
