Expand description
§Publishing and installing
A plugin is installed on your account, not on a machine: every viewer signed in to the account runs its UI half, and daemons run its daemon half. The account keeps the package and records which version each plugin runs.
§The package
standard-plugin pack writes one deterministic tarball for a plugin or a
companion pair and prints its SHA-256, the package’s identity on the
account:
manifest.json the account manifest: id, version, entries, grants
ui/standard-plugin.json the UI half's runtime manifest
ui/<module>.wasm its component
ui/browser/... the jco build, when built; viewers ignore it
daemon/standard-plugin.json the companion's runtime manifest
daemon/<module>.wasmmanifest.json names each half’s component (ui.entry, daemon.entry)
and carries the grants of both halves with their reasons: the set the user
approves. daemon.placement (and daemon.failover) come from the daemon
half’s daemon section (manifest). The
same bundle always packs to the same bytes. A package is at most 8 MiB.
§Publishing
A plugin reaches users from one of four sources. Each is recorded on the account with the plugin, so later versions are found and installed the same way (see “Updates and approval” below).
§GitHub Releases
Attach the packed .tar to a GitHub Release:
- A repository with one plugin tags releases
v<version>(or<version>) and attaches<id>-<version>.tar. Users install it withowner/repo. - A repository with several plugins tags each release
<id>@<version>(or<id>-v<version>) and attaches that plugin’s<id>-<version>.tar. Users install one withowner/repo#<id>, or withowner/repo: the install lists the repository’s plugins (each id’s newest published version, and the first line of its release notes) and asks which one. - Any asset named
*.standard-plugin.taris accepted too.
Drafts and pre-releases are skipped unless a user names the tag
(owner/repo#<id>@<tag>). When GitHub publishes an asset’s SHA-256
(digest), the download must match it. Lookups use GitHub’s REST API
without credentials; a GITHUB_TOKEN in the environment is sent to
api.github.com only (for private repositories or rate limits) and is
never stored.
A private repository installs too. When the installing viewer cannot read
it, one of the account’s machines that is signed in to GitHub (a
GITHUB_TOKEN or GH_TOKEN in its environment, or the GitHub CLI) reads
it instead, and the install dialog names that machine while it looks. The
token never leaves that machine.
A repository can release with a workflow: a script tags <id>@<version>
from the plugin’s manifest, and pushing the tag builds, packs and attaches
<id>-<version>.tar.
§npm
Publish an npm package that contains the packed .tar and names it in
package.json:
{
"name": "@standardagents/foobar",
"version": "1.2.0",
"files": ["dist/foobar-1.2.0.tar"],
"standardPlugin": { "package": "dist/foobar-1.2.0.tar" }
}standardPlugin.package is a path inside the package, relative to its
root. A standardPlugin without package is a runtime v1 plugin and is
refused. Installs resolve the latest dist-tag, or the dist-tag, version
or range the user names (npm:@scope/name@^1.2, name@next), and the
tarball must match its dist.integrity (sha512). The version’s
publisher (_npmUser) is shown as the publisher.
§A link
Any https:// link to a .tar (the packed plugin), a .tgz/.tar.gz
(a gzip of it, or an npm-style tarball as above), or a .zip holding the
packed .tar or a built plugin directory (packed at install). npm tarball
links (https://registry.npmjs.org/…/-/x.tgz) are links too. Updates
recheck the link with a conditional request, so an unchanged file is not
downloaded again.
§A local file
A built plugin directory or a packed .tar on the installing machine.
The account records its absolute path; there are no automatic updates.
§A file on another machine
The path can be on any machine of your account: pick the machine in the
install dialog, or run standard plugin install <path> --from-machine <machine>. That machine reads the path, verifies the package and uploads
it to the account; only the package’s summary (id, name, version, grants)
comes back, never the file. ~ is the home directory of that machine’s
user, and a relative path is refused. Only a built plugin directory or a
packed .tar is read. It has no automatic updates;
standard plugin update <id> asks that machine to read the path again (it
must be online).
§Limits
Downloads are https only (redirects included), at most 32 MiB and 90
seconds. Archives unpack to at most 64 MiB and 4,096 files; an entry with
an absolute path or .. refuses the archive, and links are skipped, so
nothing lands outside it. Every source ends in the same verification as a
local package: the manifest, the package’s SHA-256, and its grants.
§Installing
standard plugin install acme/standard-plugins#weather
standard plugin install @acme/weather
standard plugin install npm:@acme/weather@^1.2
standard plugin install https://example.com/weather-1.2.0.tar
standard plugin install ./my-card # a built plugin directory
standard plugin install my-card-0.1.0.tar
standard plugin install ~/plugins/my-card.tar --from-machine studio
standard plugin install acme/standard-plugins # lists them, asks which
standard plugin install acme/standard-plugins#weather --from-machine studio
standard-plugin install # check, pack, then `standard plugin install .`A GitHub repository of several plugins without #<id> lists its plugins
and asks for a number; with --yes or without a terminal it refuses and
names each owner/repo#<id> to rerun with. --from-machine also takes a
GitHub source: only that machine is asked to resolve it.
standard plugin install resolves the source, lists every grant with its
reason (high-risk grants first: machine.full, network.full, every
process.exec: and fetch:), asks y/N (--yes approves without asking),
uploads the package, and installs it with its source. When the account
already has a plugin with that id it updates it, approves the grants you
just saw, and records the new source. Without a terminal to ask and
without --yes, it lists the grants and stops, saying so; review them and
rerun with --yes.
A singleton daemon runs on one machine, which the install pins:
--machine <id or name> names it; without it the command uses the
account’s only machine or asks which one (--yes with several machines
refuses and asks for --machine). Installing an installed singleton again
with --machine moves it there; the Plugins view pins it too (P, then a
machine and Enter).
standard plugin install ./sync --machine studioIn a viewer, Install plugin… in the command palette (or I in the Plugins view) runs the same install in one card: the source (with a machine picker and a file browser for paths), then the consent screen, which lists the plugin’s permissions with their reasons, high risk first, then the install, which ends by saying where the plugin appears. The browser viewer installs from a file on one of the account’s machines; GitHub, npm and link sources install from a native viewer or the CLI.
§Updates and approval
A plugin installed from GitHub, npm or a link updates from it
automatically unless its auto-update is off (standard plugin source <id> --auto-update off, or U in the Plugins view). Nothing polls. A viewer
checks when it starts and when its Plugins view opens, at most once an
hour per plugin, and of several viewers starting together one checks and
installs. standard plugin update [id] [--all] checks now, whatever the
hour or the switch. What the source said, or why it failed, is shown in
the Plugins view under the plugin, never as a popup.
standard plugin update # every plugin with a source
standard plugin update quota-meters
standard plugin source quota-meters # where it updates from and the last check
standard plugin source quota-meters --auto-update off
standard plugin uninstall quota-meters # asks first; --yes to skip the questionstandard plugin uninstall <id> removes the plugin from the account, the
same as X in the Plugins view: it stops in every viewer and on every
machine. It asks for a confirmation at the terminal; with no terminal to
ask on (a script, a pipe) it refuses unless --yes is given.
An update that keeps the approved grants, or drops some, runs at once:
every viewer starts the new version beside the old one and swaps to it
once it has activated. An update that adds a grant waits for approval: the
Plugins view (command palette, Plugins) shows a card with the added
grants and their reasons; Enter approves exactly the update’s grants, D
keeps the installed version. A newer version a check found (with
auto-update off) shows as available; Enter installs it through the install
dialog.