workspace.yaml agents
The software_delivery.agents block configures which agent client LumenFlow prefers, which agent
names are considered part of the workspace roster, and which of those agents become mandatory for
matching code paths.
Client configuration is descriptive, not authority. Every harness uses the versioned universal capability contract for methodology, WU operations, lifecycle, initiative planning, delegation, model/effort control, and application attestation. Model control, effort control, and application attestation remain separate outcomes, including model-only or effort-only host evidence. Missing or unknown capabilities fail safe; client names and host memory/cache cannot grant authority or synthesize a canonical brief. The release-evidence-indexed contract digest and lifecycle-issued brief/WU/workspace/HEAD evidence must all match before routing is verified.
Fields
Section titled “Fields”agents.defaultClient
Section titled “agents.defaultClient”Preferred client ID when a command needs an agent client and the caller did not pass one explicitly.
- Type:
string - Default:
claude-code
agents.roster
Section titled “agents.roster”The workspace-level list of agent names the orchestration surface should treat as valid. When you omit this field, LumenFlow uses the built-in framework roster:
-
general-purpose -
lumenflow-pm -
test-engineer -
code-reviewer -
bug-triage -
lumenflow-enforcer -
initiative-architect -
Type:
string[] -
Default: the built-in agent roster above
agents.mandatory.names
Section titled “agents.mandatory.names”Subset of agents.roster that may be enforced as mandatory when a matching trigger fires.
- Type:
string[] - Default:
[]
agents.mandatory.triggers
Section titled “agents.mandatory.triggers”Maps mandatory agent names to glob patterns. If a WU touches a matching path, that agent becomes mandatory for the workflow surfaces that consume mandatory-agent rules.
- Type:
Record<string, string[]> - Default:
{}
Example:
agents.clients.<client>.agentsDir
Section titled “agents.clients.<client>.agentsDir”Optional compatibility metadata for a project-owned client agent-definition directory. LumenFlow
does not create, modify, or treat this directory as a managed surface; it remains separate from the
workspace roster and canonical .lumenflow/skills/ contract.
- Type:
string - Default: inherits the global directory default for that client
agents.clients.<client>.capabilities
Section titled “agents.clients.<client>.capabilities”Declarative capability flags for a client, consumed by the idle-orchestrator
push adapter port (ADR-019’s idle-session delivery amendment, WU-3782). This
key previously carried a different, vendor capability-resolution shape
(native_signal_hooks, settings_projection, enforcement_hooks,
brief_renderer) that was retired: LumenFlow does not project settings,
generate hooks, or gate brief rendering by client membership. It answers one
narrow capability question — “does this client expose a native push channel
this workspace can actually use to wake an idle session?” — and it is
data-driven: setting the flag never by itself proves the channel is usable,
it only tells LumenFlow to attempt a real per-host delivery instead of
skipping straight to the always-available fallback.
- Type:
object - Default:
{ harnessPush: false }for every client, including the built-in ones. No client declares this on by default.
| Field | Type | Meaning |
|---|---|---|
harnessPush | boolean | This client declares a native push/notification channel to its own session. Selection is by this flag alone, never by client name. Default: false. |
Declaring the flag is not the same as it working. Once harnessPush: true
is declared, the push port attempts a REAL per-client delivery (vendor names
live only in that adapter code, never in this config) and reports its own
outcome. As of this WU, LumenFlow ships adapters for claude-code and
codex-cli, and both report an explicit unsupported-on-host result rather
than a silent fake success — see the ADR-019 idle-session delivery amendment
for why. An unknown/BYOK client id that sets the flag with no matching
adapter gets the same honest treatment: an unsupported-on-host result
naming the client id, never a thrown error and never a silent no-op. The
durable JSONL wake-channel record mem-watch-fallback writes is the real
delivery for every host today — orchestrate:monitor --watch or mem:watch
is the prescribed orchestrator-side watcher regardless of this flag.
agents.lifecycle_enforcement.ci.runs_on
Section titled “agents.lifecycle_enforcement.ci.runs_on”GitHub Actions runner label(s) for the generated .github/workflows/lumenflow-ci.yml
enforcement job. lumenflow:enable and lumenflow:upgrade regenerate that workflow from a
template whose default is ubuntu-latest; setting this field is what makes a self-hosted
runner pool survive that regeneration instead of silently reverting to paid GitHub-hosted
minutes on the next enable/upgrade (WU-3941).
- Type:
string | string[] - Default: unset (the generated workflow keeps the template’s
ubuntu-latestdefault)
Only runs_on is modeled today. The rest of agents.lifecycle_enforcement (enabled,
policy_version, integrity_manifest) is managed by lumenflow:enable/lumenflow:disable,
not hand-edited.
Defaults And Partial Overrides
Section titled “Defaults And Partial Overrides”Nested agent config merges with defaults instead of replacing the whole structure. For example, this partial override keeps the built-in roster and default client while only adding trigger rules:
Likewise, setting only mandatory.names no longer removes the default mandatory.triggers object.
Agent configuration does not grant lifecycle authority. Repository-owned delegators and the
integrity manifest protect lifecycle evidence for every declared client, and only an enforced
lumenflow:doctor state is certifying. A hostile unsandboxed process with the same OS-user authority
can replace local code, hooks, or receipts; preventing that requires an OS sandbox or protected
remote/server authority. Disabled and uninstalled consumers cannot claim lifecycle certification.
Migration
Section titled “Migration”If your workspace previously only used:
you do not need to change anything. That configuration still works.
Add the new fields only when you need them:
- Add
agents.rosterwhen you want to declare a custom or narrowed set of agent names. - Add
agents.mandatory.nameswhen some of those agents should become enforceable. - Add
agents.mandatory.triggerswhen you want code-path-based mandatory-agent detection. - Add
agents.clients.<client>.agentsDirwhen a client should resolve agent definitions from a non-default directory. - Add
agents.clients.<client>.capabilities.harnessPushonly when you want the idle-orchestrator push port to attempt a real per-host delivery for that client instead of going straight to the always-availablemem-watch-fallbackadapter. Omitting it (the default for every client) never loses delivery — the fallback adapter already covers every host.
Validation Rules
Section titled “Validation Rules”The authoritative schema enforces two cross-field rules:
- Every name in
agents.mandatory.namesmust also appear inagents.roster. - Every key in
agents.mandatory.triggersmust also appear inagents.mandatory.names.
Those rules keep the roster, mandatory list, and trigger map aligned as you customize the workspace.