A CLI for managing a GitHub ProjectV2 board. Syncs the board to a local SQLite cache for fast queries and writes changes back via the GitHub GraphQL API.
make installRequires Go 1.24+. The binary is installed to $(go env GOPATH)/bin.
Create ~/.config/project-board/config.yaml:
github_token: ghp_...
project_url: https://github.com/orgs/YOUR_ORG/projects/N
default_team: "Your Team"
default_repo: your-org/your-repo
template_repo: your-org/your-roadmap-repo # optional, defaults to default_repo
team_field: "Team / Area" # optional, default shown
sprint_field: "Sprint" # optional, default shownA GitHub token with project and repo scopes is required.
Define how different kinds of items are displayed. The match field is an expr-lang expression evaluated against each item's fields.
item_types:
- name: Epic
match: "kind == 'Epic'"
hide: [sprint] # hide these fields in `show` output
hide_subitems: false # set true to suppress child item list
terminal_statuses: [Shipped]
template: epic # issue template to use with `new`
- name: Item
match: "true" # catch-all; evaluated lastNamed saved queries with display configuration.
views:
- name: current-sprint
query: "team == 'Platform' and sprint != nil"
columns: [number, title, status, assignee]
- name: epics
query: "kind == 'Epic' and status != 'Shipped'"
columns: [number, title, status, assignee]
show_hierarchy: falseproject-board sync # fetch all items, fields, sprints, and templates
project-board query # list all items
project-board query [expr] # filter with an expression
project-board query --sprint current # pre-filter by sprint
project-board query --team Platform # pre-filter by team
project-board query --view epics # use a saved view
project-board show <n> # full detail; child items shown automatically
project-board show <n> --raw # show without item_type display rules
project-board update <n> key=value … # update fields
project-board new key=value … # create a new item
project-board archive <n> # archive a project item
Expressions use expr-lang syntax. Field names are normalized to lowercase with underscores.
Built-in fields: number, title, state, status, sprint, team, priority, kind, has_parent, parent
Custom project fields are available by their normalized name (e.g. "Team / Area" → team_area).
project-board query "kind == 'Epic'"
project-board query "status == 'In Progress' and team == 'Platform'"
project-board query "kind == 'Epic' and (status == 'Active' or status == 'Paused')"
project-board query "kind == nil"
project-board query "has_parent == false and sprint == 'Sprint 42'"
project-board query --columns number,title,status,sprintproject-board update 42 status="In Progress"
project-board update 42 sprint=next
project-board update 42 title="New title" status=Done
project-board update 42 parent=10 # set parent (GitHub sub-issue)
project-board update 42 parent= # clear parent
project-board update 42 status= # clear a fieldSpecial keys: title, body, state (open/closed), parent. All other keys are looked up as project field names by normalized key. Sprint accepts offsets (current, next, previous, current+N) or a sprint title.
project-board new title="Fix login bug"
project-board new title="Q3 Initiative" kind=Epic
project-board new title="Implement auth" sprint=current status="In Progress" team=Platform
project-board new title="New feature" template=slicetitle= is required. body=, repo=owner/name, and template=<name> are special; everything else sets a project board field. Templates are loaded from the cache by name (stored during sync from .github/ISSUE_TEMPLATE/).
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.