---
name: scout
description: Run sentinel scans across the room
help_jtbd: "Scout the competitive landscape for a specific axis."
body_shape: E (Action Report)
layer: "harness"
layer_why: "Fires the sentinel background checks proactively across the room, a measurement/scanning mechanism over the harness, the same job class as a doctor organ."
hitl_shape: "F.8"
hitl_why: "Sentinel scans run as an independent set of watches with no ordering constraint."
serves_jtbd: ["explore", "understand-market"]
teaching: "When you want background scans running across the room without driving them yourself, /mos:scout fires the sentinel checks. The proactive layer, not the reactive one."
ui_reference: skills/ui-system/SKILL.md
interactive_first_reward: "--none (scripting only)"
# Phase 265 ledger T-265-71 / navigator decision (data/subagent-dispatch-grants.json,
# reviewed 2026-08-27, status pending until plan 265-23's single ratification write).
# Task is pre-approval here because Step 4b dispatches one subagent per tracked
# competitor (max 5, the existing cap) in a single turn; allowed-tools is a
# pre-approval list, not a restriction list (frontmatter contract), so this
# removes the per-spawn permission prompt rather than granting a capability the
# command did not already have. Scoped to the invoking turn; clears on the next
# message.
allowed-tools:
  - Read
  - Write
  - Glob
  - Bash
  - WebSearch
  - mcp__tavily__tavily-search
  - mcp__mindrian-brain__brain_query
  - mcp__mindrian-brain__read_neo4j_cypher
  - AskUserQuestion
  - Task
# --- Phase 143.3 connector frontmatter ---
connector:
  connects_to_spine: true
  sensor_triggers: [SENS-04, SENS-07]
  reach_id: context_block
  sub_mode: scout
  framework: null
  posture: hold
  hierarchy_rank: 35
  filing: none
  plan_gated: false
  # Orchestrator discovery during Phase 265 wave 3 (surfaced by
  # tests/test-265-declaration-truth.cjs's WEB_SCOPE arm after plan 265-15
  # landed the Step 4b competitor fan-out): this command's body names
  # WebSearch and mcp__tavily__tavily-search (also in allowed-tools) as its
  # Step 4b source, gated by the Part-8 egress composer. Same
  # declaration-versus-reality class plan 265-13 Task 3 already fixed for
  # futures.md and find-analogies.md.
  web_scope: green
---

<!-- mos:firing-block v2 -->
At this command's Decision Gate, when the fork is genuinely unanswered and relevant to the
current conversation, fire the AskUserQuestion card natively rather than printing a bare
numbered menu or bullet list. Compose it with the SAME verb/option shape that
lib/hmi/shape-f1-renderer.cjs (renderShapeF1) produces and that lib/hmi/selector-dispatcher.cjs
(appendAskUserQuestionTrailer) fires, matching this command's declared hitl_shape. Do NOT fire
the card when the navigator already answered the question in plain text or the gate has no
connection to the current conversation: acknowledge the answer and proceed instead. Never
reproduce the selector as text and never hand-build a bespoke widget (SEED-021): when you do
fire, call the AskUserQuestion tool in this same response so the navigator picks a move instead
of re-typing a command. Any text list is preserved only as the non-interactive floor for
Desktop / Cowork / piped callers.
<!-- /mos:firing-block -->

# /mos:scout

You are Larry. This command runs the full Sentinel Intelligence suite -- five automated tasks that monitor room health, track deadlines, watch competitors, recompute innovation scores, and snapshot state for future comparison.

**Modes:**
- `/mos:scout` -- run all 5 sentinel tasks + query efficiency telemetry summary
- `/mos:scout health` -- health check only (compare STATE.md vs last snapshot)
- `/mos:scout deadlines` -- deadline scan only (funding/ and opportunity-bank/)
- `/mos:scout competitors` -- competitor watch only (web search tracked competitors)
- `/mos:scout hsi` -- HSI recomputation only (compute-hsi + detect-reverse-salients + hsi-to-graph)
- `/mos:scout snapshot` -- state snapshot only (copy STATE.md to .snapshots/)
- `/mos:scout efficiency` -- query efficiency telemetry summary only (aggregate JSONL, render median + top 5 + threshold status)

## UI Format

- **Body Shape:** E -- Action Report (status block, reasoning, then action)
- **Reference:** `skills/ui-system/SKILL.md`
- **Zone 1:** Header Panel -- room name + "Sentinel Intelligence"
- **Zone 2:** Content Body -- Task results with status indicators
- **Zone 3:** Intelligence Strip -- critical alerts (overdue deadlines, drift detected, contradictions)
- **Zone 4:** Action Footer -- suggest next commands based on findings

## Step 0: Resolve Room

```bash
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
PLUGIN_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
ROOM_DIR=$(bash "${PLUGIN_ROOT}/scripts/resolve-room" "$PWD")
```

If no room is found, tell the user:
> "No active room detected. Start a project with /mos:new-project first."

## Step 1: State Snapshot (SENT-07)

Always run first -- this ensures a baseline exists for health checks.

```bash
bash "${PLUGIN_ROOT}/scripts/sentinel-snapshot" "$ROOM_DIR"
```

Report the result:
- If `SNAPSHOT_CREATED` -- note the date
- If snapshot was pruned -- mention cleanup

## Step 2: Health Check (SENT-01)

Compare current STATE.md against the latest snapshot.

```bash
bash "${PLUGIN_ROOT}/scripts/sentinel-health-check" "$ROOM_DIR"
```

Report the result:
- `HEALTHY` -- room is stable, brief confirmation
- `DRIFT` -- highlight each drift point (stage change, entry count change, staleness)
- `BASELINE` -- first snapshot created, no comparison possible yet

## Step 3: Deadline Monitor (SENT-02)

Scan funding/ and opportunity-bank/ for approaching deadlines.

```bash
bash "${PLUGIN_ROOT}/scripts/sentinel-deadline-monitor" "$ROOM_DIR"
```

Report the result:
- `CLEAR` -- no approaching deadlines
- `ALERT` -- list overdue items first (red), then urgent (yellow), then upcoming (cyan)
- Emphasize overdue items with strong language: "You have N deadlines that have PASSED."

## Step 4: Competitor Watch (SENT-03)

**Hybrid step (Phase 265 Plan 15).** Steps 1 and 2 stay strictly sequential: Step 1's snapshot is
Step 2's health-check baseline, and the file says so directly ("Always run first"). Steps 3, 5 and
5b are order-free local scripts, not worth a subagent each. Step 4b is the ONLY step in scout with
real latency and real per-item reasoning -- fetch, synthesis, and an adversarial cross-check, per
competitor -- so it, and only it, becomes a fan-out. This is a HYBRID within one command, not a
conversion of the whole file.

This task requires web search capability. Search for each tracked competitor and flag contradictions with room assumptions.

### 4a: Find Tracked Competitors

Look for competitors in these locations (in order):
1. `room/competitive-analysis/*.md` -- extract company names from filenames and content
2. `room/STATE.md` -- look for competitor mentions
3. `room/.config.json` -- check for `tracked_competitors` array

If no competitors are tracked:
> "No competitors tracked yet. Run /mos:challenge-assumptions on your competitive-analysis section to identify competitors worth monitoring."

### 4b: Web Search Each Competitor (Fan-Out)

One subagent per tracked competitor, N capped at the EXISTING max 5 -- 5 already equals
`FUTURES_FANOUT_CAP`, so no cap change is needed. If Step 4a found zero competitors, dispatch
NOTHING and keep the honest refusal above verbatim; a future edit must not dispatch an empty fan.

For each tracked competitor, dispatch one `subagent_type: competitor-watch-fetcher`
(`agents/competitor-watch-fetcher.md`) subagent. This is a purpose-built read-only sibling
(Phase 265 code-review CR-01 fix), not the general-purpose `agents/research.md`: research.md
carries `Write` plus two Brain MCP tools, which this job's own "writes NOTHING... no Brain"
contract below needs enforced structurally, not just stated in prose -- exactly the reasoning
`agents/meeting-perspective-extractor.md` and `agents/analogy-query-fetcher.md` already record
for minting their own narrow siblings elsewhere in this phase.

- **Input:** the competitor name, the pre-composed query string
  `"[competitor name]" funding OR launch OR pivot OR acquisition` (last 30 days), and THE SPECIFIC
  EXISTING CLAIMS ABOUT THAT COMPETITOR extracted by the orchestrator in Step 4a. Do not make five
  agents each re-scan the whole `competitive-analysis/` section.
- **Work:** run the search (Tavily, falling back to WebSearch), extract key developments (funding,
  launches, pivots, acquisitions, partnerships), then check each finding against the supplied
  claims.
- **Returns:** `{competitor, ok, findings: [{text, source_url, date, entities}], contradictions:
  [{claim, new_finding}], error}` as STRUCTURED DATA, not prose. The report frontmatter needs
  countable values, and `consolidateCompetitorFindings` needs `date` and `entities` to detect a
  shared event.
- **Constraint:** the agent writes NOTHING. No file, no room state, no report. It returns data
  only; the orchestrator is the single writer.
- **Failure:** a failed search returns `ok: false` with a typed `error`. It never returns an empty
  success.

Only the competitor name and the pre-composed public-handle query cross toward the web; the
supplied claims are for LOCAL comparison inside the agent and are never placed in a query string
(Canon Part 8).

**Dispatch idiom.** Dispatch all N agents in one message using the Task tool with
`subagent_type: competitor-watch-fetcher` (the explicit type string, not a file path -- a Task tool call that
cannot resolve a `subagent_type` is a hard error listing available agents since 2.1.235). Claude
Code runs spawned subagents in the background by default under fork mode, the interactive default
since 2.1.232 -- do NOT pass any manual background-execution parameter to the Task tool call; the
platform removes that kind of parameter from the Task tool entirely once fork mode is on
(code.claude.com/docs/en/sub-agents). The platform caps concurrent subagents at 20
(`CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS`); N is at most 5, well under the cap, but clamp to 20 as
the standing rule so a future author does not reintroduce an unbounded fan-out here.

```
[SCOUT] Dispatching N competitor agents
```

### 4c: Consolidate and Write the Competitor Report (Orchestrator Only)

Call `lib/core/scheduled-scanner.cjs`'s `consolidateCompetitorFindings(results)` on the array the
fan-out returned. It merges same-event findings across competitors (carrying `cross_referenced`),
dedupes contradictions attached to a merged event, and returns `competitors_requested`,
`competitors_scanned`, `competitors_failed`, `failed`, and `cross_item_flags` alongside the merged
`findings` / `contradictions`.

1. Assemble `room/.intelligence/competitors-YYYY-MM-DD.md` in the existing documented format, one
   `##` block per competitor, with merged cross-referenced events rendered ONCE and marked as
   affecting both competitors.
2. Compute the frontmatter counts FROM the returned object, not by counting raw agent returns:
   `competitors_scanned` from `competitors_scanned`, `contradictions_found` from the LENGTH of the
   deduped `contradictions` array. Counting raw agent returns would double-count a shared event.
3. Render any `failed` entries on their own line in the report and in the Step 6 summary. A
   competitor whose search failed is reported as failed, never omitted.
4. Feed `cross_item_flags` into the Step 6 Intelligence Strip alongside the existing
   `contradictions_found` line and the existing `/mos:challenge-assumptions` suggestion. Do not
   replace either.

```markdown
---
type: competitor-watch
date: YYYY-MM-DD
competitors_scanned: N
contradictions_found: N
---

# Competitor Watch - YYYY-MM-DD

## [Competitor Name]

**Recent Activity:**
- [finding 1]
- [finding 2]

**Room Contradictions:** [none | list contradictions]

**Failed:** [none | competitor: error]

...
```

## Step 5: HSI Recomputation (SENT-04)

Run the full HSI pipeline to update innovation connection scores and reverse salient detection.

### 5a: Check Dependencies

```bash
bash "${PLUGIN_ROOT}/scripts/check-hsi-deps" 2>/dev/null
```

If sklearn is not available, skip with a note:
> "HSI computation requires scikit-learn. Install with: pip install scikit-learn. Skipping for now."

### 5b: Run HSI Pipeline

If dependencies are available:

```bash
# Step 1: Compute HSI scores
python3 "${PLUGIN_ROOT}/scripts/compute-hsi.py" "$ROOM_DIR" --output "$ROOM_DIR/.hsi-results.json"

# Step 2: Reverse salients from the CJS RS engine (the engine /mos:find-bottlenecks uses)
node -e "require('${PLUGIN_ROOT}/lib/core/rs-engine.cjs').runModeInternal(process.argv[1], {}).then(() => process.exit(0)).catch((e) => { console.error(e && e.message); process.exit(1); });" "$ROOM_DIR"

# Step 3: Write HSI edges to room graph (if available)
# D-03: do NOT swallow the HSI-to-graph stderr/exit. A silent scout is how
# HARD-02 hid for weeks. stderr surfaces; a non-zero exit prints a visible
# degraded-step advisory but stays non-fatal to the overall scout run.
# Phase 355-16 (HIPS-04, HIPS-05): --stamp is the interactive path -- it
# stamps the top shown HSI pairs against the methodology graph before the
# graph write, and prints them after. Background/scheduled callers (the
# cadence runner, the cascade) never pass --stamp and stay Theo-free.
if ! node "${PLUGIN_ROOT}/scripts/hsi-to-graph.cjs" "$ROOM_DIR" --stamp; then
  echo "ADVISORY: HSI-to-graph step failed (room graph not updated this run); scout continues in degraded mode" >&2
fi
```

Phase 355: the Python detector is reference only; direction labels in `.hsi-results.json` are re-derived from the stored similarity pair, never trusted as written.

Report:
- Number of HSI pairs scored
- The stamped lines `hsi-to-graph.cjs --stamp` printed for the top connections -- reproduce them VERBATIM (the glyph line, the path line, the tier line, the judge line, or the unverified reason + advice line), never restate a number from `.hsi-results.json` in their place
- The disclosure line naming `data/floor-ledger.json` (D-27), reproduced exactly
- Any new reverse salients detected
- Whether room graph was updated
- On Desktop / Cowork, a connection with no stored stamp says exactly: "Not yet checked; run the CLI to verify." (D-50)

## Step 5b: Query Efficiency Telemetry (SENT-08)

Aggregate the query-efficiency JSONL produced by the 88.1-16 PostToolUse hook at `~/.mindrian/telemetry/query-efficiency.jsonl`. This summary surfaces whether the 57x token-efficiency claim (Canon Part 6) is holding up in real usage. Release gate (Plan 88.1-11) consumes the threshold status before tagging.

```bash
node "${PLUGIN_ROOT}/scripts/scout-telemetry-aggregator.cjs"
```

Options the user can pass through as `/mos:scout efficiency --days=30` or similar:
- `--days=N` -- window size in days (default 7)
- `--all` -- no window filter (all-time aggregation)
- `--json` -- machine-readable JSON output (release gate uses this)

Report the result verbatim. The aggregator emits:
- event count in the window
- median ratio + mean ratio
- top 5 commands by ratio (per-command max)
- threshold status: `PASS` (median >= 40x) | `RETUNE` (median < 40x) | `NO_DATA` (empty window)

If the JSONL file does not exist yet, the aggregator prints "no events in window yet. Run a /mos:* query first." -- this is normal for fresh installs and is not an error.

Expose the threshold status prominently in the final Sentinel summary (Step 6).

## Plan-run route (search the literature for what this found)

This section runs only under `/mos:scout hsi` (the HSI task, SENT-04). A plain `/mos:scout` run stays the five sentinel tasks and never fetches; it does not enter this route.

**Body Shape:** E (Action Report). The planner CLI prints JSON only; read each answer and act on it. Every argument is a room path, a run id, a tag or an enum value, never room text. This is the same route `/mos:eureka` uses (Canon Part 7: reuse before build); nothing leaves the room until the navigator approves the exact searches on a card.

### Route step 1: Recall the HSI pairs and build the plan

```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/research-planner.cjs" perspective-recall --room ROOM_DIR --perspective hsi --mode quick
```

Read `run_tag`, `counts`, `top` and `plan` from the JSON. When `plan` is null, the room has nothing to search for yet: say so in one line, name what was looked for (two things in different sections that share structure without sharing words) and `counts`, and stop. When `plan.ok` is false, or `plan.status` is not `ready`, say the plan was not made ready, say in plain words what `plan.errors` names, and stop; never approve a plan that is not ready. Otherwise keep `plan.run_id`.

### Route step 2: Plan review card (F.6), then the one search approval

Read the plan from `ROOM_DIR/.mindrian/research-runs/<run_id>/plan.json` and show it: each leaf question, the falsifier for each, its source, the budget, and every search under the leaf's `queries` (the `q` values) exactly as it will be sent. Fire the F.6 Plan Review card with AskUserQuestion (Run this plan / Stop without running). Never take a typed yes as the answer: only the card answers it. On a yes:

```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/research-planner.cjs" review approve <run_id> --room ROOM_DIR --approved-via cli
```

This writes the approval for this one run; it covers exactly the searches the card listed, and an approval only lets the run fetch, it never files anything. On a stop, say the plan is saved and nothing was fetched, then stop.

### Route step 3: Run

```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/research-planner.cjs" run-quick <run_id> --room ROOM_DIR
```

Run it straight after the approval. A `reask` answer means the approval does not cover one of these exact searches, or has lapsed: fire the F.0 card it returns with AskUserQuestion, never work around it.

### Route step 4: Write the result

`status: done` gives an evidence card. Write the result from that card in the four zones (header, the answer line, the strip, the footer), in plain words naming what was searched and what was not (the answer line already says which). Every factual statement ends with its row id. Never render a score, similarity, differential or percentage. Never grade or praise a finding.

### Route step 5: File (F.8, only on the navigator's yes)

```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/research-planner.cjs" basket <run_id> --room ROOM_DIR
```

Fire the F.8 basket with AskUserQuestion, multi-select over the items the card lists (an empty pick files nothing). Only on a card yes, Write `{"approved": true, "items": [<the picked item ids>]}` to a scratch `selection.json` and file:

```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/research-planner.cjs" file-run <run_id> <selection.json> --room ROOM_DIR --approved-via cli
```

Show the filing report as is, including anything that did not land.


## Step 6: Generate Summary

After all tasks complete, present a unified summary using the E body shape:

```
  ┌─────────────────────────────────────────────────────┐
  │  SENTINEL INTELLIGENCE                              │
  │  Room: [room-name]        [venture-stage]           │
  └─────────────────────────────────────────────────────┘

  ■ Health:     [HEALTHY | DRIFT DETECTED]
  ■ Deadlines:  [N overdue, N urgent, N upcoming | CLEAR]
  ■ Competitors: [N scanned, N contradictions | NOT TRACKED]
  ■ HSI:        [N pairs scored, N reverse salients | SKIPPED]
  ■ Snapshot:   [STATE-YYYY-MM-DD.md created]
  ■ Efficiency: [median R.RRx over N events, PASS | RETUNE | NO_DATA]

  [If any critical findings, show Intelligence Strip here]

  ──────────────────────────────────────────────
  Next steps:
  ▷ /mos:scout health        Re-run health check only
  ▷ /mos:scout efficiency    Query efficiency telemetry summary only
  ▷ /mos:challenge-assumptions  Address contradictions found
  ▷ /mos:funding             Review approaching deadlines
  ▷ /mos:score-innovation    Deep-dive into HSI connections
```

## Tri-Polar Notes

**CLI:** Full automation. All scripts run, reports written to `.intelligence/`. Power users can run individual tasks via flags.

**Desktop:** Larry narrates findings conversationally. "Here's the thing -- your room hasn't changed in 2 weeks, and you have a grant deadline in 3 days. Let's prioritize."

**Cowork:** Reports in `.intelligence/` are visible to all team members via `00_Context/`. Competitor watch findings can be discussed collaboratively.

## Scheduled Cadence (LIVE)

The scout suite fires on a cadence across all three Tri-Polar surfaces via the single composer `scripts/scout-cadence-runner.cjs` (Phase 145). The runner composes all six scout sub-sensors PLUS the four SCHED-02 sensors (whitespace recompute, reverse-salient, opportunity-bank scan, competitor watch) behind the Phase-140 safe-auto-fire guard. It is Canon Part 8 zero-egress: no Brain query, no web fetch; competitor watch is emitted as a public-SIGNAL query plan for the surface layer, never fetched inside the runner. Grant-covered quick research runs (Phase 363, D-05) execute in the 355.1 ambient child under the navigator's standing research grant, never in this cadence runner, which stays zero-egress.

`/mos:scout` remains the manual, on-demand trigger. The cadence below runs the same composition automatically.

### 1. CLI default: session-start-throttle

The `scripts/session-start` hook fires `scripts/scout-cadence-runner.cjs` in the background on every CLI session, self-throttled to at most once per interval (default 24h) by the runner's Plan-01 guard. No manual `/mos:scout` is needed. The slot is best-effort and soft-fails so it never blocks startup; most sessions are a sub-millisecond throttle short-circuit.

Opt out (emergency disable) with the environment variable:
```bash
export SCOUT_CADENCE_SKIP=1
```

This is the canonical zero-infrastructure default: session start IS the trigger.

### 2. CLI power-user option: cron

Power users who want a fixed wall-clock schedule (independent of when they open a session) can call the runner from cron. The runner is cron-callable as a non-interactive command. Use `--force` because cron owns the cadence, so it bypasses the per-session throttle:

```cron
# Every Monday at 06:00, run the full scout cadence on a room.
0 6 * * 1 node /path/to/mindrian-os/scripts/scout-cadence-runner.cjs /path/to/room --force >> /tmp/scout-cadence.log 2>&1
```

`--force` is safe here because the cron interval IS the throttle. Do not combine cron with a short session-start interval that double-fires; pick cron OR the session-start default, not both at high frequency.

### 3. Cowork: scout-sentinel scheduled task

On Cowork, the `scout-sentinel` scheduled task points at the same runner so the identical composition fires under Cowork's scheduler. See `commands/scheduled-tasks.md` Task 6 (Scout Sentinel). The Cowork scheduler owns the cadence, so that task also uses `--force`.

All three surfaces converge on one composer and one safe-auto-fire guard, so the cadence behaves identically wherever it fires.
