ai-team-library/claude/skills/handoff/SKILL.md
# Skill: Handoff (Typed) ## Description Creates a **typed**, contract-aware handoff packet when one persona completes its phase and the next persona picks up. The packet is no longer a free-form dump — it is the typed intersection of what the **sender produces** and what the **receiver consumes**, with each artifact spelled out in the registry-required fields. The skill bridges `close-loop` (which verifies the sender's work) and the next persona's start (which now has a checkable schema instea
npx skillsauth add beekeeper-lab/foundry ai-team-library/claude/skills/handoffInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Creates a typed, contract-aware handoff packet when one persona completes
its phase and the next persona picks up. The packet is no longer a free-form
dump — it is the typed intersection of what the sender produces and what
the receiver consumes, with each artifact spelled out in the
registry-required fields. The skill bridges close-loop (which verifies the
sender's work) and the next persona's start (which now has a checkable
schema instead of "read whatever I wrote").
/handoff slash command (see claude/commands/handoff.md).close-loop after verification passes if the
task has a downstream dependent.| Input | Type | Required | Description |
|-------|------|----------|-------------|
| from_persona | string | yes | Persona handing off (e.g., developer) |
| to_persona | string | yes | Persona receiving (e.g., tech-qa) |
| bean_id | string | yes | Owning bean (e.g., BEAN-274) |
| task_id | string | no | Originating task file (e.g., 01-developer-contract-validator.md) |
| notes | text | no | Free-form context the schema does not cover |
The skill computes the packet shape from three deterministic inputs. None of these are written by the sender — they are looked up from the library and registry at handoff time.
produces: —
ai-team-library/personas/core/<from>/contracts.yml :: producesconsumes: —
ai-team-library/personas/core/<to>/contracts.yml :: consumesai-team-library/contracts/artifact-types.yml :: types[*]
required-fields: is the per-artifact field set.pair-fields: (sibling map) lists per-edge extras: to merge in.These three sources are the same data shape that
foundry_app/services/library_indexer.py::_load_persona_contracts already
loads from the library (see lines 100-120 for ArtifactTypeInfo and
123-189 for _load_persona_contracts). Tech-QA can verify the skill by
checking it consumes the same registry the indexer does — there is no
parallel schema.
Resolve the contract intersection
from's produces and to's consumes.intersection = produces ∩ consumes (preserve produces order).NoSharedArtifactTypes (sender produces nothing the receiver consumes
— wave is misconfigured; escalate to Team Lead).Compute the packet schema for this edge
T in the intersection:
fields(T) = registry.types[T].required-fieldspair-fields: for this (from, to) edge:
extras = pair-fields[(from, to)].extrasextras = []{ T: fields(T) for T in intersection } + extras.extras apply once per packet (not per artifact). They live in a
dedicated Edge Extras section in the rendered packet.Validate before emitting (HARD GATE — see Error Conditions)
T in the intersection, check the sender
actually produced at least one artifact of that type during this
work cycle. Expected location:
ai/outputs/<from>/ — primary search (recursive). The sender's
persona-output convention; matches ArtifactTypeInfo.template-path
hint where present.ai/beans/<bean_id>/ — secondary (e.g., task-spec, bean-spec,
embedded acceptance-criteria).ai/context/decisions.md — for adr types (append-only file).code-change artifact lives in the
working tree itself (not under ai/outputs/); accept a referenced
file under foundry_app/ or tests/ as evidence, but the packet
MUST still cite a developer-authored summary doc under
ai/outputs/developer/ (notes file, decision record, or
comprehension note) so the receiver has a starting point.MissingProducedArtifact naming T, the expected
location(s), and the suggestion to either (a) author the missing
artifact, or (b) escalate to Team Lead if T was claimed in
produces: but is genuinely not part of this work cycle.Render the typed packet
ai/handoffs/<from>-to-<to>-<bean-or-task>.md
<bean-or-task> is BEAN-NNN for bean-level handoffs and
BEAN-NNN-task-NN for task-scoped ones.### <type-name> subsection enumerating its
required-fields with concrete values (file path + 1-line summary
per field, or the field value if the field is a scalar).Append to the handoff index
ai/handoffs/_index.md with
| Date | From | To | Bean | Packet | populated from the packet.Bounce-counter increment (BEAN-278)
from_persona == tech-qa AND to_persona == developer AND the
bean already has at least one Done-status developer-owned task,
this handoff is a bounce (Tech-QA is sending the work back for
another pass mid-bean). Locate the bean's Orchestration Telemetry
block (## Orchestration Telemetry), parse the
| **Bounces** | N (...) | row, increment N by one (preserving
the parenthesised hint suffix), and write it back. The counter
never decrements; over-counts are corrected by manual Team-Lead
edit, not by automation. If the bean has no Orchestration
Telemetry block (legacy beans pre-BEAN-278), this step is a silent
no-op. Note the bounce inline in the packet's ## Notes section as
> Bounce-of: <prior-developer-task-file> so the audit trail is
visible from the handoff itself.Notify the receiver
notes: covers the rest.# Handoff: <from> → <to> — <bean-or-task>
| Field | Value |
|-------|-------|
| **From** | <from-persona> |
| **To** | <to-persona> |
| **Bean** | <BEAN-NNN> |
| **Task** | <task-id or —> |
| **Date** | <YYYY-MM-DD> |
| **Packet schema** | <type-1>, <type-2>, … (intersection) |
## Produced artifacts
### <artifact-type-1>
- **<required-field-1>:** <path or value>
- **<required-field-2>:** <path or value>
- …
### <artifact-type-2>
…
## Edge extras
(Present only when `pair-fields` matched this `(from, to)` edge.)
- **<extra-1>:** …
- **<extra-2>:** …
## Start here
The 1-3 files the receiver should open first, in order.
## Notes
Free-form context the schema does not cover. Optional.
pair-fields extras merge with required-fieldsThe artifact-type's required-fields describe what the artifact itself
must contain (e.g., a code-change always has a summary,
what-changed, how-to-test, files-touched).
The pair-fields' extras describe what the receiver needs about the
edge that the artifact alone does not say (e.g., on the
developer→tech-qa edge, Tech-QA needs test-targets and rerun-command
to start verification immediately — those are not part of the
code-change artifact's required fields, but they are required for this
edge).
The merged packet schema is therefore:
packet_schema = (union over T in intersection of required-fields[T])
+ extras[(from, to)]
extras are rendered in a single Edge Extras section (not duplicated
per artifact). Field-name collisions between an artifact's required
fields and the edge extras are resolved by scoping: artifact fields
appear under the artifact subsection; extras appear under Edge Extras.
The packet renderer never collapses them into a single namespace.
| Output | Type | Description |
|--------|------|-------------|
| handoff_packet | markdown file | Typed packet at ai/handoffs/<from>-to-<to>-<bean-or-task>.md |
| index_row | table row | Appended row in ai/handoffs/_index.md |
required-field for every artifact in the intersection has a
concrete value (file path, scalar, or short prose). No TBD values.pair-fields extras (when present) appear in their own Edge Extras
section, not folded into an artifact._index.md row is appended (not inserted in arbitrary order) and
matches the columns | Date | From | To | Bean | Packet |.| Error | Cause | Resolution |
|-------|-------|------------|
| FromPersonaNotFound | from_persona is not a known core persona | Use one of team-lead, ba, architect, developer, tech-qa |
| ToPersonaNotFound | to_persona is not a known core persona | Use one of team-lead, ba, architect, developer, tech-qa |
| SamePersona | from == to | A handoff requires two different personas |
| NoContractsFile | A persona's contracts.yml is missing or unparseable | Restore the persona's contracts.yml (validated by library_indexer._load_persona_contracts) |
| NoSharedArtifactTypes | produces ∩ consumes == ∅ | Wave is misconfigured for this edge — escalate to Team Lead |
| MissingProducedArtifact | Sender did not actually produce an artifact for a required type in the intersection | Either author the missing artifact under ai/outputs/<from>/ (or the type's conventional location) and re-run, or escalate if the type does not apply to this work cycle |
| HandoffDirNotWritable | Cannot write ai/handoffs/ | Check permissions or scaffold the project |
ai-team-library/contracts/artifact-types.yml
(types: for required-fields, pair-fields: for edge extras).ai-team-library/personas/core/<id>/contracts.yml
(produces: / consumes:).foundry_app/services/library_indexer.py
(_load_persona_contracts, _load_artifact_types) — same data shape;
Tech-QA can verify the skill against the indexer for parity.ai/handoffs/_index.md is appended on every emit.development
# Skill: VDD (Verification-Driven Development) Gate ## Description Runs the programmatic VDD gate for a bean: parses the bean's `## Acceptance Criteria` section, dispatches each criterion's evidence type to the matching runner (test, lint, file, file-contains, or manual), aggregates the results into a pass/fail verdict, and writes a structured markdown report at `ai/outputs/tech-qa/vdd-<NNN>.md` (zero-padded NNN). This is the machine-checkable counterpart to the prose VDD policy in `ai/contex
tools
# Skill: Spawn Task ## Description Dispatches a single specialist persona to execute a single task with only that task's context. Auto-detects the runtime environment and chooses one of two execution paths: - **In tmux** (`$TMUX` set): spawn a worker in a git worktree using a child tmux window. Process-isolated, parallelizable, durable across the calling session's lifetime. Same pattern as `/spawn-bean` but at task granularity. - **Not in tmux**: invoke the `Agent` tool with `subagent_typ
development
# Skill: Orchestration Report ## Description Aggregates the per-bean **Orchestration Telemetry** blocks (BEAN-278) across recent Done beans and produces a markdown report that answers the architecture-aware-evaluation question: **is the orchestration paying for itself?** Distinct from `/telemetry-report` (which aggregates raw cost, duration, and tokens); this skill aggregates the orchestration-quality metrics layered on top — bounces, persona activations, contract violations, escape-hatch usag
development
# Skill: Health Check ## Description Runs all health checks defined in `ai/context/health-checks.md` and produces a table-format report. Can be called standalone or by other skills (e.g., `/long-run`). ## Trigger - Invoked by the `/health-check` slash command. - Called programmatically by `/long-run` at the start of each cycle. ## Inputs | Input | Type | Required | Description | |-------|------|----------|-------------| | health_checks | Markdown file | Yes | `ai/context/health-checks.md`