Host the plugin registry on the forge #206

Closed AtlantisPleb opened this 2d ago 2 comments

Outcome

A plugin is a forge repository with a typed manifest and a digest-pinned release artifact. The registry is a typed index over those releases plus semantic capability search — not a new backend.

Contract

  • Manifest schema per docs/2026-08-24-triage-and-plugin-model-assessment.md section 4.3: identity (name, version, artifact digest), typed input/output schemas, capability declarations (read-only mounts, host allowlist, bounds), discovery description, contributed surfaces, reserved price/license fields.
  • Index endpoint the CLI's capability tool queries; selection is semantic over manifests, invocation is exact-name (no keyword routing).
  • The gap loop: a capability search that finds nothing can file a scoped issue, deduplicated.
  • Usage counters derive from digest-carrying tool.ran thread events, under the consent tiers.

Source

docs/2026-08-24-registry-network-strategy.md sections 6–7.

  1. AtlantisPleb opened this issue 2d ago
  2. A AtlantisPleb Author 2d ago

    Server half landed on main in 8ac99fe: OpenAgents.Plugins.Manifest validates identity, a sha256-pinned artifact digest, typed input/output schemas, capability declarations (read-only mounts, host allowlist, bounds), the discovery description, contributed surfaces, and the reserved price and license fields — refusing anything that does not validate with a typed error naming the field. OpenAgents.Plugins.Index lists validated manifests discovered from forge repositories behind a classified route the CLI capability tool can query. 42 tests green.

    On selection, the workspace rule held: no ad hoc keyword or substring routing. There is no embedding path in this repository yet, so the index publishes manifests and their discovery descriptions and leaves selection to the caller rather than faking semantics with string matching; invocation stays exact-name. When a real semantic path exists it goes here.

    Remaining on this issue: semantic capability search once that path exists, the gap loop (a capability search finding nothing files a scoped, deduplicated issue), and usage counters derived from digest-carrying tool.ran events under the consent tiers. Known bound recorded in the commit: the forge adapter treats a repository's default branch as the release identity, because no separate release model exists yet.

  3. A AtlantisPleb Author 1d ago

    The registry's server half is complete.

    • Typed manifest schema (8ac99fe): identity, sha256-pinned artifact digest, typed input/output schemas, capability declarations (read-only mounts, host allowlist, bounds), discovery description, contributed surfaces, and reserved price and license fields — anything that does not validate is refused with a typed error naming the field.
    • Index endpoint the CLI's capability tool queries, over manifests discovered from forge repositories. It composes the anonymous read predicate rather than restating it, so a private repository's manifest can never leak into a public listing (6e98134).
    • Semantic selection (7e7a4bc): manifests are embedded and scored by cosine, reusing the shape the tool catalog already had. The workspace rule holds where it matters — when embeddings are off or the provider errors, the search returns candidates for the caller to choose from rather than quietly degrading to substring matching. Invocation stays exact-name.
    • The gap loop's producer: a capability search that finds nothing records a gap (shipped with the CLI's capability tool, OpenAgentsInc/openagents#27).

    Embeddings stay off by default, following the tool catalog's posture, and a plugin search can never fail a request because the provider is down.

    Two things named in the contract remain, and both want their own issue rather than holding this one open: turning recorded capability gaps into scoped, deduplicated forge issues, and usage counters derived from digest-carrying tool.ran events under the consent tiers. Known bound recorded in the commit: the forge adapter treats a repository's default branch as the release identity, because no separate release model exists yet.

  4. closed this as completed 1d ago
Sign in with GitHub to comment on this issue.