Extensions
One package, three attachment points — agent skill, headless client code, GUI surface.
Think about what "the google-drive extension" would mean in fez. Three different
things, actually: an agent uploading results to Drive, a /gdrive command you
run yourself, and maybe a Drive file-picker panel in the desktop app. fez's
extension model embraces that: one package, up to three optional attachment
points, declared in the package's package.json:
"fez": {
"parts": {
"skill": { "command": "npx", "args": ["-y", "some-mcp"], "env": { "API_KEY": "" } },
"headless": "dist/headless.js",
"gui": "dist/gui.js",
"background": true
},
"permissions": ["read:channels", "publish", "commands", "ui", "background"]
}One fez install (or fez link <dir> for local dev) registers whatever parts
exist:
-
skill— an MCP server definition, merged into the machine's skill catalog. Agents get it by declaring the name in their persona (how skills work). This is the "@deployer, upload the results" path — no GUI involved. -
headless— code loaded by any client (TUI and GUI alike) against theFezExtensionAPI: slash commands, services, new event kinds. This is the /obsidian path — and why the system still works with no GUI at all. -
gui— components only the desktop app renders: artifact viewers, theme packs, panels. Loaded from~/.fez/gui-extensionsat launch;activate(api)receives the page's React,registerArtifactViewer, andregisterTheme. Themes appear in settings → appearance. -
background— opt in to running scheduled work inside the always-on sentinel. The extension registers tasks withapi.registerScheduledTask(name, everyMs, run); the sentinel is the only host that runs them, so no extension ships its own daemon. This is an allowlist, not a default: an extension written for the TUI would otherwise start doing its foreground job a second time inside the always-on process.
Alongside parts, a package declares permissions — what it needs, shown
to the user before anything runs, and enforced by narrowing the API it receives.
See trust & approval.
A package ships only the parts that make sense: a bitwarden package might be
skill + headless (no UI needed); a theme pack is gui only; an obsidian
package plausibly ships all three. The substance always lives in the first
two — gui is presentation.
Installing
fez install <source> # npm package, git URL, or local path
fez list # what's installed
fez remove <name> # uninstall (skill definitions are kept — see below)
fez link <dir> # dev-install a local package: build, register parts, smoke-importRemoval keeps the skill definition: personas may still declare it, and any secret values you filled are yours (custody).
The first-party packages
The features you'd assume are core are themselves extensions with no private hooks — proof the seams are real: fez-communities (the channel UI itself), fez-dms, fez-docs, fez-media (Blossom uploads), fez-moderation, fez-notifications, fez-search, fez-workflows, theme packs.
The rule
If a feature can live behind a seam, it must. Core grows only when a new seam is needed — never a new feature.