BOHICA-LABS / BOHICA-LABS/vsdd-factory

documentation(orchestrator): clarify when to use SendMessage vs fresh Agent dispatch

Open
#223 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.