This is the full developer documentation for Superlibrary # The memory of the stack. > What agents made and what work was done, labelled with how each turned out. Agents consult it before they work; people browse it. ## One library, two kinds of item [Section titled “One library, two kinds of item”](#one-library-two-kinds-of-item) Artifacts Files and folders, uploaded by people or linked by agents through AgentPod. Versioned, secret-scanned on the way in, and shown in a sandboxed viewer on a separate origin. Work records Superpipeline work history, one record per card, kept current by signed push events. Outcomes Every item says how it turned out: approved, completed, in-progress, superseded, rejected, failed or abandoned. Search ranks good work first and never hides the rest. Four ways in The web app, the `suli` command line, an MCP server with three read-only tools, and an HTTP API. Superlibrary runs on Cloudflare Workers and signs people in through the SuperJackfruit account service. Start with [what it is](/what-it-is/), then [install `suli`](/install/). For agents, the same docs are published as plain text: [`/llms.txt`](/llms.txt) indexes them, and [`/llms-full.txt`](/llms-full.txt) is every page in one file. # HTTP API > Superlibrary's REST API under /api/v1. Authentication, and every route by group, with who may call it. The API is served at `/api/v1` on the app’s address (`https://app.superlibrary.dev/api/v1` on the hosted service; `http://localhost:8787` in [local development](/install/#local-development)). Requests and answers are JSON unless noted. ## Authentication [Section titled “Authentication”](#authentication) Send a bearer token from the organization’s sign-in: ```plaintext Authorization: Bearer ``` Tokens are verified against the account service as issuer and key set, for the audience of the Superlibrary app. `GET /.well-known/oauth-protected-resource` names the sign-in service; it is how `suli login` finds it. Routes say who may call them: * **person**: a signed-in member of the workspace. Agent tokens are refused. * **viewer**: a person or an agent. Agents see `workspace` items and the boards on their roster. * **operator**: a person listed in `OPERATORS`. * **service**: a signed service call (Superpipeline’s push, the AgentPod hub). An item the caller cannot see answers 404, never 403. Errors are `{"error": "", ...}`. ## Identity [Section titled “Identity”](#identity) | Route | Who | | | -------------------- | ------ | ---------------------------------------------------------------------------- | | `GET /api/v1/whoami` | viewer | `{kind, principalId}` | | `GET /api/v1/me` | person | `{kind, principalId, org, workspaceId, role}`; callable from embedding hosts | | `GET /api/health` | anyone | `{"ok": true, "service": "superlibrary-api"}` | ## Uploads [Section titled “Uploads”](#uploads) An upload is declared, filled, and committed. Nothing is in the library until the commit. | Route | Who | | | --------------------------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `POST /api/v1/uploads` | person, or the hub for an agent | Declare: `title`, `scope` (default `workspace`), optional `item` for a new version, `entry`, `expiresAt`, and `files` (each `path`, `bytes`, `sha256`). Path rules and size limits are checked here. | | `PUT /api/v1/uploads/{upl}/files?path=` | the uploader | Send one file’s bytes | | `POST /api/v1/uploads/{upl}/batch` | the uploader | Send up to 50 files and 8 MB in one multipart request | | `POST /api/v1/uploads/{upl}/override` | a person | `{"reason": "…"}` (1 to 500 characters) to override secret-scan findings; recorded | | `POST /api/v1/uploads/{upl}/commit` | the uploader | Commit. `422 secret_found` with the findings (file, line, rule) when the scan finds something not overridden. Answers `{itemId, version, url, sha256, mediaType, bytes}`. | See [Uploading](/use/uploading/) for the limits and the scan. ## Items [Section titled “Items”](#items) | Route | Who | | | ---------------------------------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `GET /api/v1/items?limit=&before=` | person | Items, newest first; `limit` 1 to 100, default 50 | | `GET /api/v1/items/{itm}` | person | The item and its versions | | `POST /api/v1/items/{itm}/embed` | person | Mint a signed viewer URL for a version (`{"version": n}` optional), valid five minutes. Answers an `EmbedGrant`; see [Embed](/build/embed/). | | `PATCH /api/v1/items/{itm}` | uploader or owner | `{"expiresAt": "" \| null}` | | `POST /api/v1/items/{itm}/revoke` | uploader or owner | Revoke the item, optional `{"reason": "…"}` | | `POST /api/v1/items/{itm}/versions/{n}/revoke` | uploader or owner | Revoke one version | | `POST /api/v1/items/{itm}/scope` | uploader or owner | `{"scope": "workspace"}`; widening only, recorded | | `GET /api/v1/items/{itm}/record` | person | A work record’s view: the record and the artifacts it links that the caller can see | ## Search and retrieval [Section titled “Search and retrieval”](#search-and-retrieval) | Route | Who | | | ------------------------------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------- | | `POST /api/v1/search` | viewer | `{query, kinds?, outcomes?, board?, agent?, station?, since?, until?, limit?}`; `limit` 1 to 25, default 10. Answers `{results}`. | | `GET /api/v1/library/{itm}?version=` | viewer | An item’s full text: `{item, text, wrapped}` | | `POST /api/v1/related` | viewer | `{cardId, text?}` or `{itemId}`, with optional `limit` (1 to 10) and `maxTokens` (100 to 4,000). Answers `{items}`. | Search and related answers carry a `Server-Timing` header. ## The library app [Section titled “The library app”](#the-library-app) These are the app’s routes. People only. | Route | | | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `POST /api/v1/browse` | Browse without words, newest activity first: the search filters plus `collection`, `limit` (1 to 100, default 50) and `cursor`. Answers `{items, next, counts}`, with a count per outcome. | | `GET /api/v1/facets` | The boards, agents and stations among items the caller can see | | `GET /api/v1/collections` | Every collection, with how many items in each the caller can see | | `POST /api/v1/collections` | Create one: `name`, optional `description` | | `GET /api/v1/collections/{col}` | One collection and its visible items | | `PATCH /api/v1/collections/{col}` | Rename or describe; creator or owner | | `DELETE /api/v1/collections/{col}` | Delete; creator or owner | | `POST /api/v1/collections/{col}/items` | Add an item, optional note | | `DELETE /api/v1/collections/{col}/items/{itm}` | Remove an item | | `POST /api/v1/items/{itm}/supersede` | `{"by": "itm_…" \| null}`; uploader or owner | | `PATCH /api/v1/items/{itm}/caption` | `{"caption": "…" \| null}`, up to 2,000 characters; artifacts only | | `POST /api/v1/items/{itm}/remove` | Remove from memory: `{"reason": "…"}`, 3 to 500 characters | ## Sources [Section titled “Sources”](#sources) | Route | Who | | | ------------------------------------------------- | ------------- | ----------------------------------------------------------- | | `POST /api/v1/sources/superpipeline/events` | Superpipeline | Record events, signed with HMAC-SHA-256 | | `POST /api/v1/sources/superpipeline/backfill` | operator | Read every board in full. `202 {"boards": N}` | | `GET /api/v1/sources/agentpod/items?station=` | person | Up to 200 live items linked from a station | | `POST /api/v1/roster/invalidate` | service | `{"principal": "prn_…"}`: an agent’s boards changed. `204`. | See [With Superpipeline and AgentPod](/use/with-superpipeline-and-agentpod/). ## Admin [Section titled “Admin”](#admin) Operators only. See [Retention and operations](/use/retention-and-operations/#operators). | Route | | | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `POST /api/v1/admin/index/reconcile` | `202 {"queued": N, "orphans": M}` | | `POST /api/v1/admin/index/reindex` | `{"embedder": ""}`; `409 reindex_running`, `409 slot_not_drained`, `400 dimension_mismatch`, `400 unknown_embedder` | | `POST /api/v1/admin/index/reindex/cancel` | `404 no_reindex` when none runs | | `POST /api/v1/admin/index/reindex/resume` | `404 no_reindex` when none runs | | `POST /api/v1/admin/search/explain` | A search query; answers `{results, candidates}` | ## Cross-origin calls [Section titled “Cross-origin calls”](#cross-origin-calls) Browsers may call the API from the origins in `EMBED_HOSTS` (the `me`, item, embed, scope and related routes) and `CONSOLE_ORIGINS` (the upload routes and the station-items list). See [Embed](/build/embed/#allowed-origins). # The suli CLI > Superlibrary from a terminal. Every suli command by group, the flags every command takes, the environment it reads, and how it signs in. `suli` is Superlibrary from a terminal; `superlibrary` is the same program under its full name. [Install](/install/#install-suli) has the installer. ```sh suli [] [--flags] [--json] suli help ``` `suli` is for people. An agent token is refused by every command that calls the server; agents use the [MCP tools](/build/mcp/) instead. ## Signing in [Section titled “Signing in”](#signing-in) | Command | What it does | | -------------------------------------------------- | --------------------------------- | | [`suli help`](/build/cli/session/#suli-help) | Every command, or one in full | | [`suli version`](/build/cli/session/#suli-version) | The version of suli | | [`suli skill`](/build/cli/session/#suli-skill) | Print or install the agent skill | | [`suli login`](/build/cli/session/#suli-login) | Sign in from this terminal | | [`suli logout`](/build/cli/session/#suli-logout) | Forget this terminal’s credential | | [`suli whoami`](/build/cli/session/#suli-whoami) | Who you are signed in as | ## Artifacts [Section titled “Artifacts”](#artifacts) | Command | What it does | | -------------------------------------------------- | ----------------------------- | | [`suli upload`](/build/cli/artifacts/#suli-upload) | Upload a file or a folder | | [`suli get`](/build/cli/artifacts/#suli-get) | Show an item and its versions | | [`suli revoke`](/build/cli/artifacts/#suli-revoke) | Revoke an item or one version | ## Finding and curating [Section titled “Finding and curating”](#finding-and-curating) | Command | What it does | | ---------------------------------------------------------------- | ----------------------------------- | | [`suli search`](/build/cli/library/#suli-search) | Search the library | | [`suli collect list`](/build/cli/library/#suli-collect-list) | Every collection in the workspace | | [`suli collect create`](/build/cli/library/#suli-collect-create) | Start a collection | | [`suli collect show`](/build/cli/library/#suli-collect-show) | The items in a collection | | [`suli collect add`](/build/cli/library/#suli-collect-add) | Add an item to a collection | | [`suli collect remove`](/build/cli/library/#suli-collect-remove) | Take an item out of a collection | | [`suli scope`](/build/cli/library/#suli-scope) | Show an item to the whole workspace | ## Flags every command takes [Section titled “Flags every command takes”](#flags-every-command-takes) | Flag | Meaning | | -------- | ----------------------------------------- | | `--json` | Print machine-stable JSON instead of text | | `--help` | Print this command’s help | Every command exits `0` on success and `1` on any failure. Each command’s page lists the reasons. ## Environment [Section titled “Environment”](#environment) | Variable | Meaning | | -------------------- | ------------------------------------------------------------ | | `SUPERLIBRARY_TOKEN` | a person’s token, used exactly as supplied and never renewed | | `SUPERLIBRARY_URL` | the server; default `https://app.superlibrary.dev` | | `XDG_CONFIG_HOME` | Linux: the config directory credentials live under | | `APPDATA` | Windows: the config directory credentials live under | Without `SUPERLIBRARY_URL`, `suli` talks to the hosted service, and `suli login` signs in through the SuperJackfruit account service. The command pages are generated from the CLI’s own command table, the same source as `suli help`. # Artifacts > suli upload, get and revoke: uploading files and folders, reading items and their versions, and revoking. Uploading files and folders, reading what is there, and revoking. Every upload passes the path rules, size caps and secret scan before anything is stored. ## `suli upload` [Section titled “suli upload”](#suli-upload) Checks every path against the rules (no `..`, no paths outside the folder, nothing on the denylist such as `.env*`, `.ssh/`, keys and credential files), checks the sizes (25 MB a file; 100 MB and 500 files a folder), then sends each file and commits. A secret found by the scan refuses the upload, naming the file and line; `--override` uploads it anyway and records your reason. ```sh suli upload [--title ] [--item ] [--board ] [--entry ] [--expires ] [--override ] ``` | argument | meaning | | -------- | ------------------ | | `` | A file or a folder | | flag | type | default | meaning | | ------------------------ | ------ | ----------------------------------------------- | -------------------------------------------------------------------- | | `--title ` | string | the file or folder name | What the item is called | | `--item ` | string | — | Upload as a new version of this item | | `--board ` | string | — | Scope it to a board (visible only to you until board access arrives) | | `--entry ` | string | index.html, then README.md, then the first file | The file a folder opens on | | `--expires ` | date | — | Delete it on this date (the start of that day, UTC) | | `--override ` | string | — | Upload despite a secret-scan finding; your reason is recorded | **Who may run it** * A person: a member of the workspace. * An agent token: refused. * Agents reach Superlibrary from a later release; an agent token is refused today. **Calls** `POST /api/v1/uploads`, `PUT /api/v1/uploads/:id/files`, `POST /api/v1/uploads/:id/override`, `POST /api/v1/uploads/:id/commit` **Prints** the item URL (and with –json the item id, version, SHA-256, type and size). **Exit status** `0` on success. `1` when: * a path is refused or a size is over its cap * the secret scan finds something and –override is not given * a symbolic link points outside the folder * there is no usable credential, or the server refuses it (401) or the act (403), or answers any other error **Example** ```sh suli upload report.md suli upload ./site --title "Launch page" --entry index.html suli upload notes.md --item itm_0123456789abcdef ``` ## `suli get` [Section titled “suli get”](#suli-get) Shows the item, its provenance and its versions. With `--embed`, also mints a signed viewer URL for one version, which works for five minutes (and is recorded as a view). ```sh suli get [--embed] [--version ] ``` | argument | meaning | | -------- | -------------------- | | `` | The item id (itm\_…) | | flag | type | default | meaning | | --------------- | ------- | ------- | -------------------------------------- | | `--embed` | boolean | — | Also mint a 5-minute signed viewer URL | | `--version ` | integer | — | The version for –embed | **Who may run it** * A person: a member of the workspace. * An agent token: refused. * Agents reach Superlibrary from a later release; an agent token is refused today. **Calls** `GET /api/v1/items/:id`, `POST /api/v1/items/:id/embed` **Prints** the item and its versions. **Exit status** `0` on success. `1` when: * the item does not exist or you cannot see it (404) * it is revoked or expired (410) * there is no usable credential, or the server refuses it (401) or the act (403), or answers any other error **Example** ```sh suli get itm_0123456789abcdef suli get itm_0123456789abcdef --embed --version 2 ``` ## `suli revoke` [Section titled “suli revoke”](#suli-revoke) Revokes at once: a viewer URL already handed out stops working immediately. Only the uploader or an owner of the workspace may. ```sh suli revoke [--version ] [--reason ] ``` | argument | meaning | | -------- | -------------------- | | `` | The item id (itm\_…) | | flag | type | default | meaning | | ----------------- | ------- | ------- | -------------------------------------------------------------------------- | | `--version ` | integer | — | Revoke only this version | | `--reason ` | string | — | Why; recorded when the whole item is revoked, so not allowed with –version | **Who may run it** * A person: the person who uploaded it, or an owner of the workspace. * An agent token: refused. * Agents reach Superlibrary from a later release; an agent token is refused today. **Calls** `POST /api/v1/items/:id/revoke`, `POST /api/v1/items/:id/versions/:n/revoke` **Prints** “Revoked.”. **Exit status** `0` on success. `1` when: * you are not the uploader or an owner (403) * there is no usable credential, or the server refuses it (401) or the act (403), or answers any other error **Example** ```sh suli revoke itm_0123456789abcdef --reason "posted by mistake" suli revoke itm_0123456789abcdef --version 2 ``` # Finding and curating > suli search, collect and scope: searching the library, keeping collections, and widening who can see an item. Searching the library with the same filters as the app, keeping collections, and widening who can see an item. Search shows only what you can see; collections and widening are a person’s acts and are recorded. ## `suli search` [Section titled “suli search”](#suli-search) Ranked results with their outcome: approved and completed work first, rejected and failed lower but never hidden. Only items you can see are searched, and none you cannot see is ever shown, even as a snippet. ```sh suli search [--kind ] [--outcome ] [--board ] [--agent ] [--station ] [--since ] [--until ] [--limit ] ``` | argument | meaning | | --------- | --------------------------------------------- | | `` | What to look for; several words are one query | | flag | type | default | meaning | | -------------------------------- | ------- | ------- | --------------------------------------------------------------------------------------------------------------- | | `--kind ` | string | — | Only artifacts, or only work records | | `--outcome ` | string | — | Only these outcomes, comma-separated: approved, completed, in-progress, superseded, rejected, failed, abandoned | | `--board ` | string | — | Only this board | | `--agent ` | string | — | Only items made by this agent | | `--station ` | string | — | Only items linked from this station | | `--since ` | date | — | Last activity on or after the start of this day, UTC | | `--until ` | date | — | Last activity on or before this day, UTC | | `--limit ` | integer | 10 | At most this many results (1 to 25) | **Who may run it** * A person: a member of the workspace. * Agents search through MCP (`library_search`), not through suli. **Calls** `POST /api/v1/search` **Prints** one line per result (id, outcome, title), its snippet and its replacement. **Exit status** `0` on success. `1` when: * a flag is not one of its values * there is no usable credential, or the server refuses it (401) or the act (403), or answers any other error **Example** ```sh suli search deploy checklist suli search launch post --outcome rejected,failed --since 2026-10-01 ``` ## `suli collect list` [Section titled “suli collect list”](#suli-collect-list) Lists the collections with how many items in each you can see. ```sh suli collect list ``` **Who may run it** * A person: a member of the workspace. * An agent token: refused. * Agents reach Superlibrary from a later release; an agent token is refused today. **Calls** `GET /api/v1/collections` **Prints** one line per collection. **Exit status** `0` on success. `1` when: * there is no usable credential, or the server refuses it (401) or the act (403), or answers any other error **Example** ```sh suli collect list ``` ## `suli collect create` [Section titled “suli collect create”](#suli-collect-create) Creates an empty collection. An artifact in a collection is kept however old it is. ```sh suli collect create [--description ] ``` | argument | meaning | | -------- | ----------------------------------------------------------- | | `` | The collection’s name; unique in the workspace, in any case | | flag | type | default | meaning | | ---------------------- | ------ | ------- | -------------- | | `--description ` | string | — | What it is for | **Who may run it** * A person: a member of the workspace. * An agent token: refused. * Agents reach Superlibrary from a later release; an agent token is refused today. **Calls** `POST /api/v1/collections` **Prints** “Created ().”. **Exit status** `0` on success. `1` when: * the name is taken (409) * there is no usable credential, or the server refuses it (401) or the act (403), or answers any other error **Example** ```sh suli collect create "Building in public — week 41" ``` ## `suli collect show` [Section titled “suli collect show”](#suli-collect-show) Shows the collection and the items in it you can see, newest added first. ```sh suli collect show ``` | argument | meaning | | -------------- | --------------------------- | | `` | Its id (col\_…) or its name | **Who may run it** * A person: a member of the workspace. * An agent token: refused. * Agents reach Superlibrary from a later release; an agent token is refused today. **Calls** `GET /api/v1/collections`, `GET /api/v1/collections/:id` **Prints** the collection and one line per item. **Exit status** `0` on success. `1` when: * no collection has that id or name * there is no usable credential, or the server refuses it (401) or the act (403), or answers any other error **Example** ```sh suli collect show "week 41" ``` ## `suli collect add` [Section titled “suli collect add”](#suli-collect-add) Any member may add an item they can see. While it is in a collection, an artifact is exempt from retention: a deployment that enforces it deletes artifacts nothing refers to after 30 days, and the shipped configuration only reports them. ```sh suli collect add [--note ] ``` | argument | meaning | | -------------- | --------------------------- | | `` | Its id (col\_…) or its name | | `` | The item id (itm\_…) | | flag | type | default | meaning | | --------------- | ------ | ------- | --------------------------- | | `--note ` | string | — | Why it is in the collection | **Who may run it** * A person: a member of the workspace. * An agent token: refused. * Agents reach Superlibrary from a later release; an agent token is refused today. **Calls** `GET /api/v1/collections`, `POST /api/v1/collections/:id/items` **Prints** “Added.”. **Exit status** `0` on success. `1` when: * the item does not exist or you cannot see it (404) * there is no usable credential, or the server refuses it (401) or the act (403), or answers any other error **Example** ```sh suli collect add "week 41" itm_0123456789abcdef --note "the launch post" ``` ## `suli collect remove` [Section titled “suli collect remove”](#suli-collect-remove) The item stays in the library; only the collection no longer holds it. ```sh suli collect remove ``` | argument | meaning | | -------------- | --------------------------- | | `` | Its id (col\_…) or its name | | `` | The item id (itm\_…) | **Who may run it** * A person: a member of the workspace. * An agent token: refused. * Agents reach Superlibrary from a later release; an agent token is refused today. **Calls** `GET /api/v1/collections`, `DELETE /api/v1/collections/:id/items/:item` **Prints** “Removed.”. **Exit status** `0` on success. `1` when: * there is no usable credential, or the server refuses it (401) or the act (403), or answers any other error **Example** ```sh suli collect remove "week 41" itm_0123456789abcdef ``` ## `suli scope` [Section titled “suli scope”](#suli-scope) Widens who can see an item from its board to everyone in the workspace, agents included. Recorded in the audit log. Only the uploader or an owner may; it cannot be undone. ```sh suli scope ``` | argument | meaning | | --------- | ----------------------------------------------------- | | `` | The item id (itm\_…) | | `` | workspace (the only value: an item is never narrowed) | **Who may run it** * A person: the person who uploaded it, or an owner of the workspace. * An agent token: refused. * Agents reach Superlibrary from a later release; an agent token is refused today. **Calls** `POST /api/v1/items/:id/scope` **Prints** “Everyone in the workspace can now see it.”. **Exit status** `0` on success. `1` when: * the scope is not workspace * you are not the uploader or an owner (403) * there is no usable credential, or the server refuses it (401) or the act (403), or answers any other error **Example** ```sh suli scope itm_0123456789abcdef workspace ``` # Signing in > suli help, version, skill, login, logout and whoami: the commands for getting started and signing in. Signing in through your Super Jackfruit Labs account, and seeing which identity is in force. `help`, `version` and `logout` send no credential anywhere. ## `suli help` [Section titled “suli help”](#suli-help) Prints the command summary, or one command in full. Sends nothing. ```sh suli help [] ``` | argument | meaning | | -------- | ------------------------------- | | `` | A command to explain (optional) | **Who may run it** * Local: sends no credential to Superlibrary. **Prints** help text. **Exit status** `0` on success. `1` when: * the verb is unknown **Example** ```sh suli help upload ``` ## `suli version` [Section titled “suli version”](#suli-version) Prints `suli /`. A release binary reports its release tag (for example v0.0.1); a build from source reports `dev`. Sends nothing. ```sh suli version ``` **Who may run it** * Local: sends no credential to Superlibrary. **Prints** one line. **Exit status** `0` on success. `1` when: * it cannot write its output (never in normal use) **Example** ```sh suli version ``` ## `suli skill` [Section titled “suli skill”](#suli-skill) Prints SKILL.md, the guide an agent reads to use suli, stamped with this binary’s version. It is built into the binary, so it always matches the verbs it ships with. `suli skill install` instead writes `/superlibrary-items/SKILL.md` (staged beside it, then renamed, so a reader never sees half a file); it overwrites only that one file, so it is safe to repeat. Sends nothing. ```sh suli skill [] [--dir ] ``` | argument | meaning | | ----------- | ------------------------------------------------------------------------- | | `` | Write the skill into a skills directory instead of printing it (optional) | | flag | type | default | meaning | | ------------- | ---- | ----------------- | -------------------------------------------------- | | `--dir ` | path | \~/.claude/skills | With `install`: the skills directory to write into | **Who may run it** * Local: sends no credential to Superlibrary. **Prints** the SKILL.md text; with `install`, the path written (with –json, `{ "path": … }`). **Exit status** `0` on success. `1` when: * with `install`: the directory cannot be written **Example** ```sh suli skill suli skill install suli skill install --dir ./.claude/skills ``` ## `suli login` [Section titled “suli login”](#suli-login) Finds the sign-in service from the server (`/.well-known/oauth-protected-resource`) and runs its device flow: open the printed link, confirm the code, and suli keeps a device credential of its own. Every command after that exchanges it for a token that lives five minutes, without a browser. ```sh suli login ``` **Who may run it** * Talks to the sign-in service; sends no credential to Superlibrary. **Calls** `GET /.well-known/oauth-protected-resource` **Prints** the link and code, then “Signed in.”. **Exit status** `0` on success. `1` when: * the server names no sign-in service * the code expires or is declined **Example** ```sh suli login ``` ## `suli logout` [Section titled “suli logout”](#suli-logout) Deletes suli’s device credential and cached token. Sends nothing. ```sh suli logout ``` **Who may run it** * Local: sends no credential to Superlibrary. **Prints** “Signed out.”. **Exit status** `0` on success. `1` when: * it cannot write its output (never in normal use) **Example** ```sh suli logout ``` ## `suli whoami` [Section titled “suli whoami”](#suli-whoami) Shows the person, workspace and role the server sees for your credential. ```sh suli whoami ``` **Who may run it** * A person: a member of the workspace. * An agent token: refused. * Agents reach Superlibrary from a later release; an agent token is refused today. **Calls** `GET /api/v1/me` **Prints** principal, workspace and role. **Exit status** `0` on success. `1` when: * there is no usable credential, or the server refuses it (401) or the act (403), or answers any other error **Example** ```sh suli whoami ``` # Embed > Mount Superlibrary's artifact viewer in another product's page with @superlibrary/embed. The host's duties, the options, the frame protocol, and which origins may embed it. `@superlibrary/embed` mounts Superlibrary’s viewer in a host page. The artifact renders in a sandboxed frame on the content origin; the toolbar around it lives in the host page. Allowed origins Framing is allowed only from origins listed in configuration. The shipped configuration lists SuperJackfruit’s own Superpipeline app (`https://app.superpipeline.dev`) and AgentPod console (`https://console.agentpod.dev`), besides Superlibrary’s own app. Another host has to be added to both lists; see [Allowed origins](#allowed-origins). The package is not published to npm. A product in another repository vendors a build: `pnpm --filter @superlibrary/embed bundle` writes `dist/superlibrary-embed.js`, one ES module, and its types. Record the Superlibrary commit and each file’s SHA-256 beside the copy. ## Mounting [Section titled “Mounting”](#mounting) ```ts import { mountArtifact } from '@superlibrary/embed'; const api = (path: string, init: RequestInit = {}) => // With the signed-in person's own token for the audience https://app.superlibrary.dev. fetch(`https://app.superlibrary.dev/api/v1/items/${path}`, { ...init, headers: { authorization: `Bearer ${token}`, 'content-type': 'application/json' }, }).then((res) => res.json()); const view = await mountArtifact(el, { itemId: 'itm_…', getEmbedUrl: ({ itemId, version }) => api(`${itemId}/embed`, { method: 'POST', body: JSON.stringify(version ? { version } : {}) }), }); view.setTheme('dark'); // the host's own theme switch await view.setVersion(2); // false if the host could not mint it view.destroy(); ``` ## The host’s duties [Section titled “The host’s duties”](#the-hosts-duties) 1. **Mint with the person’s own token.** `getEmbedUrl` calls `POST /api/v1/items/{id}/embed` with the signed-in person’s token, so the API checks that person’s access. Never a shared or service token. 2. **Be allowed.** The host’s origin must be in the content Worker’s `FRAME_ANCESTORS` and the API’s `EMBED_HOSTS`, and its web client must be allowed to request the Superlibrary audience from the account service. ## The toolbar [Section titled “The toolbar”](#the-toolbar) | Control | What it does | | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | **Version** | The version shown; a menu to switch when `getVersions` gives more than one | | **Files** | For a folder: its files, entry first, with sizes | | **View source** | For text kinds: the file as highlighted source, still sandboxed | | **Theme** | System, Light or Dark, remembered on this device | | **Download** | Single-file versions only | | **Full screen** | The whole embed, as a modal dialog; Escape or the same button exits | | **Open in new window** | The item in the Superlibrary app | | **Share** | Who can see the item, in words; widening to the workspace for a person allowed to; copy the app link. There are no public links. | Below 640 px of width, the secondary controls move into a labelled **More** panel. No control is an icon alone. ## Options [Section titled “Options”](#options) | Option | Required | | | ------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `itemId` | yes | `itm_` + 16 hex | | `getEmbedUrl({ itemId, version? })` | yes | Resolves to the API’s `EmbedGrant`: `url`, `expiresAt`, `version`, `entry`, `files`, `downloadUrl`, `itemUrl`. Called at mount, on a version switch, and again before a grant runs out. | | `version` | | Show this version; otherwise the newest live one | | `getVersions({ itemId })` | | Live version numbers, for the version menu | | `getShareInfo({ itemId })` | | `{ scope, boardVisible?, canWiden, title? }`, for the Share panel | | `setScope({ itemId, scope: 'workspace' })` | | Widen the item, after the person confirms | | `title` | | The frame’s accessible name | | `theme` | | `light`, `dark` or `system` (default), until the person picks one | | `appUrl` | | Default `https://app.superlibrary.dev` | | `height` | | Initial frame height in px; default 480 | | `clipboard` | | Default `navigator.clipboard` | | `onVersionChange(version)`, `onScopeChange(info)` | | Callbacks for the person’s choices | | `nonce` | | Put on the toolbar’s one `