ワンクリックで
gh-projects
Manage GitHub Projects v2 board: add issues, update field values, and query board state. Use when managing project boards.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Manage GitHub Projects v2 board: add issues, update field values, and query board state. Use when managing project boards.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | gh-projects |
| description | Manage GitHub Projects v2 board: add issues, update field values, and query board state. Use when managing project boards. |
Manage GitHub Projects v2 board operations: add issues as cards, update field values (status, type, ADR required), and query board state. Uses gh project CLI where available; falls back to gh api graphql for operations the CLI does not expose.
| Field | Source | Example |
|---|---|---|
project_number | project.config.yaml (github.project_number) | 3 — null = ask once; 0 = declined |
project_node_id | project.config.yaml | "PVT_kwDO..." |
status_field_id | project.config.yaml (github.status_field_id) | "PVTSSF_..." |
issue_node_id | gh-issues skill output | "I_kwDO..." |
issue_number | gh-issues skill output | 42 |
field_name | project field name | "Status" |
field_value | target option name | "In Progress" (capital P — GitHub's default option) |
Parse the github.* values robustly — strip inline comments (#…) and quotes, so
values like project_number: null # null = ask once read as null, not the
whole comment:
cfg_get() { # cfg_get <key> → prints value or empty
python3 -c "
import sys
key = '$1'
for line in open('project.config.yaml'):
s = line.strip()
if s.startswith(key + ':'):
v = s.split(':', 1)[1]
v = v.split('#', 1)[0].strip().strip('\"').strip(\"'\")
print(v)
break
"
}
PROJECT_NUMBER=$(cfg_get project_number) # "" if absent (old config) → treat as null
PROJECT_NODE=$(cfg_get project_node_id)
STATUS_FIELD_ID=$(cfg_get status_field_id)
Run this before adding any card. project_number has three states — an absent key
in an older config counts as null:
null or empty — not yet decided. Ask the user once:
"Add issues to a GitHub project board? (yes → bootstrap a board / no → skip)".
maple project (or bootstrap via GraphQL); it writes
project_number, project_node_id, and status_field_id back to
project.config.yaml. Continue.python3 - <<'PY'
import re
p = 'project.config.yaml'; s = open(p).read()
s = re.sub(r'(project_number:\s*)null', r'\g<1>0', s, count=1)
open(p, 'w').write(s)
PY
0 — user declined. Skip all board operations silently.> 0 — configured. Proceed with add + Status updates below.# CLI (preferred)
gh project item-add "$PROJECT_NUMBER" \
--owner "{owner}" \
--url "https://github.com/{owner}/{repo}/issues/{issue_number}"
# GraphQL fallback (when CLI unavailable or for automation)
gh api graphql -f query='
mutation($project: ID!, $content: ID!) {
addProjectV2ItemById(input: {projectId: $project, contentId: $content}) {
item { id }
}
}' \
-f project="$PROJECT_NODE" \
-f content="{issue_node_id}" \
--jq '.data.addProjectV2ItemById.item.id'
Save the returned item_id — required for field updates.
Field updates require the field's node ID and the option's node ID (for single-select fields).
FIELDS=$(gh api graphql -f query='
query($project: ID!) {
node(id: $project) {
... on ProjectV2 {
fields(first: 20) {
nodes {
... on ProjectV2Field { id name }
... on ProjectV2SingleSelectField {
id name
options { id name }
}
}
}
}
}
}' \
-f project="$PROJECT_NODE")
# Extract field ID by name
FIELD_ID=$(echo "$FIELDS" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for f in d['data']['node']['fields']['nodes']:
if f.get('name') == '{field_name}':
print(f['id'])
break
")
# Extract option ID by value (single-select fields)
OPTION_ID=$(echo "$FIELDS" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for f in d['data']['node']['fields']['nodes']:
if f.get('name') == '{field_name}':
for opt in f.get('options', []):
if opt['name'] == '{field_value}':
print(opt['id'])
break
")
For the Status field, use the cached $STATUS_FIELD_ID from config as
$FIELD_ID when it is set — skip the field-ID lookup. Fall back to the fetch
above only when it is empty.
gh api graphql -f query='
mutation($project: ID!, $item: ID!, $field: ID!, $option: String!) {
updateProjectV2ItemFieldValue(input: {
projectId: $project
itemId: $item
fieldId: $field
value: { singleSelectOptionId: $option }
}) {
projectV2Item { id }
}
}' \
-f project="$PROJECT_NODE" \
-f item="{item_id}" \
-f field="$FIELD_ID" \
-f option="$OPTION_ID"
gh api graphql -f query='
mutation($project: ID!, $item: ID!, $field: ID!, $value: String!) {
updateProjectV2ItemFieldValue(input: {
projectId: $project
itemId: $item
fieldId: $field
value: { text: $value }
}) {
projectV2Item { id }
}
}' \
-f project="$PROJECT_NODE" \
-f item="{item_id}" \
-f field="$FIELD_ID" \
-f value="{text_value}"
| Phase | Field | Value |
|---|---|---|
| Discover | Status | Todo |
| Architect | Status | In Progress |
| Implement | Status | In Progress |
| Validate | Status | In Review |
| Done | Status | Done |
# List all items with status
gh project item-list "$PROJECT_NUMBER" \
--owner "{owner}" \
--format json \
--jq '.items[] | {id, title: .content.title, status: .fieldValues[] | select(.field.name=="Status") | .name}'
| Condition | Action |
|---|---|
project_node_id missing from config | Run maple project to bootstrap. Stop until resolved. |
| Item already on board | Query before adding. gh project item-list and check content URL. Skip if present. |
| Field ID not found | Re-fetch fields. Field names are case-sensitive. |
| Option ID not found | List available options from field metadata. Do not guess. |
| GraphQL rate limit | Wait 60 seconds. Retry once. Log and stop on second failure. |
[gh-projects] ADD #42 → project #{project_number} item_id={id}
[gh-projects] UPDATE #42 field=Status value="In Progress"
[gh-projects] SKIP #42 already on board
MAPLE AI Development Squad — install the full skill set for multi-agent development workflows: pipeline-runner, tdd-workflow, playwright-cli, github-cli, mermaid-diagrams, and more. Designed for Claude Code, OpenCode, and GitHub Copilot.
Universal dispatcher: run a named taffy workflow (.claude/taffy/<name>.yaml), a skill (/skill-name), or a sub-agent (@agent-name). Falls back to skills.sh registry when a skill is not found locally. Tracks all runs in .claude/state/maple.json so the maple TUI shows live progress.
Universal dispatcher: run a named taffy workflow (.claude/taffy/<name>.yaml), a skill (/skill-name), or a sub-agent (@agent-name). Falls back to skills.sh registry when a skill is not found locally. Tracks all runs in .claude/state/maple.json so the maple TUI shows live progress.
Bootstrap and sync GitHub labels and milestones idempotently. Use when setting up a new repository or syncing label definitions.
Create, read, update, and link GitHub Issues as story artifacts throughout the story lifecycle. Use when managing issues for stories.
Manage GitHub Projects v2 board: add issues, update field values, and query board state. Use when managing project boards.