---
name: lfp-handoff-watcher
description: Read orchestrator prompts from `C:/Users/mclou/lfcs-handoff/orch-to-pricer.md`, execute the latest message's instructions inside the pricer session (run the named lfcs-* skill / produce the requested output), and write the result to `pricer-to-orch.md` with timestamped + bid-id-headed block. Companion to lfo-handoff-watcher.
model: claude-sonnet-4-6
phase: all (active during any handoff-driven bid lifecycle on the worker side)
invoked_by: pricer on session start, after each Rocky prompt, and at key phase transitions
preconditions:
  - handoff folder exists (`C:/Users/mclou/lfcs-handoff/`)
  - state.json present and valid
  - active_bid_id matches the bid being processed (or skill aborts if mismatch)
inputs:
  - direction: "read" (parse latest orch prompt) | "write" (draft outbound output) | "both"
  - bid_id (string)
  - message_body (when writing): the full pricer output to send
outputs:
  - latest_orch_message (when reading): parsed prompt text + metadata
  - state.json updated with new mtimes / last-seen index
  - pricer-to-orch.md appended with new outbound block (when writing)
side_effects:
  - writes to handoff folder (state.json + pricer-to-orch.md)
  - daemon (if running) detects writes and notifies orch side
authored_by: claude-code-orchestrator (skill defined for pricer worker; pricer agent owns the runtime invocation)
created: 2026-05-08
---

# lfp-handoff-watcher

Pricer-side handoff I/O. Symmetric counterpart to `lfo-handoff-watcher`. When Rocky comes to the pricer terminal and prompts "check handoff," this skill reads the latest orch prompt from `orch-to-pricer.md`, executes whatever the prompt asks (typically: run a named `lfcs-*` skill on the inputs cited in the prompt), and writes the output to `pricer-to-orch.md`.

## Procedure

### Read mode

1. **Parse `state.json`.** Pull `active_bid_id`, `current_phase`, `last_pricer_seen_orch_input_index`.
2. **Read `orch-to-pricer.md`.** Find all message blocks bracketed by `<!-- orch-msg-start bid={id} ts={iso} -->` and `<!-- orch-msg-end -->`. Filter to messages where `bid == active_bid_id` AND block index > `last_pricer_seen_orch_input_index`.
3. **If unread messages exist:** for each, parse the body. The orchestrator's prompts always name the worker skill to invoke (`lfcs-drawing-extract-text`, `lfcs-boq-parse`, `lfcs-bid-prep-doc`, `lfcs-pre-grill`, etc.) and cite the input artefact paths. Pricer reads the prompt, runs the named skill end-to-end, captures the output as a markdown block.
4. **Update `last_pricer_seen_orch_input_index`** in state.json.

### Write mode

1. **Compose outbound block.** Format:
   ```
   <!-- pricer-msg-start bid={id} ts={iso} phase={phase} msg-index={N} -->
   ## Bid {id} — Phase {phase} response — {iso}

   {message_body}
   <!-- pricer-msg-end -->
   ```
2. **Append to `pricer-to-orch.md`.** Atomic write: temp + rename.
3. **Update `state.json`.** Stamp `last_pricer_to_orch_mtime` to file's new mtime.
4. **Daemon picks up mtime change within 30s** and notifies orch terminal.

### Both mode

Read latest orch prompt → execute the worker skill it names → write the output. Most common pattern when pricer is shepherded by Rocky.

## Hard rules (per pricer + orchestrator CLAUDE.md handoff rules)

- **One active bid at a time.** If `state.json.active_bid_id` does NOT match the bid_id this skill was invoked with, abort with error "wrong-bid: state.active={X}, requested={Y}" and surface to Rocky.
- **Atomic writes only.** Temp + rename pattern.
- **Append-only on the handoff files.** Never edit prior blocks.
- **Worker contracts unchanged.** Pricer still runs the same lfcs-* skills with the same inputs; the only change is the prompt arrives via file read instead of Rocky paste.
- **Sanitisation seam intact.** L1 + L2 sanitisation per CLAUDE.md §4.3 still runs locally inside the pricer session before any external artefact is generated. The handoff file is internal-only — never sanitised, never sent externally.
- **No verbal mid-session overrides.** If the orch prompt's intake-locked envelope says LAFHA OUT, the pricer applies LAFHA OUT. Disagreements get logged back to orch via the next handoff message, not actioned in-session.

## Failure modes

- **state.json shows wrong active_bid_id:** abort, surface. Rocky decides whether to flip state or process the right bid.
- **Orch prompt names a skill that's NOT YET BUILT (e.g. lfcs-pricing-estimator M5):** pricer surfaces "skill-not-built" in its response message. Orchestrator may fall back to the manual workaround documented in pricer CLAUDE.md §8.
- **Daemon not running:** still works manually — Rocky shepherds.
- **L2 sanitisation fails on an outbound external artefact:** per pricer CLAUDE.md §4.3, artefact is deleted. Pricer writes a failure block to `pricer-to-orch.md` and orchestrator surfaces to Rocky per §6 hard case 7.

## Output schema

Read-mode output:
```yaml
latest_orch_messages:
  - bid_id: "2631"
    phase: "phase-3-worker"
    timestamp: "2026-05-08T15:00:00+00:00"
    msg_index: 3
    body: |
      Run lfcs-drawing-extract-text on:
        - 03 - Plans and Specifications/03a - Issued for Construction/2631_DWG_*.pdf
      Then lfcs-boq-parse on:
        - 02 - Scope and Pricing/02b - BOQ and Rate Schedules/2631_BOQ.xlsx
      Output the drawing index + parsed BOQ as a single markdown block.
status: "messages-found" | "no-new-messages"
```

Write-mode output:
```yaml
written_to: "pricer-to-orch.md"
new_mtime: "2026-05-08T15:25:00+00:00"
msg_index: 4
state_updated: true
```

## Notes

- This skill lives in the pricer's skill folder per pricer CLAUDE.md §1 ("Skills: `Operations/skills/lfcs-*/`" and orchestrator-aware skills under the codebase folder). Although orchestrator-aware, the pricer agent owns the runtime invocation — pricer agent reads its own SKILL.md.
- The handoff file is INTERNAL ONLY. Never include any text in handoff blocks that would fail L1/L2 sanitisation (no "claude-*" / "agent-*" / "_internal_" leaks intended for external). The daemon does NOT sanitise.
- v1 of this skill assumes Rocky is shepherding both terminals manually. Future v2 enhancements would include: auto-prompt injection into the pricer session via Claude Code CLI hook (not currently exposed), eliminating Rocky's "check handoff" trigger.
