Skip to content
Development
Skill

/agent-contract-handoff

Use for the exact input/output schema and validation rules of agent_contract_handoff

From plugin
metraton-gaia
339 skills9 agents11 hooks
Install
$ npx -y skills add metraton/gaia --skill agent-contract-handoff --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/agent-contract-handoff

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use for the exact input/output schema and validation rules of agent_contract_handoff

SKILL.md

agent-contract-handoff.SKILL.md
name: agent-contract-handoff
description: Use for the exact input/output schema and validation rules of agent_contract_handoff

Agent Contract Handoff Reference

This skill owns schema, not workflow. Use `agent-protocol` to produce a turn and `agent-response` to consume it. The envelope body is JSON, never YAML.

**Two senses of "contract" -- do not collapse them.** This skill's "contract" is the *handoff* envelope: one row per turn, born at dispatch under the injected `# Your Contract` block, mutated by `gaia contract set/add/fill`, closed by `gaia contract finalize`. A *project context contract* is a different thing -- a slice of project knowledge stored per workspace (`project_context_contracts`, seeded by `seed_contract_permissions.py`). It is NOT injected: the kernel's `can_read` / `can_write` lists (from `agent_contract_permissions`) name which of those slices the turn may pull on demand (the verb that reaches them, and the same-named sibling that reads a different table entirely, are in `agent-protocol/read-map.md`) and which it may propose updates to via `update_contracts`. When a message says "contract" without qualifying it, ask which one it means before assuming.

Draft creation is implicit

A turn born at dispatch already has a row in `agent_contract_handoffs` AND a pre-created on-disk draft (`dispatch_binding._precreate_draft` writes `gaia.contract.drafts.initial_envelope` at birth) before it runs anything -- no prior `gaia contract init` call is required. Should the draft file be missing anyway, the first `gaia contract set/add/fill/view --draft-id <draft_id>` against that same, already-born `contract_id` materializes it (`bin/cli/contract.py::_maybe_adopt_draft`). Two conditions gate it, and both must hold: the id's agent-id prefix matches `AGENT_ID_PATTERN_TEXT`, and a row already exists for that exact `contract_id` (`gaia.store.writer.agent_contract_handoff_exists`). Neither condition mints anything -- a well-formed id with no row behind it still fails with the same "No draft found... run init" error as before this existed. `gaia contract init` remains, unchanged, the explicit path for a turn that received no injected identity at all. `gaia contract validate` never triggers this: it is documented as never mutating the draft, so it never materializes one either. See `agent-protocol` for when in the turn's cycle this first write happens.

Input context

The injected input is the dispatch kernel: `# Your Contract` (identity, goal, role/surface, `project`, `can_read`/`can_write`, and -- on a plan-task-bound turn -- the acceptance gates), `# Your CLI`, and `# What I know about you`. Project context is NOT preloaded and no surface routing arrives: pull the sections you need on demand, within the `can_read` menu, before querying anything wider (`agent-protocol/read-map.md`). Only sections in `can_write` may appear in `update_contracts`.

Minimal increment

Every draft, including a mid-turn checkpoint, contains:

  • `agent_status.agent_state`, `agent_status.agent_id`, `pending_steps`, and a

non-empty `next_action`;

  • `evidence_report` with all seven keys: `patterns_checked`, `files_checked`,

`commands_run`, `key_outputs`, `verbatim_outputs`, `cross_layer_impacts`, and `open_gaps` (empty lists are valid);

  • `consolidation_report` and `approval_request`, normally `null`.

`agent_id` matches `^a[0-9a-f]{16,}$`. The canonical states are `IN_PROGRESS`, `APPROVAL_REQUEST`, `BLOCKED`, `NEEDS_INPUT`, `NEEDS_VERIFICATION`, and `COMPLETE`. Only `COMPLETE` is terminal.

Which fields are lists, and what a second write does

Eight fields hold the lists you write every turn: the seven `evidence_report` keys above -- `patterns_checked`, `files_checked`, `commands_run`, `key_outputs`, `verbatim_outputs`, `cross_layer_impacts`, `open_gaps` -- plus `agent_status.pending_steps`. They are not the only lists in the envelope: `update_contracts`, `memorialize_suggestions` and `memory_suggestions` are list-valued too (`ADVISORY_UNTYPED_FIELDS` in `gaia/contract/validator.py` -- allowlisted, and deliberately left untyped so a malformed one never blocks a close). Nothing about them is unguarded, which is the next thing a reader asks once they know they exist: the overwrite screen is generic, firing on any populated list a patch would displace, and it starts at the envelope root where these three sit. They are seeded absent rather than as `[]`, so a first write to one discards nothing.

The three write verbs differ on every one of those lists, and the difference is not cosmetic -- it decides whether your earlier evidence survives:

  • **`fill` writes a list only while that list is still EMPTY.** A patch that

would discard entries already there is refused WHOLE: non-zero exit, nothing written, every colliding field named with its existing and incoming counts. It neither appends nor replaces; where the intent is ambiguous it makes you state which one you meant. Re-sending a patch whose list is byte-identical to what is stored is not a collision, so a corrected patch may be re-issued.

  • **`add` EXTENDS a list by one entry.** This is the verb for the second,

third and fourth batch of evidence into the same field.

  • **`set` REPLACES a list outright, unguarded.** This is the verb for

correcting a field you already populated, and for clearing one to `[]`.

Writing your evidence across several calls is the NORMAL path, not an edge case: one call carrying a full envelope routinely exceeds the shell's command-length limit (`fill --json-file` is the channel for long prose). So write each list field with `fill` at most ONCE, spread `fill` calls across DIFFERENT fields, and switch to `add` the moment you return to a field you already wrote.

State-conditional close requirements

  • `APPROVAL_REQUEST`: `approval_request` is non-null and

`approval_request.exact_content` is non-blank. All approval-set data stays in this object; see `agent-approval-protocol`.

  • `COMPLETE`: `pe
Read more
Ships withmetraton-gaia

Generative AI Architecture

Get the whole plugin

Other skills on metraton-gaia.