Skip to content

Workspace Spec

The workspace spec (workspace.yaml) is the kernel-level configuration file that defines the runtime environment for a LumenFlow workspace. It declares which packs are loaded, which lanes exist, what security boundaries apply, and where events and memory are stored.

LumenFlow is designed to work across multiple consumer repo shapes, but the portability contract is explicit:

  • LumenFlow remains a Node-distributed CLI.
  • Consumer repos do not need to be Next.js apps or pnpm monorepos.
  • Framework-specific surfaces such as apps/web dashboards are optional and should only be referenced when present or configured.

Current baseline archetypes for generic lifecycle support:

| Archetype | Expected shape | Generic lifecycle expectation | | --------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------- | | Single-package service repo | src/**, no apps/ or packages/ | init, wu:create, wu:brief, wu:prep, and wu:done work without monorepo-specific guidance | | Monorepo without web app | multiple packages or services, no apps/web | gate planning and onboarding do not instruct the user to start a dashboard | | Backend/docs-oriented repo | service code plus docs/content paths | work classification does not infer UI-only guidance from framework-like filenames alone |

Smoke verification for this baseline should confirm:

  1. onboarding does not advertise dashboard startup when no dashboard surface exists
  2. classifier defaults stay backend/docs/infra-oriented unless generic UI signals or workspace config justify UI guidance
  3. docs and generated workflow guidance describe these boundaries explicitly
# workspace.yaml
id: my-workspace
name: My Project

packs:
  - id: software-delivery
    version: '0.1.0'
    integrity: sha256:a1b2c3d4e5f6...
    source: local
    # url: optional — required for git/registry sources
    # registry_url: optional — override default registry

lanes:
  - id: framework-core
    title: 'Framework: Core'
    allowed_scopes:
      - type: path
        pattern: 'packages/@lumenflow/core/**'
        access: write
    wip_limit: 1
    # policy_overrides: optional

security:
  allowed_scopes:
    - type: path
      pattern: '**'
      access: write
    - type: network
      posture: 'off'
  network_default: 'off'
  deny_overlays:
    - '.lumenflow/**'

memory_namespace: my-workspace
event_namespace: my-workspace

All ten root keys recognized by the kernel’s WorkspaceSpecSchema:

| Field | Type | Required | Managed By | Description | | ------------------- | ---------- | -------- | -------------------------------- | ------------------------------------------------ | | id | string | Yes | workspace-init | Unique workspace identifier | | name | string | Yes | workspace-init | Human-readable workspace name | | packs | PackPin[] | Yes | pack:install | Array of pack pins to load | | lanes | LaneSpec[] | Yes | lane:edit | Array of lane definitions | | policies | object | No | policy:set | Workspace-level policy overrides | | security | object | Yes | security:set | Workspace-level security config | | software_delivery | object | No | config:set (pack config) | Software Delivery pack configuration (see below) | | control_plane | object | No | config:set (writable root key) | Control plane connection and sync settings | | memory_namespace | string | Yes | config:set (writable root key) | Namespace for memory layer isolation | | event_namespace | string | Yes | config:set (writable root key) | Namespace for kernel event stream isolation |

Root keys fall into three categories based on how they are modified:

  1. Writable root keyscontrol_plane, memory_namespace, event_namespace. These can be written directly with config:set.
  2. Pack config keys — Keys like software_delivery that are declared by a pack’s config_key field in its manifest. Written with config:set and validated against the pack’s config schema.
  3. Managed root keysid, name, packs, lanes, policies, security. These require dedicated CLI commands (shown in the table above). Running config:set on a managed key produces an error with guidance on which command to use instead.

When a pack declares a config_key in its manifest, that key becomes a valid root-level field in workspace.yaml. For example, the Software Delivery pack declares config_key: software_delivery, which makes the software_delivery root key available.

The software_delivery field is optional. If the Software Delivery pack is not pinned in the packs array, the workspace boots without it. This allows workspaces that use other domain packs (or no packs at all) to operate with a minimal kernel-only configuration.

Each entry in the packs array is a pack pin — a versioned, integrity-checked reference to a domain pack that the kernel loads at startup.

| Field | Type | Required | Description | | -------------- | ------ | -------- | ------------------------------------------------------ | | id | string | Yes | Pack identifier (e.g., software-delivery) | | version | string | Yes | Semantic version (e.g., 0.1.0) | | integrity | string | Yes | sha256:<64-hex> hash or dev for local development | | source | string | Yes | One of local, git, or registry | | url | string | No | Source URL (required for git and registry sources) | | registry_url | string | No | Override the default pack registry URL |

The integrity field ensures packs cannot be tampered with. It uses the same sha256:<hex> format as Subresource Integrity (SRI):

  • sha256:<64-char-hex> — Production mode. The kernel verifies the pack manifest hash matches before loading.
  • dev — Explicit non-production bypass for local pack development. It is honored only when the caller sets LUMENFLOW_ALLOW_DEV_PACKS=1 or passes allowDevIntegrity: true to PackLoader.
packs:
  # Production: integrity-verified
  - id: software-delivery
    version: '1.0.0'
    integrity: sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    source: registry

  # Development: skip verification
  - id: software-delivery
    version: '0.1.0'
    integrity: dev
    source: local

Each entry in lanes defines a lane at the kernel level (separate from delivery lane definitions under software_delivery.lanes.definitions).

| Field | Type | Required | Description | | ------------------ | ----------- | -------- | ---------------------------------------------------- | | id | string | Yes | Lane identifier (kebab-case, e.g., framework-core) | | title | string | Yes | Human-readable name (e.g., Framework: Core) | | allowed_scopes | ToolScope[] | No | Scopes this lane grants (defaults to []) | | wip_limit | integer | No | Maximum concurrent active tasks | | policy_overrides | object | No | Lane-level policy configuration |

The lane’s allowed_scopes are used as the second level of the scope intersection algorithm:

effective_scope = workspace ∩ lane ∩ task ∩ tool

The security object defines the workspace-level permission boundary — the outermost layer of the scope intersection.

| Field | Type | Required | Description | | ----------------- | ----------- | -------- | ---------------------------------------------- | | allowed_scopes | ToolScope[] | Yes | Maximum permissions any tool can receive | | network_default | string | Yes | Default network posture: off or full | | deny_overlays | string[] | Yes | Glob patterns for unconditionally denied paths |

Scopes can be path or network types:

security:
  allowed_scopes:
    # Path scope: grant write access to all files
    - type: path
      pattern: '**'
      access: write

    # Network scope: deny all network access
    - type: network
      posture: 'off'

The network scope posture field accepts three values:

| Posture | Description | | ----------- | ----------------------------------------------- | | off | All network access blocked | | allowlist | Only traffic to listed hosts/CIDRs is permitted | | full | Unrestricted network access |

When posture is allowlist, the allowlist_entries field is required:

| Field | Type | Required | Description | | ------------------- | ---------- | ---------------------------- | ---------------------------------------------- | | allowlist_entries | string[] | Yes (when posture=allowlist) | Array of permitted host:port or CIDR entries |

security:
  allowed_scopes:
    - type: network
      posture: allowlist
      allowlist_entries:
        - 'registry.npmjs.org:443' # host:port format
        - 'api.github.com:443' # host:port format
        - '10.0.0.0/24' # CIDR format

The kernel validates that allowlist_entries is present and non-empty when posture is allowlist. Omitting it or passing an empty array produces a Zod validation error at startup.

Network scopes participate in scope intersection across all four layers (workspace, lane, task, tool). See the scope intersection page for the deny-wins semantics and entry-level set intersection behavior.

Paths in deny_overlays are unconditionally denied regardless of scope intersection. The kernel checks these before any other authorization step:

security:
  deny_overlays:
    - '.lumenflow/**' # Kernel state is tamper-proof
    - '.git/**' # Git internals are protected

The kernel validates workspace.yaml against WorkspaceSpecSchema (defined in @lumenflow/kernel) at startup. Invalid specs cause initializeKernelRuntime() to throw with a Zod validation error.

# The kernel validates automatically during initialization.
# There is no separate public CLI validation command for kernel-only workspace specs.
# Validate by booting the kernel runtime with your workspace.yaml in place.

The software_delivery root key is a pack config block owned by the Software Delivery pack. It exists in workspace.yaml only when the pack is pinned and declares config_key: software_delivery in its manifest.

| Concern | workspace.yaml top-level (kernel) | workspace.yaml > software_delivery (pack) | | -------------- | ------------------------------------ | ------------------------------------------- | | Audience | Kernel runtime | CLI and tooling layer | | Lanes | LaneSpec (id, scopes, wip) | Lane definitions (name, code_paths) | | Packs | PackPin (id, version, integrity) | Not present | | Security | Scope intersection boundaries | Git hooks, safe-git wrapper | | Gates | Pack policies (on_completion) | Gate commands, conditional commands | | Validation | Zod WorkspaceSpecSchema at init | Pack config schema via config:set |

The software_delivery.gates block configures quality gate commands and conditional commands.

Pattern-triggered commands that run only when matching files change:

software_delivery:
  gates:
    execution:
      format: 'pnpm format:check'
      lint: 'pnpm lint'
      test: 'pnpm test'

    conditional_commands:
      - trigger_patterns:
          - 'supabase/migrations/**'
          - 'supabase/schema.sql'
        command: 'pnpm db:verify'
        severity: error
        guidance: 'Apply pending migrations before verifying.'
        guidance_ref: 'docs/db-verification-guide.md'

| Field | Type | Required | Description | | ------------------ | ---------- | -------- | ---------------------------------------------------------- | | trigger_patterns | string[] | Yes | Glob patterns matched against changed files (min 1) | | command | string | Yes | Shell command to execute | | severity | string | No | error (default), warn, or off | | guidance | string | No | Actionable text shown on failure | | guidance_ref | string | No | File path whose content is appended to guidance on failure |

See Gates for usage details.

  • Kernel Runtime — How the workspace spec is loaded and used
  • Packs — Domain pack architecture and the Software Delivery Pack
  • Scope Intersection — How workspace security becomes effective permissions
  • Configurationsoftware_delivery configuration reference