Hamburger Cross Icon
Ticket Field
+
Linear Collector

Ticket Field + Linear Collector

✓ Guardrail ↓ Collector Stable Devex Build And Ci

Enforce Ticket Field using data collected by Linear Collector. Automatically check devex build and ci standards on every PR.

Guardrail: Ensures a configured ticket field, such as a Jira custom field, has an allowed value.
Data Source: Extract Linear ticket references from pull request titles, validate them against the Linear GraphQL API, and detect ticket reuse across PRs.

How Linear Collector Powers This Guardrail

The Linear Collector gathers metadata from your vcs systems. This data flows into Lunar's Component JSON, where the Ticket Field guardrail evaluates it against your standards.

When enabled, this check runs automatically on every PR and in AI coding workflows, providing real-time enforcement with actionable feedback.

1
↓ Linear Collector Gathers Data Collector
Extracts metadata from code, configs, and tool outputs
2
{ } Component JSON
Data centralized in structured format for evaluation
3
✓ Ticket Field Checks Guardrail
Pass/fail result with actionable feedback in PRs

Quick Start Configuration

Add both the collector and policy to your lunar-config.yml to enable this guardrail.

📄 lunar-config.yml
# Step 1: Enable the Linear Collector
collectors:
  - uses: github://earthly/lunar-lib/collectors/linear@v1.0.5
    # with: ...

# Step 2: Enable the Ticket Guardrails
policies:
  - uses: github://earthly/lunar-lib/policies/ticket@v1.0.5
    include: [ticket-field]
    # with: ...

What Linear Collector Collects

This collector gathers the following data that the Ticket Field guardrail evaluates.

Collector code

ticket

Extracts Linear ticket ID from PR title, fetches issue metadata from the Linear GraphQL API, and writes normalized ticket data to .vcs.pr.ticket and native Linear data to .vcs.pr.ticket.native.linear.

Collector code

ticket-history

Queries the Lunar SQL database to count how many other PRs reference the same ticket. Writes .vcs.pr.ticket.reuse_count for policy evaluation. Detects ticket recycling abuse.

Example Data Flow

Here's an example of the data that Linear Collector writes to the Component JSON, which Ticket Field then evaluates.

{ } component.json From Linear Collector
{
  "vcs": {
    "pr": {
      "ticket": {
        "id": "ENG-123",
        "source": { "tool": "linear", "integration": "api" },
        "url": "https://linear.app/acme/issue/ENG-123/add-payment-validation",
        "valid": true,
        "status": "In Progress",
        "type": "bug",
        "summary": "Add payment validation",
        "assignee": "jane@acme.com",
        "reuse_count": 0,
        "native": {
          "linear": {
            "id": "abc123",
            "identifier": "ENG-123",
            "title": "Add payment validation",
            "url": "https://linear.app/acme/issue/ENG-123/add-payment-validation",
            "state": { "name": "In Progress", "type": "started" },
            "assignee": { "email": "jane@acme.com", "displayName": "Jane" },
            "labels": { "nodes": [{ "name": "bug" }] },
            "priority": 2,
            "priorityLabel": "High",
            "team": { "key": "ENG", "name": "Engineering" }
          }
        }
      }
    }
  }
}

Configuration Options

Linear Collector Inputs

Input Required Default Description
ticket_prefix Required — Character(s) before the ticket ID in PR titles (empty = match anywhere)
ticket_suffix Required — Character(s) after the ticket ID in PR titles (empty = match anywhere)
ticket_pattern Optional [A-Za-z][A-Za-z0-9]+-[0-9]+ Regex pattern for ticket ID (without prefix/suffix)
type_labels Required — Comma-separated label names to treat as issue types (e.g. "bug,feature,chore"). If the Linear issue has a matching label, it is written as .vcs.pr.ticket.type. Empty means no type extraction from labels.

Ticket Guardrails Inputs

Input Required Default Description
allowed_sources Required — Comma-separated list of allowed ticket sources (e.g. "jira,linear"). Empty = any.
allowed_statuses Required — Comma-separated list of allowed ticket statuses (empty = any)
disallowed_statuses Required — Comma-separated list of disallowed ticket statuses (empty = none)
allowed_types Required — Comma-separated list of allowed issue types (empty = any)
max_ticket_reuse Optional 3 Maximum number of other PRs allowed to reference the same ticket
ticket_field Required — Field the `ticket-field` check reads, as a path relative to the ticket (e.g. native.jira.fields.customfield_10042 for a Jira custom field). Empty skips the check.
allowed_field_values Required — Values `ticket-field` accepts: comma-separated, one per line, or a JSON array for values that contain a comma. Empty accepts any value, so the field only has to be set.
ticket_path Optional .vcs.pr.ticket Where every check reads the ticket from. Point a second import of this policy at the path a second jira collector import records to (e.g. .vcs.pr.architecture_review) to check that reference as well.
skip_authors Required — PR author logins whose PRs every check skips, such as dependency bots (e.g. dependabot[bot], renovate[bot]). Comma-separated or one per line; matched exactly, ignoring case, so keep the [bot] suffix GitHub gives an app. Empty skips no one.

Ready to Automate Your Standards?

See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 300+ built-in guardrails.

Works with any process
check AI agent rules & prompt files
check Post-mortem action items
check Security & compliance policies
check Testing & quality requirements
Auto-ID My Guardrails
Paste your AGENTS.md or manual process doc and get guardrails in minutes
Book a Demo