Skip to content

Labels & work types

You'll learn what the two kinds of labels do — work:* labels select skills, agent labels select the coding agent — and how to set them.

Labels are terms on the control plane. Most are plain tags, but two families carry meaning for the machinery, and both are read by the agent at dispatch time rather than by the control plane.

work:* — the sub-works a ticket contains

A work:* label declares one kind of work in the ticket, its sub-work. The value after the prefix is the work type, and it is the first component of the triple a skill declares it owns — (work_type, workflow, step). That is how a ticket carrying work:docs gets a documentation skill for coding, while one carrying work:code gets the code skill.

LabelWork typeOwned byValidated by
work:codecodethe project's code skills (for a Drupal project: @gaia/ddev-drupal-feature, @gaia/ddev-drupal-bug)the project's test suite, a browser scenario where one applies
work:docsdocs@gaia/docs-authoringproportional doc, frontmatter and contract checks — no runtime
project-defineda skill the project loadswhatever that skill declares

Only work:code is universal. work:docs is shipped but opt-in — a project loads the skill in its WORKFLOW.md or does not. Projects add their own: the GAIA repository itself carries work:design-to-designbook and work:designbook-to-config for design work that runs through Designbook.

A ticket may carry several work:* labels. Then each sub-work has its own step owner, all of them run at each step in WORKFLOW.md load order, and the last one performs the single confirmation and transition — see Skills and the workflow contract.

qualification is the one step before the sub-works are known — it is owned by a skill that declares no work type, and it is what sets the work:* labels in the first place. From spec on, the work type selects the owner: @gaia/create-spec owns spec for code, @gaia/docs-authoring for docs.

Agent labels — which coding agent runs the ticket

The engine config lists the agent addons a conductor may launch. Each candidate may carry a priority function the conductor calls per ticket at dispatch; the ticket arrives with its labels as a list of names, so a label on the ticket picks the agent:

js
agent: [
  { agent: { plugin: '@gaia-ai/addon-claude' }, priority: () => 0 },
  { agent: { plugin: '@gaia-ai/addon-codex' },
    priority: (t) => t.labels.includes('codex') ? 10 : -Infinity },
]

With that config, a ticket labelled codex runs on Codex and every other ticket on Claude Code. The { agent, priority } wrapper is what carries the function — a bare { plugin } entry has no priority and scores lowest. The GAIA control plane ships codex, kimi, kimi-opencode, pi and grok as labels for exactly this use; which of them your conductor honours is its engine config's business — Choose the coding agent.

Other labels

Anything else is a plain tag for people and filters. Projects add what they need; nothing in GAIA reacts to a label outside the two families above.

Setting labels

  • In the cockpit: open the ticket and use the edit form — labels, parent and cancel live there.
  • In the new-ticket popup: labels are a field; add work:code unless you want the qualification step to decide.
  • With gaia dropsh: write the labels relationship on the ticket. The terms' uuids come from gaia dropsh search gaia_term --bundle gaia_labels:
sh
gaia dropsh --auth-profile pm update gaia_ticket/gaia_ticket/<uuid> --data @labels.json --dry-run
json
{ "data": { "type": "gaia_ticket--gaia_ticket", "id": "<uuid>",
  "relationships": { "labels": { "data": [
    { "type": "gaia_term--gaia_labels", "id": "<work:code uuid>" },
    { "type": "gaia_term--gaia_labels", "id": "<codex uuid>" } ] } } } }

A labels write replaces the list; include every label the ticket should keep.

Next