Ctrl K
ComunidadGuías…

packages/plugin-sdk/README.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# @multica/plugin-sdk

What a Multica plugin surface imports.

```js
import { multica } from "@multica/plugin-sdk";

const ctx   = await multica.context.get();
const issue = await multica.issue.get();
await multica.issue.comment({ body: "hello" });
const note  = await multica.storage.user.get("note");
multica.ui.resize(320);
```

## What a surface is

**One** script in a sandboxed iframe.

Bundle this SDK and everything else your surface needs into a single file. There
is no module graph: you publish an artifact, Multica stores it and serves your
entry inside a generated document on its dedicated plugin-content origin. There
is no path back to the author's server and no top-level module graph for a bare
`import` to resolve against. Publishing refuses an entry that has one rather
than letting it fail later in a reader's browser.

The frame is mounted with `sandbox="allow-scripts"` and **not**
`allow-same-origin`, so it has an opaque origin. Consequences worth knowing
before you write one:

- **No browser storage.** `localStorage`, `sessionStorage` and cookies all throw
  or are empty. Use `multica.storage` — it is server-side, scoped per workspace
  or per member, and survives the frame.
- **`Origin: null` on your own requests.** If your surface calls your backend
  directly, that backend must accept a null origin in CORS.
- **A CSP you did not write.** Multica generates the response and derives
  `connect-src` from the `net:` scopes in your manifest. Declare every host you
  intend to reach; with no `net:` scope your surface cannot issue a network
  request at all, including back to your own origin, which is no longer in the
  policy now that Multica serves your code. `net:` is an exact host, so declare
  `net:api.example.com` separately from `net:example.com`.

## Publishing

Zip the manifest with every file it names and upload it in **Settings →
Plugins**. You need no server of your own for the frontend; hook endpoints and
MCP servers are still yours to run.

A published version is immutable. Installing binds a workspace to one version,
and publishing a new one changes nothing there until an administrator upgrades —
so what they approved on the consent screen is what their browsers run.

## What you can do, and what bounds it

Every call becomes a message to the host, which performs it on the signed-in
user's own session. Two limits apply at once:

1. the scopes the workspace admin granted your plugin, and
2. what that particular user could already do themselves.

So a member without access to an issue gets a 404 through your surface too, and
a scope the admin declined is a 403 that names it. Errors are
`MulticaPluginError` with a `status` mirroring HTTP.

A comment you post is authored by **the user**, recorded as having been made
through your plugin. It does not run `@mention` trigger dispatch — a surface
cannot start agent runs as a side effect of posting text.

## Theme

The host pushes design tokens over the private port and again on every theme switch, and
the SDK writes them as custom properties on `:root`. Use `var(--foreground)`,
`var(--background)`, `var(--border)`, `var(--radius)` and friends and your
surface will look native without shipping a stylesheet.

`multica.ui.onThemeChange(fn)` if you need to react in JS.

## Sizing

The frame does not auto-size. Call `multica.ui.resize(px)` after your content
settles; the host clamps the value.