Synced from Hive. This page is pulled from hivecommons/hive@v5 during the docs build. Edit the canonical source in the Hive repository.
Work sources (governor.work_source)
work_source chooses where Hive reads tasks. Most hives need no change:
the default is GitHub Issues on their configured repositories.
Reading tasks from a tracker does not grant agents permission to change code
or merge it; ACMM, lane permissions, and merge gates still apply.
Choose and configure a source
Prerequisites: a running hive, access to change its settings, a GitHub repository agents can work on, and read credentials for the chosen tracker. Writing review follow-ups can require additional permissions documented below.
| Where your tasks live | Setting | Start here |
|---|---|---|
| GitHub repository issues | github (default) | No new block or credentials are needed beyond working GitHub access. |
| A GitHub Projects board | github_projects | Board setup and token scopes |
| Linear teams/projects | linear | Team-to-repository mapping |
| Jira Cloud or Jira Data Center | jira | Jira deployment and credentials |
Hosted and dashboard-managed hives configure the block from Settings → Work
source. Self-hosted operators can also set governor.work_source in their
effective hive.yaml; on Kubernetes, a ConfigMap is only the first-boot seed
(config layering).
Confirm that work is being read
- Save your source and credentials using the chosen source’s instructions. Never commit literal credentials; use the documented environment references.
- Pick a known open task that matches the configured repository, team/project, state/query, and hold-label filters.
- Wait for a governor enumeration cycle and check the dashboard work list and logs for that task. A listed task is confirmation of reading, not a promise that an agent is eligible to act on it.
- An empty list can mean no matching tasks or filtered/held work. Check the query and mappings. Authentication, TLS, or API errors in logs mean the source failed; they are not evidence of an empty backlog. Correct the credentials/connection and check the next cycle.
Optional run stages and Wavefront append work to the primary source. They are advanced integrations, not extra first-run steps.
Source reference
The four primary type values are github, github_projects, linear, and
jira.
Absent or type: "" behaves exactly like existing hives with no
work_source block — GitHub Issues on the configured project.repos
(pkg/config/config.go:1336-1348, pkg/worksource/factory.go:15-89).
This page documents all four. Linear has its own deeper guide —
Linear agent integration — for the two-way agent-session
integration (webhooks, session acknowledgement, writing back to Linear);
this page covers only the read side (work_source.linear) for parity with
the other three.
Jira Data Center supports an internal CA bundle (the certificates used to trust your server) and optional client-certificate authentication in current v5 code. See TLS for Data Center.
Trackers and forges
work_source picks the tracker: where work items are read from. The
forge — where the repositories, branches and change requests live — is a
separate setting, project.forge, which a project.repo_policies[].forge
entry can override for one repository:
Forge (project.forge) | Instance setting | Token | Status |
|---|---|---|---|
github (default) | github.base_url / github.api_url | GitHub App | Supported |
gitlab | gitlab.gitlab_url (default https://gitlab.com) | env var named by gitlab.token_env (default GITLAB_TOKEN) | Adapter only |
gitea (Gitea and Forgejo) | gitea.gitea_url (required) | env var named by gitea.token_env (default GITEA_TOKEN) | Adapter only |
The GitLab and Gitea/Forgejo adapters read repos, issues and change requests,
and can comment, label and set the hold gate; GitLab can also merge. A hive
still cannot run on them, because enumeration, the merge gate and the agents’
gh path are GitHub-only. Every work source above therefore still targets a
GitHub repository. See Forges: GitLab, Gitea and
Forgejo for the operation list and what runs through
the adapters today, and Forge setup for the reasons.
Run stages (run_stages: true)
Advanced additive source: run stages and their implementation contract
Run stages let the governor offer a pending run stage such as spec, plan,
or implement as a non-issue-shaped work item. The primary source remains the
configured adapter; run stages are appended only when the flag is enabled:
governor:
work_source:
type: github
run_stages: trueWith the flag omitted or set to false, ListIssues output is unchanged. With
it enabled, pending stages use source type run, Number: 0, and an external
ID of <runKey>:<stage>. Their stable key is therefore
<owner/repo>!<runKey>:<stage>, not a fabricated repo#0. Later stages carry
a dependency on the previous stage’s run key, so plan records its dependency
on spec and implement records its dependency on plan.
The dashboard’s RunStageAccessor backs this source with the lease registry:
each stage lease is the run’s pending stage, a stage some connection is
currently working is not offered again, and implement is listed only once the
run’s imported plan is approved. The hive binary wires that accessor during
dashboard boot; if the accessor is unavailable, the additive source fails
closed by listing no run stages. The Spektacular (Spek) stage runner that advances the
lease is described in spektacular.md.
Wavefront migration graph (wavefront.enabled: true)
Advanced additive source: migration graph, receipts, and plan-import reference
The second additive item kind is a versioned code-migration graph such as
Crustify’s C/C++ to Rust migration driven by Wavefront (#8362, the second
proving workload of #7620). Wavefront stays authoritative for its semantic
graph: it owns dependency closure, cycle handling, waves, and batching. Hive
reads the graph, lists each ready node as a run-stage work item, withholds
blocked nodes, and records a receipt when a node completes. Hive never
re-derives the graph with an LLM, never fabricates GitHub issues or pull
requests for nodes, and the adapter (pkg/worksource/wavefront) makes no
GitHub call at all. Publication of results is out of scope (#8353).
governor:
work_source:
type: github
wavefront:
enabled: true
path: /data/wavefront/graph.json # or url: https://wavefront.example/graph.json
repo: acme/crust # owner/name every node key is scoped to
receipts_dir: /data/wavefront/receiptsenabled defaults to false; with it off, ListIssues output is
byte-identical to a hive that has never heard of the block. Exactly one of
path or url is required when enabled, and repo is required. The graph
is re-read on every governor cycle, so a plan Wavefront republishes is picked
up without a restart. receipts_dir is optional; empty keeps receipts in
memory for the life of the process.
Dashboard owners can configure the same wavefront block from Settings →
Governor → Work Source → Wavefront (Crustify) migration graph instead of
hand-editing hive.yaml; the URL source expects a plain unauthenticated JSON
document, matching the YAML-only configuration.
Graph document. A JSON object with a graph name, a revision, and a
nodes list. Each node has id, title, an optional kind, an optional
depends_on list of node ids, and an optional status (pending (default),
ready, done, or blocked). Hive validates structure only: an unnamed
graph, a missing revision, a duplicate or malformed id, an edge to an
undefined node, or a cycle is refused as a whole; the graph is never repaired.
A small fixture lives at
pkg/worksource/wavefront/testdata/wavefront-fixture/graph.json.
Listing. A node is ready when it is not done or blocked, holds no
completion receipt at the current revision, and every node it depends on is
either done in the graph or holds a completion receipt at the current
revision. Ready nodes are listed in wave order as run-stage items: source type
run, Number: 0, stage implement, external id <graph>:<node>, stable
key <owner/repo>!<graph>:<node>, labels hive-run, stage/implement,
wavefront, wavefront/<kind>, and graph-rev/<revision>. Each
depends_on edge is carried as a DependsOn entry keyed
<owner/repo>!<graph>:<dep>, so admission sees the same edges Wavefront
declared. Blocked nodes and everything downstream of them are withheld, not
listed as unresolved.
Stale-plan guard. The graph-rev/<revision> label is the revision the
item was minted at. Source.Verify and Source.Complete take that revision
back and refuse it with ErrStaleRevision when the graph has since moved.
A refused item is never mapped onto the new graph; it is simply re-listed
from the current revision if it is still ready. A receipt recorded under an
older revision no longer satisfies anything, so a dependent whose upstream
changed is withheld again rather than silently continuing (the #8346
provenance guard, expressed through the revision).
Receipts. Source.Complete(ctx, externalID, revision, artifacts, startedAt)
writes one stage-receipt/v1 record (#8295) per completed node under
<receipts_dir>/<graph>/<node>.json: work key, assignment id
<graph>:<node>, stage implement, contract wavefront-node/v1,
input_revision wavefront-graph@<graph digest>, and the artifact-borne
progress anchors the stage produced (default wavefront/<graph>/<node>).
Completing an already-completed node at the same revision returns the existing
receipt unchanged, so a retry is idempotent. Completing a node whose
dependencies are not all satisfied is refused with ErrNotReady. Receipts are
the only state Hive keeps for the migration; there is no side database.
Plan import. wavefront.ImportPlan(store, epic, graph, expectedRevision, opts) admits the graph as an epic’s child beads through
planning.DecomposeFromOutput: the graph is rendered as the already-structured
task list that function consumes (N. [<node>] <title> (depends: ...) [agent_suitable], in wave order) and materialized with no prompt and no
planner call. Node ids become each child’s plan_ref; edges become bead
dependencies. A graph whose revision is not expectedRevision is refused
before anything is written.
Not wired yet. The adapter lists work and records receipts. Handing a
listed node to an agent worktree, the mid-node crash reconciling to Unknown,
and the burndown counts on /api/runs/{key} are follow-ups on the #8290
umbrella; the adapter’s Receipts() and Ready() are the seams they read.
type: github (default)
No config needed. Enumerates open issues on project.repos via the existing
GitHub client (pkg/worksource/factory.go:17-18). This is the only source
type most hives ever need.
type: github_projects — GitHub Projects (Projects v2)
Reads items from a GitHub Projects v2 board via the GraphQL API
(pkg/worksource/github_projects.go). Use this when work is tracked on a
project board rather than as bare repo issues.
governor:
work_source:
type: github_projects
github_projects:
project_number: 7 # required — the number in the project URL
org: your-org # optional — falls back to project.org
states: [Todo, In Progress] # optional — Status field values to include; empty = all
priority_field: Priority # optional — name of a single-select priority field
iteration_field: Sprint # optional — name of an iteration field; only current-iteration items are returned when set
default_repo: your-org/repo # optional — used when an item's own repo can't be determined
Config fields (GitHubProjectsSourceConfig, pkg/config/config.go:1696-1703):
| YAML key | Go field | Required | Notes |
|---|---|---|---|
project_number | ProjectNumber | Yes | The project’s number, visible in its URL (.../projects/7). |
org | Org | No | Defaults to project.org if empty (factory.go:23). |
states | States | No | Filters on the project’s Status single-select field. Empty means no filtering. |
priority_field | PriorityField | No | Name of a single-select field to map to normalized priority (urgent/high/medium/low/none; see normalizePriority, github_projects.go:525-538). Empty means every issue gets priority none. |
iteration_field | IterationField | No | Name of an iteration field. When set, only items whose iteration window covers “now” are returned (inCurrentIteration, github_projects.go:506-522). |
default_repo | DefaultRepo | No | owner/repo used when the project item’s own repository can’t be read from the GraphQL response. |
Credentials. The adapter authenticates with the same GitHub token the
hive already uses for issues/PRs (ghToken passed into
worksource.FromConfig, pkg/worksource/factory.go:15,23) — there is no
separate token field in github_projects:. That token needs the
read:project scope in addition to whatever repo scopes it already carries;
a classic PAT with only repo cannot read a Projects v2 board and the
GraphQL call fails with a GraphQL-level authorization error surfaced as
worksource/github_projects: graphql error: ...
(github_projects.go:330-332).
Cadence and webhooks (#13379).
The GraphQL listing is not made on every eval cycle. It runs on a reconcile
cadence (githubProjectsReconcileInterval, 15 minutes,
pkg/worksource/github_projects_cache.go) and the result is held in a
process-wide per-board cache; cycles in between read the cache, with the
status, iteration and priority filters applied at read time so the
current-iteration window moves without a re-list. Subscribing the App or
organization webhook to projects_v2_item keeps the cache current between
listings: each created/edited/deleted/reordered/archived/
restored/converted delivery is a hint that re-reads that one item by
node id (one GraphQL call; deleted removes it with no call) and patches
the cache (worksource.ApplyProjectsV2ItemEvent). The delivery’s
project_node_id must match a board that has listed at least once;
anything else waits for the next listing. Writes
(AddIssueToColumn, the review backlog destination) are unchanged and
still go straight to GitHub.
Failure mode. A wrong project_number or an org the token can’t see
returns a GraphQL error on the first listing, logged but not fatal — the
hive keeps running with an empty work-item list from this source. When a
later re-list fails, the previous listing is served (and the entry marked
stale) for up to two hours before the error surfaces again.
type: linear
governor:
work_source:
type: linear
linear:
api_key: ${LINEAR_API_KEY}
hold_labels: [hold] # additive; GitHub's hold defaults still apply
teams:
- key: ENG
repo: your-org/default-repo
states: [Todo, In Progress]
cycles: current # optional; only issues in the active cycle
projects: # optional; when present, only these projects enumerate
- name: Platform
repo: your-org/platform
assigned_only: true # optional; requires a connected Linear agent app
session_agent: scanner # which hive agent takes Linear agent sessions
A team’s (or project’s) repo also gates review scope-contract recognition: a Linear key found in a PR’s body, title, or branch is treated as its scope contract only when that key maps to the PR’s repository.
The hive then reads that issue read-only through this work source when it plans the review kick — identifier, title, state, description and the last few comments, capped at 10 KiB with a truncation note — and inlines it into the kick as untrusted data from the issue tracker, so reviewers judge against the acceptance criteria without ever holding the Linear key. The text is cached per issue and refetched only when its updatedAt changes (checked at most every five minutes). If a refresh fails, the last known-good text for that issue is reused (and not retried until the next recheck); only an issue never fetched before makes the kick name the identifier it could not fetch.
api_key and at least one teams[].key/teams[].repo are required —
construction fails closed with an explicit error naming the missing field
otherwise (factory.go:32-53). assigned_only: true additionally requires
the Linear agent app to already be connected (linearagent.StoredViewerID);
without a connected app it is a startup error, not “enumerate everything”
(factory.go:58-67).
See Linear agent integration for the OAuth app setup,
webhook wiring, LINEAR_CLIENT_ID/LINEAR_CLIENT_SECRET/
LINEAR_WEBHOOK_SECRET, and how agents write back to Linear.
ACMM gap issues. The dashboard’s ACMM “Open Issue” / “Open All” buttons
file on GitHub by default even on a Linear-sourced hive. Set
governor.acmm.issue_tracker: work_source to file them on the Linear team
mapped to the criterion’s repo instead (teams[].repo match, else the first
team) — see ACMM policy matrix → Where gap issues are filed.
type: jira — Jira Cloud or Jira Data Center
Reads issues from Jira Cloud via REST API v3, or from Jira Data Center / Server
via REST API v2 when deployment: datacenter is set (pkg/worksource/jira.go).
The Jira Data Center REST reference documents API version 2 and URI layouts
that include the instance context path, such as
http://host:port/context/rest/api-name/api-version/resource-name
(Atlassian Jira Data Center REST API reference).
Atlassian’s server examples use /rest/api/2/... endpoints for issues and
searches (Jira REST API examples).
Data Center PATs are available in Jira Core/Software 8.14+ and are sent with Jira Data Center’s bearer-token HTTP authentication (Using Personal Access Tokens).
Jira Cloud rich text comments/descriptions use ADF JSON
(Atlassian Document Format);
Data Center accepts plain text / wiki-markup string bodies.
Terms in the examples: PAT is a personal access token; JQL is Jira Query Language, used to select issues; ADF is Atlassian Document Format for rich text. TLS protects the connection, a CA is a certificate authority, and PEM is the text format used for certificates and keys. mTLS means mutual TLS: the client presents a certificate as well as verifying the server.
governor:
work_source:
type: jira
jira:
base_url: https://your-org.atlassian.net # required
email: bot@your-org.com # required — Atlassian account email
api_token: ${JIRA_API_TOKEN} # required
project_keys: [ENG, OPS] # used to build the default JQL
# jql: "project in (ENG) AND statusCategory != Done" # optional full override
repo: your-org/default-repo # required for agents to know what to clone
hold_labels: [hold, blocked] # optional — Jira labels that gate an issue
Jira Data Center / Server example:
governor:
work_source:
type: jira
jira:
deployment: datacenter
base_url: https://jira.example.com/jira # context paths are preserved
api_token: ${JIRA_DATACENTER_PAT} # preferred PAT bearer auth
# Or, for older instances without PATs:
# username: hive-bot
# password: ${JIRA_DATACENTER_PASSWORD}
# ca_bundle: ${JIRA_DATACENTER_CA_BUNDLE} # optional PEM, appended to system roots
# insecure_skip_verify: false # optional, unsafe; testing only
# client_cert: ${JIRA_DATACENTER_CLIENT_CERT} # optional mTLS PEM
# client_key: ${JIRA_DATACENTER_CLIENT_KEY} # optional mTLS PEM key
project_keys: [ENG, OPS]
repo: your-org/default-repo
hold_labels: [hold, blocked]
Config fields (JiraSourceConfig, pkg/config/config.go):
| YAML key | Go field | Required | Notes |
|---|---|---|---|
deployment | Deployment | No | Empty/cloud keeps Jira Cloud REST API v3. datacenter or server uses REST API v2 and Data Center auth/body shapes. |
base_url | BaseURL | Yes | Jira instance root, e.g. Cloud https://myorg.atlassian.net or Data Center https://jira.example.com/jira; context paths are preserved. |
email | Email | Cloud yes | Atlassian account email; used for Cloud HTTP Basic auth alongside the API token. |
username | Username | DC basic auth only | Jira Data Center username when using basic auth. |
api_token | APIToken | Cloud yes; DC preferred | Cloud API token (Basic password) or Data Center Personal Access Token (Bearer). |
password | Password | DC basic auth only | Jira Data Center password, used only when api_token is empty. Prefer PATs where supported. |
ca_bundle | CABundle | No | Data Center only. PEM CA certificate bundle appended to system trust roots. May be a ${ENV} reference or pasted PEM; dashboard responses expose only ca_bundle_set. |
insecure_skip_verify | InsecureSkipVerify | No | Data Center only. Disables server certificate and hostname verification. Default false; use only for testing. The dashboard warns loudly and the adapter logs a warning whenever this client is built. |
client_cert | ClientCert | No | Data Center only. Optional PEM client certificate for mTLS; set with client_key. Dashboard responses expose only client_cert_set. |
client_key | ClientKey | No | Data Center only. Optional PEM private key for mTLS; set with client_cert. Dashboard responses expose only client_key_set. |
project_keys | ProjectKeys | No¹ | Project keys to enumerate, e.g. ["ENG","OPS"]. Used to build the default JQL when jql is empty. |
jql | JQL | No | Full JQL override. When empty, the adapter builds project in (<keys>) AND statusCategory != Done AND issuetype != Epic. |
repo | Repo | Yes in practice | GitHub owner/name repo agents clone to work these issues; every returned Issue.Repo is set to this single value — Jira source config maps to exactly one repo, unlike Linear’s per-team repo map. |
hold_labels | HoldLabels | No | Jira label values that gate an issue out of the work list, the Jira analogue of GitHub’s hold label. |
¹ project_keys is not enforced as required by the constructor, but if both
it and jql are empty the built JQL becomes project in () AND ..., which
Jira will reject — set one or the other.
Credentials. Jira Cloud REST v3 uses HTTP Basic auth with the account
email as username and the API token (not the account password) as
password. Jira Data Center sends the PAT as bearer-token HTTP auth when
api_token is set; otherwise it falls back to HTTP Basic with
username/password (or email as the username when username is empty).
Supply secrets via ${JIRA_API_TOKEN} / ${JIRA_DATACENTER_PAT} /
${JIRA_DATACENTER_PASSWORD} environment-variable substitution in hive.yaml
— never inline literal credentials in committed config.
TLS for Data Center
If Jira is signed by an internal CA, set
ca_bundle to a PEM bundle (or ${JIRA_DATACENTER_CA_BUNDLE}) and Hive
appends those roots to the system trust store. mTLS is optional: provide both
client_cert and client_key as PEM values or environment references. The
dashboard’s Work Source tab shows these Data Center-only fields as write-only
set/unset indicators. insecure_skip_verify remains off by default; when
enabled it bypasses TLS verification, should be limited to testing, and emits a
warning every time the Jira client is built.
Jira data and failure reference
Data model differences. Cloud users expose accountId and rich-text
description/comment bodies as ADF JSON. Data Center commonly exposes users by
name / key; the adapter prefers those identities when deployment: datacenter is set. Data Center comments sent by Hive are plain strings so Jira
can render them as wiki markup/plain text; Cloud comments use a minimal ADF
document.
Priority mapping. Jira priority names are normalized case-insensitively
(normalizeJiraPriority, jira.go:126-141):
| Jira priority | Normalized |
|---|---|
highest, critical, blocker, p0 | urgent |
high, p1 | high |
medium, p2 | medium |
low, lowest, p3, p4 | low |
| anything else | none |
Hold-label gating. ListIssues drops any issue whose Jira labels
field contains one of the configured hold_labels before it is returned to
the governor — the same shape as GitHub’s hold label, but Jira has no
built-in “hold” concept so this is opt-in and additive
(jira.go:143-175).
Pagination and endpoints. Cloud posts to /rest/api/3/search/jql with an
explicit field list and follows nextPageToken until isLast or no next token.
Data Center uses /rest/api/2/search with startAt/maxResults and a total.
Both request 100 issues per page until the result set is exhausted.
Issue fetch, comment, and transition helper paths use the same API-version
switch (/issue/{key}, /issue/{key}/comment, and
/issue/{key}/transitions).
Failure mode. A bad base_url, invalid credentials, or non-2xx Jira
response causes a worksource/jira: search: ... error on every governor
cycle. For an HTTP rejection, the message is
worksource/jira: search: returned <status>: <body>. It is logged but not
fatal — the hive keeps running with an empty work-item list from this source
until the misconfiguration is fixed.
Review backlog routing (review.backlog)
Review findings below the blocking line (review.severity.block_at), and cited out-of-scope findings, are filed as follow-up items in the tracker named by review.backlog.destination. The destination must match the active work source. The item is written with this page’s work-source client and credentials (src/pkg/worksource/review_backlog_sink.go):
review.backlog.destination | Needs type: | What is filed |
|---|---|---|
github_issue (default) | any | An issue in the reviewed PR’s repo. |
github_project | github_projects | The same issue, added to the project and set to the Status option project_column_id via addProjectV2ItemById + updateProjectV2ItemFieldValue. The token also needs the project write scope. |
linear | linear | An issue on the team mapped to the PR’s repo (teams[].repo), in linear_state when set. Labels that already exist on the team are applied. |
jira | jira | A Task in the first project_keys project, moved to jira_status when set. Labels have their whitespace replaced with -. |
If the destination’s work source is not active, or cannot be built (for example a missing api_key), the hive files a GitHub issue with the agent/reviewer label and logs why. Items are de-duplicated per repo by finding fingerprint. When another PR raises the same finding, the hive comments on the existing item instead of filing a new one. At most max_per_pr_per_day items are filed or updated per PR per day. See review-swarm.md for the fingerprint, item body and audit entries.
Open questions
- The issue that requested this page (#4926) says GitHub Projects requires
a “project node ID”. The code instead takes a plain integer
project_number(the number visible in the project’s URL) and resolves it server-side via GraphQL (organization(login).projectV2(number),github_projects.go:102-103) — there is no node-ID field inGitHubProjectsSourceConfig. This page documents the code as written.