Write a work kind
A work kind is the rules for one kind of work, such as an investigation, a review or a change. It supplies how the agent works, what the work produces and where it lands, and it is chosen for a flight with gg fly --work-kind. A flight opened without one runs under the organisation’s implement work kind, or under root alone when there is none. Use this guide to write a new work kind, or to make a variant of an existing one.
Each field is described in full in The envelope. This page shows how the fields fit together in one file.
Prerequisites
Section titled “Prerequisites”- A working copy of the airspace, pulled with
gg airspace pull. Change the airspace explains the cycle. - Permission to apply airspace documents. A new work kind loosens the rules, so its approver also needs to be available.
1. Write the file
Section titled “1. Write the file”A work kind is one file in work-kinds/, named after the work kind. This example is an investigation that reads a work item and its repository and proposes an analysis without changing any file:
# work-kinds/investigate.yaml (an example)
# For people choosing a work kind. No agent sees it.description: "Analyse a work item for implementation. Changes no code."
# The job, in one sentence. It opens the agent's task.brief: "Investigate the work item this flight names and work out how it should be implemented. Change nothing."
# Which files the agent may change, and the rules version root uses.context: scope: "**" constitution: "1.0.0"
# What a flight of this kind may be about.accepts: - repository - tracker
# What the work can yield. Obligations that need a fact not listed here never apply.produces: - landing.proposal - loop.digest - loop.outcome - loop.question
# Standing guidance, passed to the agent word for word after root's.instructions: - "Name only paths that were opened and read, not paths expected to exist." - "When the item is too unclear to analyse, return the question instead of a guess."
# What must be true before the work is accepted.obligations: investigate-finished: check: machine rule: loop-not-exhausted investigate-in-scope: check: machine rule: no-file-outside-scope
# How the work is done: exactly one loop.loops: investigate: executor: frontier model: claude-opus-5-5 discharges: - investigate-finished - investigate-in-scope moves: - history - propose-landing - read - search budget: wall-clock: "20m" on-exhaustion: handoff-to-human
# Where finished work goes, and what it requires first.destinations: none: kind: none requires: - investigate-finished - investigate-in-scopeWhat each field does, with a link to its full description:
| Field | Required | What it does |
|---|---|---|
description |
No | One line for people choosing a work kind, such as in the console. It governs nothing, and no agent sees it. |
brief |
No | The job a flight of this kind is to do, in one sentence. It is the first thing the agent’s task says, so it is the place to say “change nothing” or “write a score, not code”. |
context.scope |
Yes | The files the agent may change. The flight receives the overlap of this and root’s scope. constitution repeats root’s value. |
accepts |
Yes | What a flight of this kind may be about: repository (a tree to work in), tracker (a backlog to read, with no tree), or envelope (an airspace document). An empty list means no subject. |
produces |
Yes | The facts this work can yield. Leaving a fact out switches off the obligations that depend on it, so removing one counts as loosening the rules. |
instructions |
No | Standing guidance, passed to the agent word for word. Root’s instructions come first, then the work kind’s. |
obligations |
Yes | Machine checks and human checks. A human check opens a gate for its approver. |
loops |
Yes | Who does the work, on which model, with which moves, for how long, and who takes over when time runs out. |
destinations |
Yes | Where finished work lands, and which obligations it requires. |
A work kind may also set hosts (the environment the work’s running application needs, when that differs from where the agent runs) and variables (environment variables for what the flight runs; never a secret). Repositories, environments, the models a person may choose and the organisation’s tool servers belong to root, and a work kind that sets a different value is refused.
2. Check it
Section titled “2. Check it”Check the file’s shape before sending it anywhere:
gg envelope validate work-kinds/investigate.yamlgg prints This is a valid envelope. and the form it will be stored in, or This is not an envelope. with the reason. It contacts nothing.
Then see what applying it would do:
gg airspace diffA new work kind shows as widening. A file that does not read as a document is listed with the reason.
3. Declare and apply it
Section titled “3. Declare and apply it”A new work kind needs its name declared before its file can be applied:
gg airspace apply --declare-namesBoth the declaration and the new document loosen the rules, so gg reports the flights they opened and who each one awaits. Once those gates are answered, the work kind is in force, and gg fly --work-kind investigate uses it.
To read the rules a flight of this kind would run under, run gg envelope show investigate. It prints root combined with the work kind, with each rule marked by the document it came from.
Make a variant without copying
Section titled “Make a variant without copying”A work kind can extend another and state only what it changes. The parent is named with extends:, and everything the child leaves out is inherited:
# work-kinds/investigate-instructions.yaml (an example)extends: investigatedescription: "Investigate a work item and write the implementation instructions into it."remove: destinations: - none instructions: - "When the item is too unclear to analyse, return the question instead of a guess."instructions: - "End the analysis with a numbered list of implementation steps."destinations: instructions-field: kind: work-item-tracker requires: - investigate-finished - investigate-in-scope may-perform: - field may-write: - Custom.InstructionsThe child is applied over its parent with these rules:
- Single values, such as
description,briefor a loop’smodel, take the child’s value when it gives one. - Lists, such as
accepts,producesandhosts, are replaced whole by the child’s list. No list is merged item by item. - Loops, destinations and obligations are matched by name. A child entry replaces the parent’s entry of the same name whole, and a new name is added.
- Instructions are added after the parent’s.
remove:takes things away from the parent:loops,destinationsandobligationsby name, andinstructionsby their exact text. A removal that matches nothing is refused, naming it, so a parent reworded under its child fails loudly at the child’s next apply. Removing an obligation or a destination loosens the rules and is approved like any other loosening change.
In the example, the child removes the parent’s none destination and adds its own, because a work kind has one destination.
A chain holds at most three work kinds, counting the top one. A child cannot set root’s fields or context; it inherits them.
A base that exists only to be extended is marked abstract: true. It is never flown itself, it need not declare a destination, and it is checked through each work kind that extends it. Being abstract is not inherited.
A child’s name is declared under its parent. gg airspace apply --declare-names does this from the extends: line, and the parent cannot be changed once the name is declared. gg airspace show investigate-instructions prints the child as written and then the result of applying it over its parent.
Related
Section titled “Related”- The envelope: every field in full, and how the layers combine.
- Change the airspace: pulling, applying and declaring names.
- Fly from a work item: choosing a work kind for a flight.