name: langwatch-kanban description: "Manage the LangWatch Kanban GitHub project board — sync statuses, view your board, find stale items, move issues, assign work." user-invocable: true allowed-tools: Bash(gh:), Bash(python3:) argument-hint: "<sync|my-board|stale|move|assign> [args]"
LangWatch Kanban
Manage the LangWatch Kanban GitHub project board (project #5, org: langwatch).
Project Reference
Read the project board reference from memory before doing anything:
- File:
/Users/USER/.claude/projects/-Users-hope-workspace-langwatch-workspace-langwatch-saas-langwatch/memory/reference_gh-project.md
This contains all project IDs, field IDs, status option IDs, and GraphQL patterns. Use python3 for all JSON parsing — issue titles with special characters break jq.
Subcommands
Parse $ARGUMENTS to determine which subcommand to run:
sync
Sync the project board so statuses match reality.
- Page through all project items (100 per page, up to 8 pages) using the GraphQL
projectV2.itemsquery - Find items where:
- Issue/PR state is
CLOSEDorMERGEDbut project status is NOTDoneorReleased
- Issue/PR state is
- For each stale item, update the Status field to
Doneusing theupdateProjectV2ItemFieldValuemutation - Report what was changed:
Synced N items to Done: #123 — Title here (was: In progress) #456 — Title here (was: Ready) - If nothing to sync, say "Board is in sync — no stale items found."
my-board
Show the current user's assigned items grouped by status.
- Get current user:
gh api user --jq .login - Page through project items, collecting items where the current user is an assignee
- Group by status and display:
## In progress (3) - #123 — Title here [bug] - #456 — Title here [feature, scenarios] ## Ready (2) - #789 — Title here [chore] ## Backlog (5) - #101 — Title here ... - Skip
DoneandReleaseditems - Show a count summary at the end
stale
Find items that may be stuck or forgotten.
- Page through project items
- Flag items that are:
- In progress but the issue has had no updates in 14+ days
- In review but the linked PR has no review activity in 7+ days
- Blocked with no recent comments explaining why
- For each flagged item, show:
#123 — Title [In progress, last updated 21 days ago] #456 — Title [Blocked, no comments since 2026-03-01] - Suggest actions: "Move to Backlog?", "Close as stale?", "Needs attention?"
move <issue-number> <status>
Move an issue to a new status on the board.
- Parse the issue number and target status from arguments
- Map status name (case-insensitive) to option ID:
backlog→14fed42eblocked→131e7d86ready→12261fbfin-progress/progress→3264b20ein-review/review→90b57b27done→2b388473released→7717b7edstale→9fefdc9d
- Find the project item ID by paging through items and matching the issue number
- Update the status field
- Confirm:
Moved #123 to In progress
assign <issue-number>
Assign an issue to the current user and ensure it's on the board.
- Get current user:
gh api user --jq .login - Assign the issue:
gh issue edit <number> --repo langwatch/langwatch --add-assignee <login> - Check if it's on the project board; if not, add it:
gh project item-add 5 --owner langwatch --url <issue-url> - Confirm:
Assigned #123 to <login> and added to LangWatch Kanban
GraphQL Pagination Pattern
Use this python3 pattern for all paginated queries:
import subprocess, json
cursor = None
results = []
for page in range(1, 9):
after = f', after: "{cursor}"' if cursor else ''
query = '''{
organization(login: "langwatch") {
projectV2(number: 5) {
items(first: 100''' + after + ''') {
nodes {
id
content {
... on Issue { number title state }
... on PullRequest { number title state merged }
}
fieldValueByName(name: "Status") {
... on ProjectV2ItemFieldSingleSelectValue { name }
}
}
pageInfo { hasNextPage endCursor }
}
}
}
}'''
result = subprocess.run(
['gh', 'api', 'graphql', '-f', f'query={query}'],
capture_output=True, text=True
)
data = json.loads(result.stdout)
items = data['data']['organization']['projectV2']['items']
for n in items['nodes']:
content = n.get('content') or {}
status = (n.get('fieldValueByName') or {}).get('name', '')
# ... process each item ...
results.append({...})
if not items['pageInfo']['hasNextPage']:
break
cursor = items['pageInfo']['endCursor']
Error Handling
- If
$ARGUMENTSis empty or unrecognized, show usage:Usage: /langwatch-kanban <command> [args] Commands: sync Sync closed issues/PRs to Done status my-board Show your assigned items by status stale Find stuck or forgotten items move <#number> <status> Move an issue to a new status assign <#number> Assign issue to you and add to board Statuses: backlog, blocked, ready, in-progress, in-review, done, released, stale - If
gh auth statusfails, tell the user to rungh auth login - If a project API call fails, show the error and suggest
gh auth refresh -s project
Constants
These are hardcoded from the LangWatch Kanban project:
PROJECT_NUMBER = 5
ORG = "langwatch"
REPO = "langwatch/langwatch"
PROJECT_ID = "PVT_kwDOCL9uOs4BH69J"
STATUS_FIELD_ID = "PVTSSF_lADOCL9uOs4BH69Jzg4iLlU"
STATUS_OPTIONS = {
"Backlog": "14fed42e",
"Blocked": "131e7d86",
"Ready": "12261fbf",
"In progress": "3264b20e",
"In review": "90b57b27",
"Done": "2b388473",
"Released": "7717b7ed",
"Stale": "9fefdc9d",
}