Connectors
Cromford talks to every tracker through one set of verbs: list, read, comment, transition, add and remove a label, link a PR, and close out. Each tracker gets its own adapter for those verbs.
A project picks its tracker with the settings row tracker_adapter.<project>. The value is github-issues, jira or linear. With no row, the project uses the tracker it was enrolled with. Any other value is refused, and nothing is filed.
These pages list setting and credential names only. Values never go in a settings file or a log.
GitHub Issues
Section titled “GitHub Issues”This is the default, and the one the quickstart sets up.
- What it reads: issues labeled
ai-build, with their comments and labels. Every call goes through GitHub’s REST API. - What it writes: comments, labels and state. Linking a PR is a
PR: <url>comment, because the issue API has no PR-link field. - Credentials: the GitHub App (
GH_APP_ID,GH_APP_PRIVATE_KEY_FILE) or the token (GH_TOKEN) from your setup. Install the App, or scope the token, only on the repos Cromford watches. - Webhooks: the jobs worker takes GitHub deliveries at
POST /webhooks/githuband wakes triage for the issue.
GitHub has no “waiting on” or triage verdict fields, so the adapter reports those as empty rather than guessing.
Jira Cloud
Section titled “Jira Cloud”- What it reads: issues found by a bounded JQL search, and their comments. It uses REST v3 through Atlassian’s scoped-token gateway,
https://api.atlassian.com/ex/jira/<cloudId>. Jira Server and Data Center are not supported. - What it writes: comments (as Atlassian’s document format), labels and transitions. It finds transitions by asking Jira, so no status name is hard-coded.
- Credentials: in the project’s own env file:
JIRA_BASE,JIRA_EMAIL,JIRA_API_TOKENandJIRA_SITE. - Settings rows:
tracker_jira.<project>.write_projects,comment_projectsandread_projectsare the allowlists. Alsolabel(defaultai-build),waiting_on_field,triage_verdict_fieldandstatus_map.
The allowlist is a hard guard. Every call names an issue key like <KEY>-12, and that key’s project has to be on the right allowlist. With no write row, nothing is written. Before every write, the adapter reads the issue back and refuses unless Jira answers with the same key in the same project. A moved issue can’t send a write somewhere you didn’t allow.
The readiness gate reads Jira tickets through this adapter. The rest of the build pipeline doesn’t drive Jira end to end yet.
Linear
Section titled “Linear”- What it reads: issues for your team, filtered by a label (default
ai-build), through Linear’s GraphQL API. - What it writes: comments, labels and state. Linking a PR is a real Linear attachment. Labels are never created: a label your workspace doesn’t have is an error.
- Credentials: a Linear personal API key, plus your team key (like
<TEAM>). - States: by default it maps by Linear’s state type (unstarted, started, completed, canceled), and review is the state named “In Review”. You can map names yourself.
The adapter is built, but the build pipeline doesn’t call it yet.
Webhooks for Jira and Linear
Section titled “Webhooks for Jira and Linear”Without webhooks, Cromford polls. With them, a real change wakes it right away. The jobs worker takes POST /webhooks/jira and POST /webhooks/linear. Each checks its own signature, and each delivery wakes triage once, however many times the vendor resends it.
Only real changes wake it: a new issue or comment, or an edit to status, labels, title or description. Sort-order moves, sprints and reactions don’t. Changes made by the accounts you list as Cromford’s own (webhook_self.jira, webhook_self.linear) are dropped.
Both receivers are off until you arm them:
- Set the worker secret,
JIRA_WEBHOOK_SECRETorLINEAR_WEBHOOK_SECRET. - In Jira or Linear, add a webhook to
https://<jobs-host>/webhooks/jira(or/webhooks/linear) with the same secret. For Jira, scope it with JQL to your project. - Add the settings row
webhook_route.jira.<project key>orwebhook_route.linear.<team key>, with your repo asowner/repo.
Before step 1 a delivery gets a 503. After it, an unsigned one gets a 401.