Validates and persists signal files to the yahoo-mlb signals directory. Every MLB skill calls this skill before writing a signal. Enforces the signal-framework.md schema -- required YAML frontmatter fields (type, date, emitted_by, confidence, source_urls), range-checks numeric signals (0-100 unipolar, -100 to +100 bipolar), verifies variant_synthesis metadata, and enforces file naming. On validation failure, does not persist and routes a failure entry to mlb-decision-logger. Use when an agent or skill needs to emit a signal, validate a signal file, write to signals/YYYY-MM-DD-<type>.md, or check signal frontmatter. Triggers — "emit signal", "validate signal", "write signal file", "signal frontmatter".
Action: Write to yahoo-mlb/signals/2026-04-17-player-caminero.md and return the absolute path.
Failure scenario: If confidence: 1.4 had been passed, validation fails. The skill does NOT write the file. It calls mlb-decision-logger with a failure entry: kind: signal_validation_failure, signal_type: player, reason: confidence out of range (1.4 not in [0.0, 1.0]), emitter: mlb-player-analyzer, and returns an error to the calling agent.
The caller hands in three things: (1) YAML frontmatter key-value pairs, (2) signal body (markdown tables), (3) intent (e.g., "this is a final synthesized signal" vs. "this is an intermediate variant dump"). See resources/template.md for the canonical input shape.
Frontmatter fields collected
Body (markdown tables) supplied
Intent known: final vs. variant-intermediate
Step 2: Validate YAML frontmatter
Confirm all required keys are present and well-typed. See resources/methodology.md for the full list.
type present and in the allowed enum (lineup, waivers, streaming, trade, category-plan, playoff-push, player, matchup, regression, two-start, closer, faab, cat-state)
date present and formatted YYYY-MM-DD
emitted_by present and references a known skill or agent
confidence present as a float in [0.0, 1.0]
source_urls present as a non-empty list of URLs
Step 3: Range-check numeric signals
Every numeric signal in the body must fall inside its declared range. See resources/methodology.md for the per-signal range table (it mirrors signal-framework.md).
Bipolar signals (regression_index, positional_flex_delta) in [-100, +100]
Integer signals (playoff_games) >= 0
Dollar signals (acquisition_value, faab_max_bid, faab_rec_bid) >= 0
Enum signals (cat_position, verdict) inside their declared allowed sets
Step 4: Validate variant synthesis metadata
If this is a synthesized final signal, it must declare which variants produced it.
If variant_synthesis: true, variants_fired is a list with >= 1 entry
If variant_synthesis: true, synthesis_confidence is present and in [0.0, 1.0]
If variant_synthesis: false, the file is an intermediate variant dump; filename must include the variant suffix (see Step 5)
red_team_findings (if present) is a list of objects with severity, likelihood, score, note fields
Step 5: Determine and validate file path
The canonical path is yahoo-mlb/signals/YYYY-MM-DD-<type>.md. For an intermediate variant dump, use YYYY-MM-DD-<type>-<variant>.md. For per-player or per-game files, an optional identifier suffix is allowed: YYYY-MM-DD-<type>-<identifier>.md.
Compute path from date and type in frontmatter
Check that a signal of this type+date does not already exist unless the caller explicitly passed overwrite: true
Ensure the parent directory exists (create if missing)
Reject paths that escape the signals/ directory
Step 6: Write file OR log validation failure
If all checks pass: write the file, return the absolute path. If any check fails: do NOT write, call mlb-decision-logger with a structured failure entry, return an error object to the caller. See resources/methodology.md for the failure log schema.
On pass: write file, return absolute path
On fail: build failure object (reason, field, expected, actual), send to mlb-decision-logger, return error
Required numeric signals in body: daily_quality, plus the three components (form_score, matchup_score, opportunity_score)
Always a final synthesized signal when emitted by mlb-player-analyzer -- so variant_synthesis: true and variants_fired: [advocate, critic]
Source URLs must include Baseball Savant, FanGraphs, and MLB.com (confirmed lineup)
Pattern 2: Daily lineup roll-up (type: lineup)
Filename: YYYY-MM-DD-lineup.md
Body references, by name, the per-player signal files it consumed (provenance chain)
synthesis_confidence reflects agreement between the advocate (bat-everyone) and critic (sit-risky) variants
Red-team findings typically flag weather, role uncertainty, or fragile platoon calls
Pattern 3: Intermediate variant dump (variant suffix in filename)
Filename: YYYY-MM-DD-<type>-advocate.md or YYYY-MM-DD-<type>-critic.md
variant_synthesis: false (this IS a variant, not a synthesis)
emitted_by names the agent and variant (e.g., mlb-lineup-optimizer/advocate)
The synthesizing agent reads these two intermediate files, produces the final synthesized signal, then emits with variant_synthesis: true
Pattern 4: Low-confidence graceful degrade
When a web search fails, the upstream skill should still emit a signal but with confidence <= 0.3 and a red_team_findings entry flagging the missing data source
This skill does NOT reject low-confidence signals -- low confidence is legitimate. It only rejects out-of-range or missing fields.
Flag in body: "Could not verify opposing pitcher; using prior-start proxy."
Guardrails
Never silently drop a signal. If validation fails, the failure must be logged via mlb-decision-logger so the calibration review can see what was rejected and why. A signal that never gets written AND never gets logged is invisible to the team.
Do not re-derive signal values. This skill is a validator and file-writer only. It never computes daily_quality or any other signal itself. If an upstream skill passes in a half-computed signal, reject it rather than filling in the blanks.
Reject unknown type values. The enum in signal-framework.md is the authoritative list. If a caller passes type: vibe-check, reject and log. Adding a new signal type requires updating signal-framework.md first, then this skill's validator.
Range checks are hard limits. A form_score of 105 is not "close enough" -- it indicates a bug upstream (probably forgot to normalize). Reject and log. Do NOT clamp-and-accept.
confidence is required, not optional. Even a perfectly-computed signal with three source URLs must carry a confidence float. A missing confidence is a validator failure, not a warning.
source_urls must be a non-empty list. Per CLAUDE.md rule 1 ("Web-search everything"), every factual signal is backed by a live source. An empty source_urls list means the signal was not grounded -- reject and log.
Variant synthesis claims must be provable. If variant_synthesis: true but variants_fired is empty or missing, that is a lie about the team's process. Reject and log.
Do not overwrite without explicit consent. If a signal already exists at the target path, refuse to overwrite unless the caller passes overwrite: true. This prevents losing an earlier morning's signal when a mid-day re-run happens.
Quick Reference
Required frontmatter fields (always):
type (enum)
date (YYYY-MM-DD)
emitted_by (string)
confidence (float 0.0-1.0)
source_urls (non-empty list)
Required when variant_synthesis: true:
variants_fired (list, >= 1)
synthesis_confidence (float 0.0-1.0)
File path conventions:
Final synthesized: signals/YYYY-MM-DD-<type>.md
With identifier: signals/YYYY-MM-DD-<type>-<id>.md
resources/evaluators/rubric_mlb_signal_emitter.json: 8 criteria for evaluating the emitter's behavior
Inputs required:
Frontmatter key-value pairs from caller
Signal body (markdown tables)
overwrite flag (default false)
Outputs produced:
On success: absolute file path of the written signal
On failure: error object; a failure entry appended to tracker/decisions-log.md via mlb-decision-logger
1---
2name: mlb-signal-emitter
3description: Validates and persists signal files to the yahoo-mlb signals directory. Every MLB skill calls this skill before writing a signal. Enforces the signal-framework.md schema -- required YAML frontmatter fields (type, date, emitted_by, confidence, source_urls), range-checks numeric signals (0-100 unipolar, -100 to +100 bipolar), verifies variant_synthesis metadata, and enforces file naming. On validation failure, does not persist and routes a failure entry to mlb-decision-logger. Use when an agent or skill needs to emit a signal, validate a signal file, write to signals/YYYY-MM-DD-<type>.md, or check signal frontmatter. Triggers — "emit signal", "validate signal", "write signal file", "signal frontmatter".
4---
56# MLB Signal Emitter
78## Table of Contents
9- [Example](#example)
10- [Workflow](#workflow)
11- [Common Patterns](#common-patterns)
12- [Guardrails](#guardrails)
13- [Quick Reference](#quick-reference)
1415## Example
1617**Scenario**: `mlb-player-analyzer` has computed a `daily_quality` signal for Junior Caminero on 2026-04-17 and wants to persist it.
1819**Inputs passed to this skill**:
20- `type: player`
21- `date: 2026-04-17`
22- `emitted_by: mlb-player-analyzer`
23- `variant_synthesis: true`, `variants_fired: [advocate, critic]`
24- Body contains: `form_score: 68`, `matchup_score: 74`, `opportunity_score: 62`, `daily_quality: 69`, `regression_index: +18`, `confidence: 0.78`
25- `source_urls: [baseballsavant..., fangraphs..., mlb.com/gameday...]`
2627**Validation pass** (what this skill checks):
2829| Check | Result |
30|---|---|
31| YAML frontmatter parses | PASS |
32| `type` is in allowed enum | PASS (`player`) |
33| `date` is ISO YYYY-MM-DD | PASS |
34| `emitted_by` present | PASS |
35| `confidence` in [0.0, 1.0] | PASS (0.78) |
36| `source_urls` is non-empty list | PASS (3 URLs) |
37| `variant_synthesis: true` implies `variants_fired` has >= 1 | PASS (2 fired) |
38| All numeric signals in declared range | PASS (all 0-100 signals clamped; regression_index in +-100) |
39| File path matches `signals/YYYY-MM-DD-<type>.md` convention | PASS |
4041**Action**: Write to `yahoo-mlb/signals/2026-04-17-player-caminero.md` and return the absolute path.
4243**Failure scenario**: If `confidence: 1.4` had been passed, validation fails. The skill does NOT write the file. It calls `mlb-decision-logger` with a failure entry: `kind: signal_validation_failure`, `signal_type: player`, `reason: confidence out of range (1.4 not in [0.0, 1.0])`, `emitter: mlb-player-analyzer`, and returns an error to the calling agent.
4445## Workflow
4647Copy this checklist and track progress:
4849```
50Signal Emission Progress:
51- [ ] Step 1: Receive signal payload from upstream skill/agent
52- [ ] Step 2: Validate YAML frontmatter (required fields)
53- [ ] Step 3: Range-check all numeric signals
54- [ ] Step 4: Validate variant synthesis metadata
55- [ ] Step 5: Determine and validate file path
56- [ ] Step 6: Write file OR log validation failure
57```
5859**Step 1: Receive signal payload**
6061The caller hands in three things: (1) YAML frontmatter key-value pairs, (2) signal body (markdown tables), (3) intent (e.g., "this is a final synthesized signal" vs. "this is an intermediate variant dump"). See [resources/template.md](resources/template.md) for the canonical input shape.
6263- [ ] Frontmatter fields collected
64- [ ] Body (markdown tables) supplied
65- [ ] Intent known: final vs. variant-intermediate
6667**Step 2: Validate YAML frontmatter**
6869Confirm all required keys are present and well-typed. See [resources/methodology.md](resources/methodology.md#required-frontmatter-fields) for the full list.
7071- [ ] `type` present and in the allowed enum (lineup, waivers, streaming, trade, category-plan, playoff-push, player, matchup, regression, two-start, closer, faab, cat-state)
72- [ ] `date` present and formatted `YYYY-MM-DD`
73- [ ] `emitted_by` present and references a known skill or agent
74- [ ] `confidence` present as a float in [0.0, 1.0]
75- [ ] `source_urls` present as a non-empty list of URLs
7677**Step 3: Range-check numeric signals**
7879Every numeric signal in the body must fall inside its declared range. See [resources/methodology.md](resources/methodology.md#range-check-rules) for the per-signal range table (it mirrors signal-framework.md).
8081- [ ] Unipolar signals (form_score, matchup_score, opportunity_score, daily_quality, qs_probability, streamability_score, role_certainty, cat_pressure, playoff_matchup_quality, etc.) in [0, 100]
82- [ ] Bipolar signals (regression_index, positional_flex_delta) in [-100, +100]
83- [ ] Integer signals (playoff_games) >= 0
84- [ ] Dollar signals (acquisition_value, faab_max_bid, faab_rec_bid) >= 0
85- [ ] Enum signals (cat_position, verdict) inside their declared allowed sets
8687**Step 4: Validate variant synthesis metadata**
8889If this is a synthesized final signal, it must declare which variants produced it.
9091- [ ] If `variant_synthesis: true`, `variants_fired` is a list with >= 1 entry
92- [ ] If `variant_synthesis: true`, `synthesis_confidence` is present and in [0.0, 1.0]
93- [ ] If `variant_synthesis: false`, the file is an intermediate variant dump; filename must include the variant suffix (see Step 5)
94- [ ] `red_team_findings` (if present) is a list of objects with `severity`, `likelihood`, `score`, `note` fields
9596**Step 5: Determine and validate file path**
9798The canonical path is `yahoo-mlb/signals/YYYY-MM-DD-<type>.md`. For an intermediate variant dump, use `YYYY-MM-DD-<type>-<variant>.md`. For per-player or per-game files, an optional identifier suffix is allowed: `YYYY-MM-DD-<type>-<identifier>.md`.
99100- [ ] Compute path from `date` and `type` in frontmatter
101- [ ] Check that a signal of this type+date does not already exist unless the caller explicitly passed `overwrite: true`
102- [ ] Ensure the parent directory exists (create if missing)
103- [ ] Reject paths that escape the `signals/` directory
104105**Step 6: Write file OR log validation failure**
106107If all checks pass: write the file, return the absolute path. If any check fails: do NOT write, call `mlb-decision-logger` with a structured failure entry, return an error object to the caller. See [resources/methodology.md](resources/methodology.md#handling-validation-failures) for the failure log schema.
108109- [ ] On pass: write file, return absolute path
110- [ ] On fail: build failure object (reason, field, expected, actual), send to `mlb-decision-logger`, return error
111112## Common Patterns
113114**Pattern 1: Per-player daily signal (`type: player`)**
115- Filename: `YYYY-MM-DD-player-<lastname>.md` (e.g., `2026-04-17-player-caminero.md`)
116- Required numeric signals in body: `daily_quality`, plus the three components (`form_score`, `matchup_score`, `opportunity_score`)
117- Always a final synthesized signal when emitted by `mlb-player-analyzer` -- so `variant_synthesis: true` and `variants_fired: [advocate, critic]`
118- Source URLs must include Baseball Savant, FanGraphs, and MLB.com (confirmed lineup)
119120**Pattern 2: Daily lineup roll-up (`type: lineup`)**
121- Filename: `YYYY-MM-DD-lineup.md`
122- Body references, by name, the per-player signal files it consumed (provenance chain)
123- `synthesis_confidence` reflects agreement between the advocate (bat-everyone) and critic (sit-risky) variants
124- Red-team findings typically flag weather, role uncertainty, or fragile platoon calls
125126**Pattern 3: Intermediate variant dump (variant suffix in filename)**
127- Filename: `YYYY-MM-DD-<type>-advocate.md` or `YYYY-MM-DD-<type>-critic.md`
128- `variant_synthesis: false` (this IS a variant, not a synthesis)
129- `emitted_by` names the agent and variant (e.g., `mlb-lineup-optimizer/advocate`)
130- The synthesizing agent reads these two intermediate files, produces the final synthesized signal, then emits with `variant_synthesis: true`
131132**Pattern 4: Low-confidence graceful degrade**
133- When a web search fails, the upstream skill should still emit a signal but with `confidence <= 0.3` and a `red_team_findings` entry flagging the missing data source
134- This skill does NOT reject low-confidence signals -- low confidence is legitimate. It only rejects out-of-range or missing fields.
135- Flag in body: "Could not verify opposing pitcher; using prior-start proxy."
136137## Guardrails
1381391. **Never silently drop a signal.** If validation fails, the failure must be logged via `mlb-decision-logger` so the calibration review can see what was rejected and why. A signal that never gets written AND never gets logged is invisible to the team.
1401412. **Do not re-derive signal values.** This skill is a validator and file-writer only. It never computes `daily_quality` or any other signal itself. If an upstream skill passes in a half-computed signal, reject it rather than filling in the blanks.
1421433. **Reject unknown `type` values.** The enum in signal-framework.md is the authoritative list. If a caller passes `type: vibe-check`, reject and log. Adding a new signal type requires updating signal-framework.md first, then this skill's validator.
1441454. **Range checks are hard limits.** A `form_score` of 105 is not "close enough" -- it indicates a bug upstream (probably forgot to normalize). Reject and log. Do NOT clamp-and-accept.
1461475. **`confidence` is required, not optional.** Even a perfectly-computed signal with three source URLs must carry a confidence float. A missing confidence is a validator failure, not a warning.
1481496. **`source_urls` must be a non-empty list.** Per CLAUDE.md rule 1 ("Web-search everything"), every factual signal is backed by a live source. An empty `source_urls` list means the signal was not grounded -- reject and log.
1501517. **Variant synthesis claims must be provable.** If `variant_synthesis: true` but `variants_fired` is empty or missing, that is a lie about the team's process. Reject and log.
1521538. **Do not overwrite without explicit consent.** If a signal already exists at the target path, refuse to overwrite unless the caller passes `overwrite: true`. This prevents losing an earlier morning's signal when a mid-day re-run happens.
154155## Quick Reference
156157**Required frontmatter fields (always):**
158- `type` (enum)
159- `date` (YYYY-MM-DD)
160- `emitted_by` (string)
161- `confidence` (float 0.0-1.0)
162- `source_urls` (non-empty list)
163164**Required when `variant_synthesis: true`:**
165- `variants_fired` (list, >= 1)
166- `synthesis_confidence` (float 0.0-1.0)
167168**File path conventions:**
169- Final synthesized: `signals/YYYY-MM-DD-<type>.md`
170- With identifier: `signals/YYYY-MM-DD-<type>-<id>.md`
171- Intermediate variant: `signals/YYYY-MM-DD-<type>-<variant>.md`
172173**Signal ranges (see [resources/methodology.md](resources/methodology.md#range-check-rules) for the full table):**
174- Unipolar (0-100): form_score, matchup_score, opportunity_score, daily_quality, qs_probability, k_ceiling, era_whip_risk, streamability_score, role_certainty, save_role_certainty, cat_pressure, cat_reachability, cat_punt_score, positional_need_fit, opp_sp_quality, park_hitter_factor, park_pitcher_factor, weather_risk, bullpen_state, playoff_matchup_quality, holding_value, obp_contribution, sb_opportunity
175- Bipolar (-100 to +100): regression_index, positional_flex_delta
176- Dollar (>= 0): acquisition_value, faab_max_bid, faab_rec_bid, trade_value_delta
177- Integer (>= 0): playoff_games
178- Enum: cat_position (winning|tied|losing), verdict (accept|counter|reject)
179180**On validation failure:**
1811. Do NOT write the signal file.
1822. Build failure entry: `{kind: signal_validation_failure, signal_type, reason, field, expected, actual, emitter, timestamp}`.
1833. Call `mlb-decision-logger` with the failure entry.
1844. Return an error object to the caller.
185186**Key resources:**
187- **[resources/template.md](resources/template.md)**: Canonical signal file template with every required frontmatter field and a fully-populated example body
188- **[resources/methodology.md](resources/methodology.md)**: Validation rules -- required fields, range checks, variant-synthesis checks, path conventions, failure handling
189- **[resources/evaluators/rubric_mlb_signal_emitter.json](resources/evaluators/rubric_mlb_signal_emitter.json)**: 8 criteria for evaluating the emitter's behavior
190191**Inputs required:**
192- Frontmatter key-value pairs from caller
193- Signal body (markdown tables)
194- `overwrite` flag (default false)
195196**Outputs produced:**
197- On success: absolute file path of the written signal
198- On failure: error object; a failure entry appended to `tracker/decisions-log.md` via `mlb-decision-logger`
Run npx skillmds@latest add lyndonkl/mlb-signal-emitter in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Validates and persists signal files to the yahoo-mlb signals directory. Every MLB skill calls this skill before writing a signal. Enforces the signal-framework.md schema -- required YAML frontmatter fields (type, date, emitted_by, confidence, source_urls), range-checks numeric signals (0-100 unipolar, -100 to +100 bipolar), verifies variant_synthesis metadata, and enforces file naming. On validation failure, does not persist and routes a failure entry to mlb-decision-logger. Use when an agent or skill needs to emit a signal, validate a signal file, write to signals/YYYY-MM-DD-<type>.md, or check signal frontmatter. Triggers — "emit signal", "validate signal", "write signal file", "signal frontmatter". It is listed under AI & ML on SkillMD.
This skill has not completed SkillMD's automated safety review yet. Independent scanners report: SkillSpector: PASS, Skill Scanner: PASS. Capability flags: docs only. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
lyndonkl (@lyndonkl) published this skill. Their other Agent Skills are listed on their SkillMD profile.