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 liveSettingStart here
GitHub repository issuesgithub (default)No new block or credentials are needed beyond working GitHub access.
A GitHub Projects boardgithub_projectsBoard setup and token scopes
Linear teams/projectslinearTeam-to-repository mapping
Jira Cloud or Jira Data CenterjiraJira 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

  1. Save your source and credentials using the chosen source’s instructions. Never commit literal credentials; use the documented environment references.
  2. Pick a known open task that matches the configured repository, team/project, state/query, and hold-label filters.
  3. 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.
  4. 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 settingTokenStatus
github (default)github.base_url / github.api_urlGitHub AppSupported
gitlabgitlab.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: true

With 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/receipts

enabled 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. [&lt;node&gt;] &lt;title&gt; (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 keyGo fieldRequiredNotes
project_numberProjectNumberYesThe project’s number, visible in its URL (.../projects/7).
orgOrgNoDefaults to project.org if empty (factory.go:23).
statesStatesNoFilters on the project’s Status single-select field. Empty means no filtering.
priority_fieldPriorityFieldNoName 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_fieldIterationFieldNoName of an iteration field. When set, only items whose iteration window covers “now” are returned (inCurrentIteration, github_projects.go:506-522).
default_repoDefaultRepoNoowner/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 keyGo fieldRequiredNotes
deploymentDeploymentNoEmpty/cloud keeps Jira Cloud REST API v3. datacenter or server uses REST API v2 and Data Center auth/body shapes.
base_urlBaseURLYesJira instance root, e.g. Cloud https://myorg.atlassian.net or Data Center https://jira.example.com/jira; context paths are preserved.
emailEmailCloud yesAtlassian account email; used for Cloud HTTP Basic auth alongside the API token.
usernameUsernameDC basic auth onlyJira Data Center username when using basic auth.
api_tokenAPITokenCloud yes; DC preferredCloud API token (Basic password) or Data Center Personal Access Token (Bearer).
passwordPasswordDC basic auth onlyJira Data Center password, used only when api_token is empty. Prefer PATs where supported.
ca_bundleCABundleNoData 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_verifyInsecureSkipVerifyNoData 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_certClientCertNoData Center only. Optional PEM client certificate for mTLS; set with client_key. Dashboard responses expose only client_cert_set.
client_keyClientKeyNoData Center only. Optional PEM private key for mTLS; set with client_cert. Dashboard responses expose only client_key_set.
project_keysProjectKeysNo¹Project keys to enumerate, e.g. ["ENG","OPS"]. Used to build the default JQL when jql is empty.
jqlJQLNoFull JQL override. When empty, the adapter builds project in (<keys>) AND statusCategory != Done AND issuetype != Epic.
repoRepoYes in practiceGitHub 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_labelsHoldLabelsNoJira 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 priorityNormalized
highest, critical, blocker, p0urgent
high, p1high
medium, p2medium
low, lowest, p3, p4low
anything elsenone

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.destinationNeeds type:What is filed
github_issue (default)anyAn issue in the reviewed PR’s repo.
github_projectgithub_projectsThe 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.
linearlinearAn 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.
jirajiraA 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 in GitHubProjectsSourceConfig. This page documents the code as written.