TaskMetadata

Canonical JSON document anchored on-chain by FrontierRegistry task.metadataHash.

A document of this kind carries a schema field matching xny://schemas/task-metadata/<major>.<minor> — the version is part of the URI, and it is the only place a document's version is recorded.

Canonical JSON document anchored on-chain by FrontierRegistry task.metadataHash. The exact bytes uploaded to metadataUri define the hash — see Metadata Hash Rules in docs/architecture/protocol-v2-design.md §6.1.

Fields

FieldTypeRequiredDescription
schemastringyesPer-kind versioned schema identifier. Format: xny://schemas/task-metadata/<major.minor>. This is the single source of truth for document version; do not use schema_version.
kindstringyesDocument kind discriminator. Always 'task-metadata' for this schema.
publisherstringyesDID of the entity that published this document. Pseudonymous identifier written to the permanent Arweave layer. DID-to-identity mapping exists only in an off-chain deletable layer (GDPR note: deletion right does not cover this field).
published_atstringyesRFC 3339 / ISO 8601 UTC timestamp of document publication.
tagsobjectyesFree-form key-value metadata tags for indexing and filtering. Bounded to 32 entries with keys up to 64 characters — conservative structural limits to keep the anchored document small, not a semantic constraint on tag content. Values are permanently written to Arweave alongside the rest of this document: do not put personal data in a tag (see CONVENTIONS.md's GDPR Note).
task_idstringyesOff-chain identifier (snowflake). On-chain bytes32 = keccak256(utf8 of this string).
campaign_idstringyesParent campaign identifier.
owner_did_idstringyesuint128 DID id of the task creator (controls updateTaskMetadata), serialised as decimal string.
task_keystringyesStable key used by depends_on references within the same campaign.
namestringyesHuman-readable task name. Permanently written to Arweave — do not put personal data in it (see CONVENTIONS.md's GDPR Note).
description——Free-text task description. Permanently written to Arweave — do not put personal data in it (see CONVENTIONS.md's GDPR Note).
task_typesubmission | validationyes
executionhuman | agentyes
originmanual | auto_generatedyes
template_id——
template_version——
annotation_config_uri——URI to LabelStudio-style XML annotation config (kept out of the JSON to keep metadataHash stable across whitespace edits to the XML).
data_requirementsobject—Free-form, task-type specific input requirements.
data_displayobject—Free-form display config (frontend rendering hints).
rewardobjectyes
acceptance_rule—yesDiscriminated union by 'type'.
max_countintegeryes
duplicate_permissionintegeryesMax submissions per contributor under this task (1 = no duplicates allowed).
depends_onarray of stringyesUpstream task_key values within the same campaign.
positionintegeryes
qualification_override——Per-task override of campaign-level qualification; null = inherit from campaign.

Example

{
  "schema": "xny://schemas/task-metadata/1.0",
  "kind": "task-metadata",
  "publisher": "did:xny:0xabcdef1234567890abcdef1234567890abcdef12",
  "published_at": "2026-06-08T10:00:00Z",
  "tags": {},
  "task_id": "t-residue-label-002",
  "campaign_id": "c-protein-annotation-001",
  "owner_did_id": "1042",
  "task_key": "residue_label_advanced",
  "name": "Annotate functional residues (advanced)",
  "description": "A harder variant of the base task, restricted to higher-reputation contributors.",
  "task_type": "submission",
  "execution": "human",
  "origin": "manual",
  "template_id": "tmpl-residue-annotation",
  "template_version": 3,
  "annotation_config_uri": "ipfs://QmExampleAnnotationConfigCidForResidueAnnotationV3",
  "data_requirements": {
    "input_kind": "uniprot_entry",
    "min_sequence_length": 50
  },
  "data_display": {
    "viewer": "ngl",
    "color_scheme": "residue_type"
  },
  "reward": {
    "type": "per_accepted_instance",
    "amount_usd": 2.5,
    "currency": "USD"
  },
  "acceptance_rule": {
    "type": "consensus",
    "min_agreement": 3
  },
  "max_count": 500,
  "duplicate_permission": 1,
  "depends_on": [],
  "position": 1,
  "qualification_override": {
    "crs_min": 80
  }
}

1 rejection case is kept alongside the schema in docs/schemas/examples/, exercised by validate_schemas.py.

Last updated

On this page