Plugin Push Contract — agent → /ops/plugins
A second window.aegis.* surface, parallel to
Weekly Maker Asset Review. Where that
page documents pushing a maker-stats data snapshot,
this page documents pushing a WASM plugin package — a
binary the agent has compiled locally on the maker’s
machine.
Same architecture, same trust model: browser-local sandbox, no server-side registry, agent does the heavy lifting, the maker reviews the result.
Data flow
+--------------------+ pushed via +----------------------+
| local agent | -- chrome-mcp --> | window.aegis |
| compiles WASM | evaluate_script | .publishPlugin() |
| + builds package | | |
+--------------------+ +----------+-----------+
|
v
localStorage:
aegis.plugins.registry
|
v
/ops/plugins reads it on
mount and on the
`aegis:plugins:updated`
event — version table +
audit log re-render live.
The activated plugins from this registry are consulted by the in-browser build pipelines (ESPCTL MCP, Build Lab) at pre/post-compile time. Plugins activated here actually execute in this browser’s builds.
Browser API contract
Six functions on window.aegis, installed once on app
mount via installPluginRegistryWindowApi in
src/lib/user-settings/plugin-registry.ts:
| Function | Returns | Notes |
|---|---|---|
window.aegis.publishPlugin(pkg, actor?) | Promise<{ ok, error?, audit, record? }> | Validates pkg.manifest, verifies digest, persists, dispatches aegis:plugins:updated. Async because manifest validation runs crypto.subtle.digest. |
window.aegis.activatePlugin(pluginId, version, options?) | { ok, error?, audit, record? } | options?: { actor?, scope?, rolloutPct? }. Defaults: actor='agent', scope='all', rolloutPct=100. |
window.aegis.deactivatePlugin(pluginId, version, actor?) | { ok, error?, audit, record? } | |
window.aegis.rollbackPlugin(pluginId, version, actor?) | { ok, error?, audit, record? } | Rolls back active version to the supplied earlier version. |
window.aegis.getPluginSnapshot() | PluginRegistrySnapshot | Reads current versions[] + activeVersions{} + audits[]. |
window.aegis.clearPluginRegistry() | void | Wipes the local registry. |
Listen for updates with:
window.addEventListener('aegis:plugins:updated', (event) => {
console.log('new plugin registry snapshot', event.detail);
});
Snapshot schema
interface PluginRegistrySnapshot {
versions: PluginVersionRecord[];
activeVersions: Record<PluginId, Version>;
audits: PluginLifecycleAudit[];
}
interface PluginVersionRecord {
pluginId: string;
version: string;
manifest: PluginManifest; // see contracts/manifest.ts
digest?: string;
publishedAt: string;
publishedBy: string;
updatedAt: string;
state: 'published' | 'active' | 'inactive' | 'rolled_back';
rollout: {
scope: 'all' | 'beta' | 'canary' | 'internal';
rolloutPct: number;
};
}
A SignedPluginPackage (what publishPlugin accepts):
interface SignedPluginPackage {
manifest: PluginManifest;
artifactDigest?: string;
artifactUrl?: string;
}
The manifest must pass parsePluginManifest() validation
(plugin_id / version / contract_version / hooks / capabilities /
digest / runtime). Invalid manifests reject with
{ ok: false, error: 'Manifest validation failed during publish.', audit }.
Minimal agent script
A browser-driving agent that has just compiled a WASM plugin on disk would do something like:
// pseudocode the agent runs after a successful local compile
const manifest = JSON.parse(fs.readFileSync('plugin-manifest.json', 'utf8'));
const wasm = fs.readFileSync('plugin.wasm');
const digest = await sha256(wasm);
const pkg = {
manifest: { ...manifest, digest: `sha256:${digest}` },
artifactDigest: `sha256:${digest}`,
artifactUrl: 'file:///tmp/plugin.wasm',
};
const result = await chromeMcp.evaluateScript(
`window.aegis.publishPlugin(${JSON.stringify(pkg)}, 'agent-compile-flow')`,
);
if (!result.ok) throw new Error(result.error);
// Then activate via:
await chromeMcp.evaluateScript(
`window.aegis.activatePlugin('${manifest.plugin_id}', '${manifest.version}')`,
);
/ops/plugins will reflect the new version + audit row
immediately via the aegis:plugins:updated event.
Trust boundary
The browser-local plugin registry is single-maker, single-browser:
- No upload UI (intentional). The agent is the publisher.
- No public-key signature. Digest match (
crypto.subtle.digest) proves integrity, not authenticity — adequate because the agent is the maker’s own local automation. - No server-side ledger. Each browser has its own
aegis.plugins.registrylocalStorage entry.
The build pipeline that actually executes activated plugins
(runActivePluginPreCompile / runActivePluginPostCompile
in features/plugins/runtime.ts) lives in the same browser,
so “activated here” and “loaded by my next build” are the
same lifetime.
Related
- Weekly Maker Asset Review — the parallel agent push contract for review data.
- Aegis Ops — the landing page that frames both contracts.
/ops/plugins— the governance UI that consumes the snapshot.