Skip to content

Scopes and inheritance

A scope answers where does this apply. It is the mechanism that stops a lesson from repo:payments surfacing in repo:marketing-site because the two happen to embed near each other.

Every memory is pinned to a scope_key, and every principal has scopes it may read and write.

org:acme
repo:payments
service:checkout
env:production

Flat, explicit strings. There is no parsing of structure out of them.

The limit. Only two relationships are structurally computable:

  1. an exact matchrepo:payments covers repo:payments
  2. org:* — covers everything in the organisation

Anything else fails closed: treated as not covered rather than guessed at.

coverscoversexact match onlyNOT computedorg:*repo:paymentsservice:checkoutrepo:paymentsservice:checkout-in-payments

What still holds. Both computable cases are exact and enforced. And the failure direction is the safe one: a mis-modelled scope costs you recall, never isolation. You will notice it as memory that does not surface — never as memory appearing somewhere it should not.

What to do about it. Model scopes flat. Do not encode a hierarchy in the key and expect it to be understood:

DoDo not
repo:paymentsorg:acme/team:core/repo:payments
service:checkoutrepo:payments/service:checkout
org:* for organisation-wide policyinventing team:* and expecting it to fan out

If a lesson genuinely applies to two repositories today, write it at org:* or write it twice. Both are honest; a fictional hierarchy is not.

A principal carries the scopes it may read and write. A principal scoped to repo:payments cannot read repo:infra — enforced server-side, a forbidden fault, no verdict involved.

This is why machine principals matter: a CI job that only ever touches one repository should have a credential that can only see that repository, so a prompt injection has nothing to reach for.

A request may supply an actor block to narrow what it sees — useful when one process acts for several agents and you want each to see only its own slice.

Narrowing is enforced by rejection, not by silent clamping:

  • A valid narrower scope_key binds the visible set.
  • A scope_key outside the principal’s authority is a forbidden fault.
  • A clearance that would widen is rejected, not quietly reduced to what is allowed.

Silent clamping would be the friendlier-looking choice and the wrong one: a caller that asked for more than it may have has a bug, and returning a smaller answer without saying so hides it until it matters.

Orthogonal to scope. Scope is where; clearance is how sensitive. A principal cleared to internal does not see restricted memory even inside its own scope.

Both are checked at admission, on every read.