Manage your Linear workspace as code — teams, labels, workflow states, views, git automation and workspace settings, reconciled by OpenTofu
resource "linear_custom_view" "in_review" {
name = "In Review"
team_id = linear_team.eng.id
shared = true
filter_json = jsonencode({
state = { type = { eq = "started" } }
})
}Teams, labels, workflow states, views and git automation declared in HCL and reconciled by OpenTofu — not clicked together in the Linear UI. Scope is workspace configuration, not issue content.
Important
Pre-1.0 / beta. Every resource and data source below is implemented and covered by acceptance tests against a GraphQL mock, but nothing has been verified against a live workspace yet — which fields Linear really accepts, and what its actual defaults are, is still unconfirmed. Pin an exact version and test before relying on it.
terraform {
required_providers {
linear = {
source = "kirchdev/linear"
version = "~> 0.1"
}
}
}
provider "linear" {
token = var.linear_token # or set LINEAR_TOKEN
}
resource "linear_team" "eng" {
name = "Engineering"
key = "ENG"
}export LINEAR_TOKEN="lin_api_..." # Linear → Settings → API → Personal API keys
tofu planNote
A Linear API key is workspace-scoped. Managing several workspaces needs one aliased provider per workspace, each with its own key.
- 📐 Linear as code — teams, labels, workflow states, views, git automation, webhooks and workspace settings in HCL.
- 🔭 Views included —
linear_custom_viewwith team, project and initiative scope. Filters are expressed as JSON and compared semantically, so a server-normalised filter doesn't read as drift. - 🧩 Full workspace-settings coverage — every field
organizationUpdateaccepts, not a subset. - 🌿 Git automation per event —
draft,start,review,mergeableandmergeeach as their own resource, so all five round-trip on import. - 🚀 OpenTofu & Terraform — published as
kirchdev/linearon both registries. - ⚡ Modern stack —
terraform-plugin-framework; docs generated from the schema.
Scope is workspace configuration. Issues, projects, initiatives, documents and comments are content — they belong in Linear's UI and its API, not in a state file.
Full coverage
- Workspace —
linear_workspace_settings,linear_workspace_label,linear_project_status,linear_project_label,linear_initiative_label,linear_emoji. - Teams —
linear_team,linear_team_label,linear_team_membership,linear_workflow_state,linear_template,linear_triage_responsibility,linear_time_schedule,linear_email_intake_address,linear_agent_skill. - Git automation —
linear_git_automation_state,linear_git_automation_target_branch. - Views —
linear_custom_view,linear_view_preferences. - Integrations —
linear_webhook,linear_integrations_settings. - Releases —
linear_release_pipeline,linear_release_stage. - Customers —
linear_customer_status,linear_customer_tier. Needs Linear Customers enabled for the workspace. - Data sources —
linear_organization,linear_team(s),linear_user(s),linear_workflow_state(s),linear_label(s),linear_custom_view(s),linear_template.
Per-resource docs live under docs/, generated from the schema with make docs (build + export schema + tfplugindocs).
PRs welcome. Conventional Commits required (enforced via commitlint). Husky runs the linters/formatters on git commit.
Tip
Run make build && go vet ./... before pushing — CI will catch what husky missed.
See CONTRIBUTING.md for the full workflow.
Semantic Versioning via release-please — see CHANGELOG.md.