docs(design): layered service templates + MCP enrollment org-scoping#439
Merged
angel-manuel merged 6 commits intoJul 8, 2026
Merged
Conversation
Two design docs for the corporate-refocus feedback (2026-07-08):
- org-catalog-overlay.md: an org-owned sparse patch over global and
autodiscovered templates. Per-action allow/deny, clamp-upward risk,
disclose, relabel, and instantiation presets, stored as DB JSONB and
authored as a YAML fragment. Resolved base ⊕ overlay at load so
discovery, instantiation, and execution all read the effective
template (hard gate for free). Tracks upstream (no fork); restriction-
only (never grants capability). Folds in "pre-filled services, each
user their own OAuth" via publish_mode: user_instantiated.
- mcp-enrollment-org-scoping.md: guarantee that <org>.{app,api}.overslash
.com/mcp onboards agents only into <org>. Documents the current gap
(pending.org_id comes from the session not the subdomain; DCR clients
are org-global) and the fix (derive enrollment org from ctx, re-auth on
mismatch, org-scope the fast-path binding, stamp org_id on
oauth_mcp_clients).
Both indexed in docs/design/INDEX.md as Draft — proposed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Fold the org-catalog-overlay draft into a single "layered template" model that unifies forks and overlays, per the design interview. - Rename org-catalog-overlay.md -> layered-service-templates.md, rewritten as a buildable handover spec (glossary, data model + migration 095, the recursive fold, delta vocabulary, authority, validation, v1 scope, implementation map, rejected-alternatives). - A layer is a service_templates row; `extends` (NULL=standalone full doc, set=derived delta over a base key) resolved by a recursive fold. Masks (allowlist/denylist, clamp-up risk, disclose, relabel) are monotonic and order-independent -> containment is structural; extensions add actions/hosts only (no auth, no rebinding). `extends` is a live pointer. - Authority is namespace-based; `allow_user_templates` bool generalizes to `user_template_policy: none|restrictive|full` (v1 honors none|full). Classifier + scope constraints deferred but reserved (no future migration). - Update docs/design/INDEX.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The subdomain enrollment lock constrains the subdomain endpoint only — it is not a claim that an org is reachable solely via its subdomain. Make the root guarantee explicit: a member with a valid <org> session sees and uses <org> from app.overslash.com (dashboard + enrollment into their session org), exactly as today. - Fix the invariant text that wrongly implied root is only for personal/creator orgs; reframe root as the multi-org hub. - Add "Root and multi-org access" subsection grounded in check_subdomain_matches_jwt being a no-op at Root; enrollment org follows the resolved org (subdomain org on Org ctx, session org on Root), re-auth-on-mismatch fires on Org ctx only. - DCR client org_id: NULL for root/back-compat clients (multi-org path); on a subdomain accept NULL-or-matching (NULL safe via the org-derivation), reject a different-org stamp; root doesn't gate on client org_id. - Add root multi-org + NULL-client-on-subdomain regression tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-templates Sentry review catch: the file was renamed; update the cross-reference in mcp-enrollment-org-scoping.md line 19. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both confirmed against SCHEMA.sql: - layered-service-templates: migration 095 must DROP NOT NULL on service_templates.openapi (derived layers store NULL there) and tighten the shape CHECK so standalone→openapi present / derived→delta present. Note the ServiceTemplateRow.openapi field becomes Option<serde_json::Value>. - mcp-enrollment-org-scoping: fast-path binding scoping by org requires migrating mcp_client_agent_bindings from UNIQUE (user_identity_id, client_id) to UNIQUE (user_identity_id, client_id, org_id) — the current global-unique key makes per-org bindings impossible and would collide the root multi-org case (one NULL root client enrolling into two orgs a member belongs to). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…hange Sentry follow-on: changing mcp_client_agent_bindings to UNIQUE(user_identity_id, client_id, org_id) requires matching edits in mcp_client_agent_binding.rs — upsert ON CONFLICT gains org_id, get_for gains an org_id param + WHERE clause, and the module doc comment is updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two design docs for the corporate-refocus feedback (
docs/feedback/2026-07-08-refocus-adapt-to-corporate.md). Docs only — no code changes.1.
layered-service-templates.md— one primitive for forks and overlaysRefined in a design interview (grill-with-docs + domain-modeling); this is a buildable handover spec with a settled model, a migration, an implementation map, and rejected-alternatives called out so they aren't relitigated.
The model. Fork and overlay collapse into one layer = a
service_templatesrow.extends(a base template key) decides its nature:NULL→ standalone layer (full OpenAPI doc; the old "fork"); set → derived layer (a sparse delta over a live base). Resolution is a recursive fold:resolve(layer) = apply(delta, resolve(extends)).allowlist/denylist(monotonic set-ops, no scalar default — it was the only widening lever and the only order-sensitive field),riskclamp-up-only, additivedisclose, relabel, templatehidden. Monotonic + order-independent ⇒ containment is structural (resolve(child) ⊆ resolve(base)); autodiscover-safe by construction (allowlist excludes new upstream MCP tools, the fix(hubspot): re-sync to HubSpot's replaced MCP tool catalog + RFC 6749 scope fallback on OAuth callback #428 hazard).shadowed_extensionwarning.extendsis a LIVE pointer — the entire reason for layers over forks (tracks upstream). Chainsglobal → org → userallowed (extend up); cycle + target guards; cascade cache invalidation.user_template_policyenum{none|restrictive|full}(migrated fromallow_user_templates; v1 honorsnone/full;restrictivereserved for the deferred classifier — pure-compute, no future migration). Downgrades forward-only.resolution_report.warnings[](recomputed on base change via the live pointer).restrictivetier; scope default-request preset; scope-constraint fold op (waits on per-actionrequired_scopes); materializedopenapicache; proactive new-tools review queue.Migration 095 adds
extends/deltatoservice_templatesand absorbs the existing org/user tier (existing rows are already valid standalone layers). Supersedes the earlierorg-catalog-overlay.mddraft (renamed).2.
mcp-enrollment-org-scoping.md— corp subdomain onboards only into that org<org>.{app,api}.overslash.com/mcpmust onboard agents only into<org>. Documents the current gap (pending.org_idcomes from the session, not the subdomain; DCR clients are org-global) and the fix (derive enrollment org fromctx, re-auth on mismatch, org-scope the fast-path binding, stamporg_idonoauth_mcp_clients). Unchanged in this round.Follow-ups if approved
overslash-core;extends/deltarepo + validation; effective-template reads in discovery/kernel_create_service/action resolver;user_template_policy; catalog layer-editor UI.authorize()change +oauth_mcp_clients.org_idmigration + tests.🤖 Generated with Claude Code