BOHICA-LABS / BOHICA-LABS/vsdd-factory
documentation(orchestrator): clarify when to use SendMessage vs fresh Agent dispatch
- Dominant language
- Rust
- Stars
- 2
- Forks
- 1
- Avg merge
- 6h 43m
- Merged PRs (30d)
- 29
Description
## Summary
The orchestrator can dispatch sub-agents in two ways:
1. `Agent(subagent_type=..., prompt=...)` — fresh dispatch with no prior context.
2. `SendMessage(to=, ...)` — continuation of a still-running or recently-completed agent with full prior context.
The Agent tool's documentation mentions this distinction, but the orchestrator's own AGENTS.md and skill prompts don't include guidance for choosing between them. As a result, observed pattern: orchestrators tend to default to fresh `Agent()` dispatches and rarely use `SendMessage()`, even when it would be cheaper.
Examples from the ftc-blue Phase 1d session where SendMessage would have been better:
- Pass-8 follow-up: "bump ARCH-INDEX §4 ADR-0006 row from v1.8 to v1.9 (lint just flagged it)" — this is a small handoff to the same architect that just finished a related burst. Dispatched as fresh `Agent()` with ~3000-token re-briefing. Could have been a 100-token `SendMessage` to the still-warm architect agent.
- Pass-9 OQ-006 sweep completion: PO finished a sweep, lint caught 2 stragglers. Dispatched fresh `Agent()` to PO with re-briefing. Could have been `SendMessage` continuation.
- Multiple "lint discovered N more violations of the class you just fixed" handoffs — same pattern.
Cumulative cost: estimated 100–200k tokens of unnecessary re-briefing in this session alone.
## Proposed change
Add explicit guidance to `agents/orchestrator/AGENTS.md` (and the orchestrator skill prompts) on when to use each:
**Use `Agent(subagent_type=...)` when:**
- Starting a new task with a distinct theme.
- The previous agent's context is no longer relevant.
- The task spans a different agent type than was recently used.
- The previous agent terminated with a permanent failure.
**Use `SendMessage(to=)` when:**
- The new task is a small follow-up to a task the agent JUST completed (lint discovery, tiny correction, etc.).
- The previous agent's context is directly relevant and re-briefing would be redundant.
- The agent is still running (e.g., asynchronously) and you have an updated instruction.
**Worked examples:**
1. Pass-9 lint discovers BC-10.10.005 arity mismatch right after PO's pass-9 BC burst completed. **Use `SendMessage(to=, "...BC-10.10.005 arity mismatch...")`.** Don't re-dispatch PO with full pass-9 re-briefing.
2. Pass-10 starts a fresh adversarial pass with a different cycle baseline. **Use `Agent(subagent_type="adversary", ...)`.** Don't try to re-use the pass-9 adversary's context.
## Applies to
- `agents/orchestrator/AGENTS.md` — new "SendMessage vs Agent" section
- `skills/run-phase/SKILL.md` — same
- `agents/pr-manager.md` — also uses sub-agent dispatch and would benefit
- Worked-examples doc: `docs/playbooks/agent-dispatch-patterns.md`
## Acceptance criteria
- [ ] AGENTS.md documents the decision criteria with worked examples
- [ ] Skill prompts surface the choice at the right moments
- [ ] Measurable: subsequent cycles show SendMessage usage proportionate to small-followup work
## Found during
ftc-blue Phase 1d adversarial cycle (2026-06-23, vsdd-factory@1.0.0-rc.21). Cumulative ~100k tokens spent on re-briefing that SendMessage would have avoided.
## Notes
This is pure documentation — no code change. But empirically, documentation gaps drive runtime token cost, which is real money.
Contributor guide
Assessment
This issue has not been assessed yet.