2026-09-23·by Sijie Wang#standmeet#architecture#design

owner-facade-from-registry

Owner MCP facade = generic discovery + invoke over the two containers

Parent: backend-domain-modules · Related: facade-parity · facade-directions

Decision (2026-07-27, owner)

The owner's agent (owner's own MCP client / Claude Code) must reach capabilities the same generic way the visitor agent does: discover from the container, invoke by name. No explicit per-capability host code.

Give the owner agent, over MCP, two generic discover+invoke doors — one per container:

containerdiscoverinvoke
capability (capreg)list registered capabilitiesinvoke a capability's tool by name, in owner context
connector (Hub)list connected connectorsconnector.invoke(category, verb, args) (opaque door — already exists)

"这样就通用了" — instead of N explicit owner caps, TWO generic doors. Owner books = discover the booker capability → invoke it; owner sets policy = same; owner uses calendar = discover the calendar connector → invoke. The owner side is zero explicit cap code.

What this replaces / deletes

  • The entire internal/plugins/ownercore explicit cap_* surface (~29 hand-written owner caps: cap_calendar / cap_booking / cap_chat / cap_corpus_* / …). They become discovered from the registry, not hand-written. cap_calendar/cap_booking in particular are the anti-pattern the owner flagged: an externalized capability (booker sandbox) re-implemented as explicit host code. See external-means-fully-external.
  • This is the endgame of facade-from-registry (facade-parity): every facade generated-from / verified-against the one capability registry.

The one real mechanism to build (the crux)

capreg already had List() (discovery was done). The missing piece was owner-context invocation of a capability — especially a sandbox capability. Until then a sandbox cap was dialed only inside a visitor session (Capability.VisitorBinding(ctx, AssembleInput)dialAndList per ConversationID; extMCPCapability/mcpAppCapability were ShapeVisitorOnly, OwnerMCPBindings() returned []). There was no owner-context dial: the owner has no visitor session, only an owner_id.

Built (7f02bccc1, 2026-07-29): the manifest declares owner tools as data (mcpplugin.Manifest.OwnerTools, internal/capabilities/mcpplugin/manifest.go), and routes/capload/capreg_mcp_app_owner.go turns each declared tool into an OwnerMCPBindings() entry whose handler dials the sandbox only when invoked, with owner context (owner_id, no visitor/code/conversation) and forwards the tools/call. The table is enumerated at assembly time so facade-parity reconciles against it without dialing anything at boot. The sandbox tool runs its logic via the same generic reach-back it already used (connector.invoke + capstore + owner.meta); booker declares its owner-facing tools (owner list_slots, calendar_cancel_booking, policy get/set, bookings-list) in mcp-servers/booker/main.go, and the host's duplicate policy/slots evaluator was deleted in the same commit. The same hole reopened once more for settings — a capability could declare owner tools but not owner-tunable fields, so booker's booking policy was hand-written on the host again — and was closed the same way: Manifest.Config / capconfig (cc5c1db47, 2026-07-31).

Consequence for internal/

Reaching the "plugins gone" target was gated on this build, and it went through: internal/plugins dissolved into owner/ (fea7ae93f, 2026-07-29), the domains declare their own ops and the dispatcher only aggregates (53733b661, 2026-08-01), and ownercore itself is gone (f35e82c04, 2026-08-02). As of 2026-09-07 internal/ holds 11 directories — the 8 core domains + capabilities + routes + infra — which is exactly the whitelist check-internal-dirs.sh enforces.

Scope / verification

Foundational, replaces ownercore, must be verified by real owner + visitor booking e2e (gcal + sandbox rebuild; make test-only SPEC=booking). Compile+lint green is NOT sufficient.

Status

Shipped. Owner-context invocation 2026-07-29 (7f02bccc1), plugins dissolved 2026-07-29 (fea7ae93f), ownercore deleted 2026-08-02 (f35e82c04). Proof files: internal/routes/capload/capreg_mcp_app_owner.go, internal/capabilities/mcpplugin/manifest.go; internal/plugins/ and internal/owner/ownercore/ no longer exist on main.

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →