Local-first token, cost and cache observability for Factory AI's droid.
Requires the observer binary already on your PATH. This plugin is
wiring only — it declares an MCP server that runs observer; it does not
download or bundle it.
npm i -g @superbased/observer # or: pipx install superbased-observer
observer start # run the local daemondroid/ ← marketplace root
├── .factory-plugin/marketplace.json ← the catalog
└── factory/superbased/
├── .factory-plugin/plugin.json ← the plugin manifest (metadata only)
└── mcp.json ← the MCP server it bundles, at the plugin ROOT
Factory's own docs are explicit that only the manifest belongs inside
.factory-plugin/: "Do not put them inside .factory-plugin/; that
directory is for plugin metadata." The catalog entry's source is
./factory/superbased — relative to the marketplace root, and inside it,
as the documented rule requires.
Note the file name: Droid's native MCP file is mcp.json, not
.mcp.json. The dotted form is the Claude Code compatibility alias, which
Droid translates to mcp.json when it copies a plugin into its cache. (Qoder,
in ../qoder/, is the exact reverse — dotted only. The two are not typos.)
droid plugin marketplace add https://github.com/superbasedapp/plugins
droid plugin install superbased@superbasedOr browse with /plugins inside the CLI. A local checkout works too —
droid plugin marketplace add ./droid then the same
install line.
Factory maintains its own official marketplace at
github.com/Factory-AI/factory-plugins. Listing there is a public
submission, not something this repository does on its own; the catalog above is
the self-hosted form, exactly like the Codex surface.
| Component | What it declares |
|---|---|
.factory-plugin/plugin.json |
Identity only — Droid's manifest has no MCP field. |
mcp.json |
The observer MCP server: observer serve — the same launch observer init writes into ~/.factory/mcp.json, transposed into the plugin's own file. |
No hooks are declared. Droid documents plugin hooks, but observer has no
Droid hook receiver (observer hook accepts claude-code, cursor, codex and
hermes only), so a hooks/hooks.json here would declare a command that
does not exist. Droid capture works without hooks: observer's watcher reads the
JSONL transcripts under ~/.factory/sessions and their settings sidecars.
Captured data lands in the local ~/.observer/observer.db. The MCP server
makes no network calls of its own.
Droid is one of the few tools here where observer init does write an
MCP entry: ~/.factory/mcp.json, under the same observer
key. Carrying both that entry and this plugin loads observer's MCP tool schema
twice per turn — wasted context, no data corruption (observer's rows are keyed
and upsert).
Droid has no --droid init flag. It is selected by auto-detection —
observer init with no tool flags, or observer init --all — so the
MCP step runs for it whenever ~/.factory is present.
And Droid is not auto-detected the other way either. The detect-and-skip
observer init performs is internal/claudeplugin — claude-code-only,
by design — so nothing notices this plugin. With it installed, either skip the
MCP step at init time:
observer init --skip-mcp # hooks + proxy routes only, for every selected toolor, if it is already wired, delete the "observer" key from
~/.factory/mcp.json (the file is otherwise left untouched — observer only
ever adds or removes its own entry there). This is documented, not built.
- Docs: https://superbased.app/
- Source: https://github.com/superbasedapp/observer
- License: Apache-2.0