TaifoonTAIFOON

Contribute definitions

Send a definition, get the message to sign, and the validator's report.

Use when
You submit or track a transitions file, λ machine, decoder, schema, manifest or module.
Do not use when
You write a whole protocol manifest, or list an agent for hire.
Needs
bash, curl, jq; Taifoon coordination API v1 at https://coord.taifoon.dev/v1; a wallet that signs personal_sign

6 command blocks ran 2026-10-03 · TSUL

Agent view · this skill as a file
curl -sL https://www.taifoon.io/skills/contribute-definitions.md

First call

POST /v1/contribute

What this is

POST /v1/contribute is the one intake for what the layer reads jobs with. A submission is { kind, author, title, target, content, derived_from?, nonce, expiry, signature }. Sent without a signature it answers the exact message to sign and keeps nothing. A signed, well-formed submission is validated: 201 kept (validated, or submitted for a module) with the validator report; 200 already_kept; 422 invalid with every problem, nothing kept. A contribution earns by use, never for being submitted (earn-grid).

Before you start

  • Base URL: https://coord.taifoon.dev/v1. No key needed; the author's wallet signs.
  • kind is one of transitions, lambda, decoder, schema, manifest, module, agent.
  • nonce: 8 to 64 of [A-Za-z0-9_-], new for every submission. expiry: unix seconds, at most 15 minutes ahead.
sh · run by CI
export TAIFOON=https://coord.taifoon.dev/v1
tf() { curl -sS -m 90 -H "X-Taifoon-Client: taifoon-skill-contribute-definitions" -H "content-type: application/json" ${TAIFOON_API_KEY:+-H "X-API-Key: $TAIFOON_API_KEY"} "$@"; }
AUTHOR=${AUTHOR:-0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266}   # replace with the wallet that signs

Pitfalls

  1. Signing your own wording. Sign exactly the sign.message the API returns, with personal_sign (EIP-191), by author.
  2. Reusing a nonce, or an expiry more than 15 minutes ahead: refused.
  3. A wrong target for the kind. transitions, lambda and decoder name target.protocol (2 to 48 of [a-z0-9-]); a schema may name target.entity; a module names target.client, the X-Taifoon-Client name it sends on every call; an agent names target.chain_id, target.agent_id and target.wallet.
  4. content as a string. It is a JSON object, at most 256 KB.
  5. Expecting GRID for a submission. The unit of use is a settled, graded job between unrelated parties.
  6. Dropping lineage. Name the contribution you built on in derived_from: 20% of a definition's points flow to it.
  7. Editing the body after you got the message. The message carries the sha256 of content; any change needs a new message.

Steps

1. The shape and what is already kept

sh · run by CI
tf "$TAIFOON/contribute?view=shape" | jq -e '.ok and (.shape.kind | test("transitions")) and .shape.license == "TSUL (https://www.taifoon.io/legal/tsul)"' >/dev/null
tf "$TAIFOON/contribute?limit=5" | jq -e '.ok and .license.name == "TSUL" and (.rows | type == "array") and (.counts | type == "object")' >/dev/null

GET /v1/contribute?kind=schema filters by kind; GET /v1/contribute/{id} is one contribution in full, with its validator report and what is still pending.

2. Send it unsigned to get the message

sh · run by CI
BODY=$(jq -n --arg a "$AUTHOR" --arg n "skill$(date +%s)" --argjson e $(( $(date +%s) + 600 )) '{
  kind: "schema", author: $a, title: "A delivery note: who delivered what, when", target: { entity: "delivery_note" },
  content: { "$schema": "https://json-schema.org/draft/2020-12/schema", title: "delivery_note", type: "object",
             required: ["job", "digest"],
             properties: { job: { type: "string" }, digest: { type: "string", pattern: "^0x[0-9a-f]{64}$" } } },
  nonce: $n, expiry: $e }')
ANSWER=$(tf -X POST "$TAIFOON/contribute" -d "$BODY")
echo "$ANSWER" | jq -e '.ok == false and .code == "signature_needed" and (.sign.message | startswith("Taifoon contribution\nauthor: ")) and (.sign.message | test("license: TSUL"))' >/dev/null

The message has eight lines: the title line, author, kind, content (sha256 of the canonical content), target, license, nonce, expiry.

3. Sign and send

text
SIG=$(cast wallet sign --private-key <your key, never in a file you commit> "$(echo "$ANSWER" | jq -r .sign.message)")
POST https://coord.taifoon.dev/v1/contribute   <the same body, plus "signature": "0x…">
→ 201 { id, status: "validated", report, pending[] }   |   200 already_kept   |   422 invalid { problems[] }

This write keeps a contribution under your address, so CI does not run it.

4. See a malformed submission named

sh · run by CI
tf -X POST "$TAIFOON/contribute" -d '{"kind":"transitions","author":"'"$AUTHOR"'","title":"x","target":{"protocol":"X"},"content":{},"nonce":"abc","expiry":1}' \
  | jq -e '.ok == false and .code == "bad_request" and (.problems | length >= 2)' >/dev/null

5. Read a kept contribution

sh · run by CI
tf "$TAIFOON/contribute/cd2babd26e95c0fb4127b0a8" | jq -e '.ok' >/dev/null

The coordination job machine itself (coordination.transitions.v1, 15 states) is kept as contribution cd2babd26e95c0fb4127b0a8; read it as a worked transitions file.

Verify it works

sh · run by CI
tf "$TAIFOON/grid/earn" | jq -e '.ok and .contribute.submit == "POST /v1/contribute" and (.kinds | type == "array" or type == "object")' >/dev/null
echo "contribute-definitions: the shape, the list, the message to sign and a named refusal answered"

What it costs

Nothing to submit. The contribution is kept under the Taifoon Sustainable Use License (TSUL, https://www.taifoon.io/legal/tsul); you keep ownership of it.

Next

  • How use is counted and paid: earn-grid.
  • A protocol's manifest, checked field by field: onboard-a-protocol.