Skip to content
Development
Command

/signal-planner

Closed-loop autonomy — convert a production/analytics/incident signal into a dependency-ordered issue DAG, execute via /orchestrate, then verify the originating signal is resolved. Event-driven companion to /autopilot.

BOOST
From plugin
forgedock
11980 skills80 commands
Install
> /plugin marketplace add RapierCraftStudios/ForgeDock
> /plugin install forgedock@forgedock

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/signal-planner

Context preview

What this command does when you run it.

Closed-loop autonomy — convert a production/analytics/incident signal into a dependency-ordered issue DAG, execute via /orchestrate, then verify the originating signal is resolved. Event-driven companion to /autopilot.

Command definition

signal-planner.md
description: Closed-loop autonomy — convert a production/analytics/incident signal into a dependency-ordered issue DAG, execute via /orchestrate, then verify the originating signal is resolved. Event-driven companion to /autopilot.
argument-hint: "[--signal '<json>' | --metric '<name> <threshold>' | --incident <issue#> | --geo | --dry-run | --max-issues N]"
install: extras

<!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios --> <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->

/signal-planner — Closed-Loop Production Signal to Verified Resolution

> **Skill names**: `{FORGE_SKILL_PREFIX}` is `forgedock:` (plugin install) or empty (`install.sh`), resolved once per run by `commands/work-on.md` § Skill Name Resolution. If the skill is not found under either name, STOP and report "skill not found" — never run the phase inline.

**Input**: $ARGUMENTS

**Config variables used by this command** (set in `forge.yaml`):

  • `{CREDENTIALS_FILE}` ← `paths.credentials.file` (optional) — path to credentials YAML for analytics APIs
  • `{BILLING_ENABLED}` ← `billing.enabled` (optional, default `false`) — enable Stripe data in signal hydration
  • `{GOVERNOR_MAX_ISSUES}` ← `governor.max_issues_per_run` (optional, default `10`) — hard cap on issues spawned per run
  • `{GOVERNOR_MAX_COST_USD}` ← `governor.max_cost_usd` (optional, default `5.00`) — hard cap on estimated LLM spend per run

**NEVER use plan mode (EnterPlanMode).** **NEVER use the Agent tool** for implementation work — dispatch issues via `Skill(skill="{FORGE_SKILL_PREFIX}work-on", ...)` or via `/orchestrate`.

<!-- FORGE:SPEC_LOADED — signal-planner.md loaded and active. Agent is bound by this spec. -->

You are the closed-loop autonomy engine. Your job is to accept a production signal (metric regression, incident event, GEO gap), plan a dependency-ordered issue DAG, execute it via `/orchestrate`, and then verify the originating signal is resolved. You close the loop from observation to verification — no human needs to author a single issue.

---

Argument Parsing

Parse `$ARGUMENTS` and set:

SIGNAL_JSON        = raw JSON from --signal '...' (if provided)
SIGNAL_METRIC      = metric name + threshold from --metric '<name> <threshold>' (if provided)
SIGNAL_INCIDENT    = issue number from --incident <N> (if provided)
SIGNAL_GEO         = true if --geo flag present
DRY_RUN            = true if --dry-run present
MAX_ISSUES_OVERRIDE = N from --max-issues N (if provided)

**Signal source priority** (first match wins): 1. `--signal` — structured JSON signal (most precise) 2. `--metric` — named metric with threshold breach 3. `--incident` — P0/P1 incident issue number 4. `--geo` — run geo-audit sensor for GEO gaps 5. *(no flag)* — interactive: print usage and exit

If no recognized signal flag is present, print:

/signal-planner requires a signal source. Examples:

  /signal-planner --signal '{"type":"metric","name":"gsc_clicks","value":1200,"baseline":2000,"window":"7d"}'
  /signal-planner --metric "checkout_latency_p99 >2000ms"
  /signal-planner --incident 55
  /signal-planner --geo
  /signal-planner --dry-run --signal '...'   # plan only, no issues created

Then exit.

---

Phase 0: Economic Governor (MANDATORY — run before ANY side effects)

**Goal**: Prevent runaway spend. Hard-fail if governor limits would be breached.

0A: Resolve governor config

FORGE_YAML="${FORGE_CONFIG:-$(git rev-parse --show-toplevel 2>/dev/null)/forge.yaml}"

GOVERNOR_MAX_ISSUES=$(python3 -c "
import yaml, sys
cfg = yaml.safe_load(open('$FORGE_YAML')) if __import__('os').path.exists('$FORGE_YAML') else {}
print(cfg.get('governor', {}).get('max_issues_per_run', 10))
" 2>/dev/null || echo "10")

GOVERNOR_MAX_COST=$(python3 -c "
import yaml, sys
cfg = yaml.safe_load(open('$FORGE_YAML')) if __import__('os').path.exists('$FORGE_YAML') else {}
print(cfg.get('governor', {}).get('max_cost_usd', 5.00))
" 2>/dev/null || echo "5.00")

# Apply per-run override
if [ -n "$MAX_ISSUES_OVERRIDE" ]; then
  GOVERNOR_MAX_ISSUES=$(( MAX_ISSUES_OVERRIDE < GOVERNOR_MAX_ISSUES ? MAX_ISSUES_OVERRIDE : GOVERNOR_MAX_ISSUES ))
fi

0B: Record governor state

Store `GOVERNOR_MAX_ISSUES` and `GOVERNOR_MAX_COST` as the hard caps for this run. They are checked in Phase 3 before any issue is created. Exceeding them is a hard fail — not a warning.

Print:

[signal-planner] Governor: max_issues={GOVERNOR_MAX_ISSUES}, max_cost_usd={GOVERNOR_MAX_COST}

---

Phase 1: Signal Intake & Hydration

**Goal**: Normalize the raw input signal into a typed, structured `SIGNAL` object and hydrate it with enough context to plan work.

1A: Normalize the signal

Build `SIGNAL` from the input:

SIGNAL = {
  type:      "metric" | "incident" | "geo" | "raw",
  name:      <human-readable signal name>,
  raw_input: <original input string or JSON>,
  severity:  "P0" | "P1" | "P2" | null,
  context:   {}   # filled in 1B
}

**For `--signal <json>`**: Parse JSON directly. Map `type` field; if absent, classify from content.

**For `--metric <name> <threshold>`**: Set `type="metric"`, `name=<name>`. Parse threshold string (e.g., `>2000ms`, `<80%`, `dropped 30%`). Set `severity` based on magnitude:

  • >50% regression or latency >5x baseline → P0
  • 20–50% regression → P1
  • 10–20% regression → P2

**For `--incident <N>`**: Fetch the issue:

gh issue view {N} -R {GH_REPO} --json number,title,body,labels,state \
  --jq '{number: .number, title: .title, severity: (.labels | map(.name) | map(select(startswith("priority:"))) | .[0]), state: .state}'

Set `type="incident"`, `name="incident #N: {title}"`, `severity` from label.

**For `--geo`**: Set `type="geo"`, `name="GEO compliance gap"`, `severity="P2"`. Hydration (1B) will call `/geo-audit`.

1B: Hydrate context

Fetch live data to fill `SIGNAL.context` based on signal type:

**For `type="metric"`**:

  • Read credentials from `{CREDENTIALS_FILE}` (from `forge.yaml`)
  • Pull the named metric fro
Read more
Ships withforgedock

ForgeDock — autonomous AI dev pipeline for Claude Code. GitHub as agent memory: issue in, PR out.

Get the whole plugin

Other commands on forgedock.