> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nodalmerge.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Extending goals

> Inject goals programmatically from CI systems, monitoring alerts, scheduled tasks, and headless peers.

# Extending goals — programmatic goal injection

Goals can be created by humans via the VS Code extension, by autonomous agents via
MCP tools, or by external systems via the REST API. This page covers the REST API
surface and patterns for injecting goals from external triggers.

## GoalNode vs. WorkUnit — the distinction

Every executing goal has two representations:

|                              | WorkUnit                                                       | GoalNode                                                   |
| ---------------------------- | -------------------------------------------------------------- | ---------------------------------------------------------- |
| **What it is**               | Execution container                                            | Decision-centric metadata                                  |
| **Lifecycle**                | `Pending → Active → Proposed → Reviewing → Merged / Abandoned` | `Exploring → Converging → Converged → Blocked → Abandoned` |
| **Owns**                     | Branch, agent assignments, task tree, artifact chain           | Exploration status, parent/child goal hierarchy            |
| **ID relationship**          | Primary identity                                               | `GoalId == WorkUnitId`                                     |
| **What the extension reads** | Activity Center "Active Goals" reads work units directly       | GoalNode records are not yet read by any extension panel   |

For most automation purposes, **creating a work unit is sufficient** — it will
appear in the extension and can have an agent spawned against it. Creating a goal
node additionally enrolls the work unit in the `GoalNode` store, used by
`nm_v1_goal_list` / `GET /studio/goals`.

## REST API

### Create goal + GoalNode (preferred for full metadata)

`POST /studio/goals`

```json theme={null}
{
  "goal": "Fix authentication timeout on /api/login",
  "owner": "ci-pipeline",
  "repositoryId": "repo-abc123",
  "referenceFiles": ["src/Auth/LoginHandler.cs"]
}
```

Response:

```json theme={null}
{
  "goalId": "WU-abc123",
  "workUnitId": "WU-abc123",
  "branchId": "work-abc123",
  "status": "Exploring"
}
```

### Create work unit only

`POST /studio/workunits`

```json theme={null}
{
  "goal": "Fix authentication timeout on /api/login",
  "branchId": "fix/auth-timeout",
  "owner": "ci-pipeline",
  "reviewPolicy": "AgentApproval"
}
```

The `reviewPolicy` field (`HumanRequired` / `AgentApproval` / `Hybrid`) is only
available here. The MCP tool `nm_v1_workunit_create` always defaults to
`HumanRequired`. If `branchId` is omitted, a stable ID is generated from the work
unit ID.

<Note>
  `AgentApproval` and `Hybrid` are available only via `POST /studio/workunits`. To use
  agent-controlled review in an automated pipeline, create the work unit via REST and
  pair with `Workspace:AllowAgentGitCommits=true` for a fully unattended flow.
</Note>

### Spawn an agent after creation

`POST /studio/agents/spawn`

```json theme={null}
{
  "workUnitId": "WU-abc123",
  "agentType": "orchestrator",
  "provider": "anthropic",
  "model": "claude-sonnet-4-6",
  "apiKey": "sk-...",
  "enabledDomainAgents": ["Security", "Test"]
}
```

`enabledDomainAgents` overrides the session-wide `Workspace:EnabledDomainAgents`
setting for this work unit's execution — see [Guides → Domain observers](/studio/guides/domain-observers).

## Visibility in the extension

Work units created by REST or a headless peer appear in the Activity Center and
Goal Workspace identically to interactively created ones — there is no "external
source" badge. The `owner` field on the work unit records the creator identity
(e.g., `"ci-pipeline"`) and is shown in the Decision Lens metadata.

## External trigger patterns

### Pattern 1 — CI failure webhook

```
CI build fails
  → webhook fires to listener
  → POST /studio/goals  { goal: "Investigate build failure: ...", reviewPolicy: "AgentApproval" }
  → POST /studio/agents/spawn  { workUnitId: ..., provider: "anthropic", ... }
  → agent investigates, proposes fix, reviewer agent auto-approves
  → AllowAgentGitPush=true: branch pushed, PR opened externally
```

No headless peer is needed if the Studio host is already running (e.g., via the VS
Code extension).

### Pattern 2 — Monitoring alert handler (persistent peer)

A headless peer (`PeerType: "persistent-agent"`) subscribes to a metrics/alerting
bus. On alert receipt, it injects a goal in-process — no HTTP round-trip needed.
Because the peer is connected to the room (`Peer:HostUri` set), the resulting work
unit and agents appear in the extension in real time. See
[Guides → Headless peer](/studio/guides/headless-peer).

### Pattern 3 — Scheduled maintenance (cron → ephemeral peer)

A cron job launches the peer binary in `--mode peer`. An initialization hook creates
a work unit and spawns an orchestrator at startup. With
`Workspace:AllowAgentGitCommits=true` and `Workspace:AllowAgentGitPush=true`, the
agent commits and pushes its work. The peer exits when the orchestrator finishes.
Set `Workspace:AllowAutoRequeue=false` so a failure surfaces as an exit code, not an
infinite retry loop.
