Skip to content

Scope Intersection

Scope intersection is the permission model at the heart of LumenFlow’s security. Before any tool executes, the kernel computes the intersection of four independent scope layers. A tool can only operate within the permissions that all four layers jointly permit.

LayerSourceWho controls itExample
Workspaceworkspace.yaml security.allowed_scopesWorkspace administratorsrc/** (read+write), no network
LaneLane configuration allowed_scopesLane ownersrc/core/** (write), ** (read)
TaskTask spec declared_scopesTask authorsrc/core/auth/** (write)
ToolPack manifest required_scopesPack author** (write) — tool needs write access

The intersection narrows progressively:

Workspace allows: src/** (write)
Lane allows:      src/core/** (write)
Task declares:    src/core/auth/** (write)
Tool requires:    ** (write)

Intersection: src/core/auth/** (write)
  ← narrowest pattern that all four agree on

The tool can only write to src/core/auth/**. Even though the tool itself requests ** (everything), the workspace, lane, and task scopes constrain it.

For each scope type (path-read, path-write, network), the kernel:

  1. Takes every possible combination across the four layers
  2. Checks that all four patterns overlap (using micromatch as the matching library)
  3. Selects the narrowest pattern by specificity score (literal characters minus wildcard penalties)
  4. Deduplicates results by access:pattern key

If any layer provides zero scopes for a given access type, the result for that access type is empty — which means denial.

Workspace allows: src/** (write)
Lane allows:      tests/** (write)       ← no overlap with workspace
Task declares:    src/core/** (write)
Tool requires:    ** (write)

Intersection: [] (empty)
  → SCOPE_DENIED

The workspace and lane have no overlapping write patterns, so the intersection is empty and the tool call is denied.

LumenFlow supports two scope types:

required_scopes:
  - type: path
    pattern: 'src/**'
    access: read # or 'write'

Path patterns use glob syntax (* for single segment, ** for any depth). The kernel uses micromatch for pattern matching and a synthetic-path heuristic for containment checking.

required_scopes:
  - type: network
    posture: full # or 'off'

Network scopes use a simpler model — the posture value must match across all four layers. If the workspace says off and the tool says full, the intersection fails.

Regardless of what scopes are configured, the kernel unconditionally denies writes to .lumenflow/**. This protects the kernel’s own state (event log, evidence store, task specs) from being modified by any tool, even if all four scope layers would otherwise allow it.

This check runs before scope intersection — it cannot be overridden by any configuration.

The 4-level model provides several guarantees:

  1. Principle of least privilege. Each layer narrows permissions. A broad tool scope is constrained by a narrow task scope.
  2. No privilege escalation. A lower layer cannot grant permissions that a higher layer denied. The intersection can only shrink, never grow.
  3. Fail-closed. Empty intersection = denied. Missing scopes at any layer = denied. The safe direction is always denial.
  4. Defense in depth. Even if one layer is misconfigured (e.g., ** for everything), the other three layers still constrain the effective scope.

Consider a workspace with two lanes and a tool that writes files:

# workspace.yaml
security:
  allowed_scopes:
    - type: path
      pattern: '**'
      access: write

# Lane: Framework Core
allowed_scopes:
  - type: path
    pattern: 'src/core/**'
    access: write

# Lane: Experience UI
allowed_scopes:
  - type: path
    pattern: 'src/components/**'
    access: write

An agent working in the “Framework Core” lane on a task scoped to src/core/auth/** can write to src/core/auth/** — but cannot touch src/components/ (lane boundary) or docs/ (task boundary), even though the workspace allows **.

  • Kernel Runtime — Where scope intersection happens in the execution pipeline
  • Policy Engine — The policy layer that runs alongside scope checks
  • Packs — How tools declare their required scopes
  • Lanes — How lanes define scope boundaries