Domain observers
Domain observers are six reactive agents built into the Studio runtime that watch
the artifact stream and propose constraints when they detect a gap relevant to their
domain. They run in-process, fire-and-forget, and produce only artifacts — they
cannot create goals, spawn work units, schedule tasks, or write files.
The six observers
| Observer | Triggered by keywords (sample) |
|---|
| Security | auth, authn, authz, login, password, token, jwt, oauth, session, credential, secret, permission, role, acl, encrypt, csrf, xss, sql injection, cors, cookie |
| Architecture | architecture, framework, library, module boundary, service boundary, coupling, dependency graph, design pattern, microservice, monolith, scalability, migration |
| Performance | performance, latency, throughput, n+1, cache, caching, benchmark, memory leak, allocation, slow query, timeout, concurrency, lock contention, rate limit |
| Test | test coverage, unit test, integration test, flaky, test gap, regression, mock, test fixture, e2e, untested |
| Documentation | documentation, docs, readme, api doc, changelog, undocumented, doc gap |
| UX | ux, usability, accessibility, a11y, user flow, ui, design system, user experience, onboarding, error message, confusing |
Enabling observers
Observers are disabled by default (empty list). Enable them by adding agent
names to Workspace:EnabledDomainAgents in appsettings.json:
{
"Workspace": {
"EnabledDomainAgents": ["Security", "Architecture", "Test"]
}
}
Valid names: Security, Architecture, Performance, Test, Documentation,
UX. The value is case-sensitive. Changes require a host restart.
Per-work-unit override
When spawning an orchestrator via POST /studio/agents/spawn, pass
enabledDomainAgents to override the session default for that specific work unit’s
execution:
{
"workUnitId": "WU-abc123",
"agentType": "orchestrator",
"enabledDomainAgents": ["Security"]
}
This is captured at spawn time and does not change if the session default is later
updated.
There is no panel in the VS Code extension to toggle observers per goal today.
Configuration is via appsettings.json (global) or the enabledDomainAgents field
on agent spawn (per work unit).
How observers trigger
After any Research, Decision, or Constraint artifact is recorded against a
work unit, the trigger pipeline runs for each enabled observer:
- Type filter — only
Research, Decision, Constraint artifacts are
considered. Other artifact types (Plan, Task, MergeProposal, etc.) do not trigger
observers.
- Loop prevention — artifacts whose title starts with an observer’s title
prefix (e.g.,
[SecurityAgent] ) do not re-trigger that observer. This prevents
an observer’s own output from cascading back into itself or cross-triggering
peers.
- Keyword heuristic — the artifact’s title and body are scanned for the
observer’s keywords. If no keyword matches, the observer is skipped for that
artifact.
- Spawn — an observer loop starts fire-and-forget. Failures do not affect the
artifact that triggered them.
What an observer can do
Each observer receives exactly four MCP tools:
| Tool | Purpose |
|---|
nm_v1_projection_get | Read the work unit’s artifact chain + inherited constraints |
nm_v1_artifact_query | Search for existing constraints to avoid duplicates |
nm_v1_workspace_search | Grep workspace files to corroborate a finding |
nm_v1_artifact_record | Record a Constraint or Research artifact |
The observer’s LLM loop (max 8 iterations) uses these tools to decide whether a
concrete gap exists. If yes, it records a Constraint; if the gap is already
covered or doesn’t apply, it does nothing. Observers never call write, build, test,
or merge tools.
What observers produce
Observers emit Constraint artifacts for concrete, specific gaps (e.g., “Missing
CSRF protection on the password-reset endpoint”) or Research artifacts for
findings that don’t rise to an actionable constraint. Constraints proposed by
observers appear in the Decision Lens Context tab’s artifact chain, identifiable by
their title prefix — see Reference → Control Tower UI.