Skip to content

Scopes & domains

A correction you make in one project shouldn’t leak into a different one. PLUR uses two orthogonal mechanisms: scope controls where an engram applies; domain controls what topic it covers.

Scope is a hierarchical namespace. Examples:

  • global — always loaded
  • project:my-app — only loaded for my-app
  • cluster:prod — only loaded when working against the prod cluster
  • service:api — only loaded for the api service
  • group:acme/platform — Enterprise team scope (details)

Recall filters by the current scope but always includes global. So if you’re in project:my-app and ask “what do I know about deploys”, you get project:my-app engrams + global engrams, not project:other-app.

Adapters detect scope automatically from the active project:

  • Claude Code / Cursor / Windsurf: PLUR reads .plur.yaml from the project root if present.
  • CLI: plur init --scope project:my-app writes .plur.yaml.
  • Programmatic: pass scope to any MCP tool.
scope: project:my-app
domain: backend # default domain when learning

Hooks pick this up automatically — corrections made in this project get tagged with scope: project:my-app and domain: backend unless you override.

Domain is a topic tag. Examples:

  • software.deployment
  • software.git
  • plur.brand
  • infrastructure.agents
  • firm.miles.heartbeat

Conventional separator is . — feel free to invent. Domain is soft routing: recall doesn’t strictly filter by domain, but the embedder weights it heavily, so an engram with domain: software.deployment ranks higher when you ask deploy questions.

ScopeDomainBehaviour
globalunsetAlways considered.
project:xunsetConsidered when current scope = project:x.
globalsoftware.gitAlways considered, but ranks higher on git topics.
project:xsoftware.gitConsidered for project:x; ranks higher on git topics inside project:x.

The rule: scope is a hard filter, domain is a soft signal.

Scopes are also PLUR’s privacy boundary, hardened in the independently audited 0.10.0 release:

  • Private by default. An engram is visible only within its scope family unless you deliberately share it. Unscoped writes land in your personal global namespace — they never fall through to a team store.
  • Per-engram routing. Every learn carries its own scope, and the write routes to whichever store is registered for that scope — one session can produce personal, project, and team engrams that each land in the right place.
  • Leak guard on shared writes. Writes destined for a shared or remote scope are scanned for secrets, personal paths, and infrastructure details (IPs, internal hosts, auth URLs). Offending writes are demoted to a private scope rather than published — fail-closed, including for oversized content the scanner can’t fully check.
  • Segment-aware matching. project:app matches project:app/api but never project:application — sibling scopes with a shared string prefix cannot bleed into each other.
  • No hostile scope registration. Scope discovery against a remote server only auto-registers shared-family scopes (group:, project:, org:, …). A server cannot trick your client into routing personal global writes to it.

In PLUR Enterprise, you also get team scopes:

  • group:acme — anyone in the acme org
  • group:acme/platform — only the platform team
  • group:acme/platform/api-service — service-level

These resolve against your identity (OIDC, SAML, GitHub, GitLab) and the team membership recorded in the admin dashboard. Permissions are enforced server-side — see Permissions & scopes.

Next: Activation & decay →