| name | Managing GitHub Projects |
| description | Manages GitHub Projects V2 items and custom fields using GitHub CLI commands. Use when adding issues/PRs to projects, updating Status (Backlog/Todo/Doing/Done), Value (Essential/Useful/Nice-to-have), or Effort (Light/Moderate/Heavy) fields, querying project data, or performing bulk operations. |
GitHub Projects Management
Manage GitHub Projects V2 items and custom fields using the GitHub CLI.
What you should do
When invoked, help the user manage project items by:
Understanding the request - Determine what operation is needed:
- Update item field values (Status, Value, Effort, or other custom fields)
- Add issues/PRs to projects
- Query project items and their field values
- List available fields and options
- Bulk operations on multiple items
Gather required information - You may need:
- Project number or ID
- Repository owner (org or user)
- Issue/PR number (for adding to project)
- Item ID (for updating existing items)
- Field name and new value
Execute the appropriate operation based on the request type.
Core operations
1. Add item to project
# Add issue to project
gh project item-add <project-number> --owner <org> --url <issue-url>
# Example
gh project item-add 1 --owner kynoptic --url https://github.com/kynoptic/ultimate-ranks-data/issues/310
2. List project fields
# Get all fields
gh project field-list <project-number> --owner <org> --format json
# Get specific field ID
gh project field-list <project-number> --owner <org> --format json \
--jq '.fields[] | select(.name == "Status") | .id'
# Get field options (for single-select fields)
gh project field-list <project-number> --owner <org> --format json \
--jq '.fields[] | select(.name == "Status") | .options[] | {name, id}'
3. List project items
# Get all items with details
gh project item-list <project-number> --owner <org> --format json --limit 100
# Get specific item by issue number
gh project item-list <project-number> --owner <org> --format json \
--jq '.items[] | select(.content.number == 307) | {id, number: .content.number, title: .content.title}'
4. Update item fields
Single-select fields (Status, Value, Effort):
gh project item-edit \
--id <item-id> \
--project-id <project-id> \
--field-id <field-id> \
--single-select-option-id <option-id>
Text fields:
gh project item-edit \
--id <item-id> \
--project-id <project-id> \
--field-id <field-id> \
--text "new text value"
Date fields:
gh project item-edit \
--id <item-id> \
--project-id <project-id> \
--field-id <field-id> \
--date "2025-10-18"
Number fields:
gh project item-edit \
--id <item-id> \
--project-id <project-id> \
--field-id <field-id> \
--number 42
Clear a field:
gh project item-edit \
--id <item-id> \
--project-id <project-id> \
--field-id <field-id> \
--clear
Project-specific configuration
To use this skill effectively, you'll need to identify the project-specific IDs for your repository. Use the commands below to discover these values:
# Get project number and ID
gh project list --owner <org-or-user> --format json | jq '.[] | {title, number, id}'
# Get custom field IDs
gh project field-list <project-number> --owner <org-or-user> --format json
Example custom fields configuration:
Status field
- Field ID:
PVTSSF_lAHOAvtmyM4BCtNbzg01sVQ - Type: Single-select
- Options:
Backlog(ID:6a4c50b0) - Not yet prioritized or ready to startTodo(ID:f75ad846) - Ready to start, requirements clearDoing(ID:47fc9ee4) - Currently being worked onDone(ID:98236657) - Completed and merged
Workflow:
Backlog→ Items not yet ready or prioritizedTodo→ Requirements defined, ready to pick upDoing→ Active work in progressDone→ Work completed and merged
Note: Use issue dependencies (blockedBy/blocking) to indicate when items cannot proceed.
Value field
- Field ID:
PVTSSF_lAHOAvtmyM4BCtNbzg01ul0 - Type: Single-select
- Options:
Essential(ID:5885ea3a) - Critical functionality, must haveUseful(ID:50c89511) - Valuable improvement, should haveNice-to-have(ID:1e7b8c9e) - Optional enhancement, could have
When to use:
Essential: Core features, security fixes, data integrity issues, blocking bugsUseful: Significant improvements, important refactors, common use casesNice-to-have: Minor enhancements, edge cases, cosmetic improvements
Note: These values align conceptually with the "Must fix/Should fix/Nice to have" framework commonly used in code reviews and development prioritization.
Effort field
- Field ID:
PVTSSF_lAHOAvtmyM4BCtNbzg02ZGg - Type: Single-select
- Options:
Light(ID:449696b6) - Quick task, minimal complexityModerate(ID:6ec15605) - Standard task, some complexityHeavy(ID:187484d1) - Complex task, significant work
When to use:
Light: Simple changes, typo fixes, small refactors, minor featuresModerate: Standard features, multi-file changes, moderate complexityHeavy: Major features, architectural changes, large refactors, cross-cutting concerns
Complete workflow example
Goal: Add issue #310 to project and set Status=Todo, Value=Useful, Effort=Moderate
# Step 1: Add to project
ITEM_ID=$(gh project item-add 1 --owner kynoptic \
--url https://github.com/kynoptic/ultimate-ranks-data/issues/310 \
--format json | jq -r '.id')
# Step 2: Set constant IDs (from configuration above)
PROJECT_ID="PVT_kwHOAvtmyM4BCtNb"
STATUS_FIELD_ID="PVTSSF_lAHOAvtmyM4BCtNbzg01sVQ"
VALUE_FIELD_ID="PVTSSF_lAHOAvtmyM4BCtNbzg01ul0"
EFFORT_FIELD_ID="PVTSSF_lAHOAvtmyM4BCtNbzg02ZGg"
# Option IDs (from configuration above)
TODO_ID="f75ad846"
USEFUL_ID="50c89511"
MODERATE_ID="6ec15605"
# Step 3: Update fields
gh project item-edit --id "$ITEM_ID" --project-id "$PROJECT_ID" \
--field-id "$STATUS_FIELD_ID" --single-select-option-id "$TODO_ID"
gh project item-edit --id "$ITEM_ID" --project-id "$PROJECT_ID" \
--field-id "$VALUE_FIELD_ID" --single-select-option-id "$USEFUL_ID"
gh project item-edit --id "$ITEM_ID" --project-id "$PROJECT_ID" \
--field-id "$EFFORT_FIELD_ID" --single-select-option-id "$MODERATE_ID"
Efficient patterns
Pattern 1: Load configuration from project config file
Recommended: Use the project configuration file created by gh-project-setup:
# Load configuration from standard location (.github/project-config.json)
CONFIG_FILE=".github/project-config.json"
# Extract IDs from config using jq
PROJECT_ID=$(jq -r '.project.id' "$CONFIG_FILE")
STATUS_FIELD_ID=$(jq -r '.fields.status.id' "$CONFIG_FILE")
BACKLOG_ID=$(jq -r '.fields.status.options.Backlog.id' "$CONFIG_FILE")
# Use in project commands
gh project item-edit --id "$ITEM_ID" --project-id "$PROJECT_ID" \
--field-id "$STATUS_FIELD_ID" --single-select-option-id "$BACKLOG_ID"
Best practice: Store project config in .github/project-config.json (not docs/):
- ✅ Standard location for GitHub-specific configuration
- ✅ Alongside workflows, issue templates, and other automation
- ✅ Separates infrastructure config from user documentation
- ✅ Created automatically by
gh-project-setupskill
Alternative: Query and cache field IDs dynamically (if config file doesn't exist):
# Get all field configurations once
gh project field-list 1 --owner kynoptic --format json > /tmp/project-fields.json
# Extract IDs as needed
STATUS_BACKLOG=$(jq -r '.fields[] | select(.name == "Status") | .options[] | select(.name == "Backlog") | .id' /tmp/project-fields.json)
Pattern 2: Bulk updates
Update multiple items with the same field value:
# Get all items in "Todo" status
TODO_ITEMS=$(gh project item-list 1 --owner kynoptic --format json \
--jq '.items[] | select(.status.name == "Todo") | .id')
# Move selected items to "Doing"
PROJECT_ID="PVT_kwHOAvtmyM4BCtNb"
STATUS_FIELD_ID="PVTSSF_lAHOAvtmyM4BCtNbzg01sVQ"
DOING_ID="47fc9ee4"
for item_id in $TODO_ITEMS; do
gh project item-edit --id "$item_id" --project-id "$PROJECT_ID" \
--field-id "$STATUS_FIELD_ID" --single-select-option-id "$DOING_ID"
done
Pattern 3: Update from issue metadata
Set project fields based on issue labels:
# If issue has "bug" label, set Value=Essential
if gh issue view 123 --json labels --jq '.labels[].name' | grep -q "bug"; then
PROJECT_ID="PVT_kwHOAvtmyM4BCtNb"
VALUE_FIELD_ID="PVTSSF_lAHOAvtmyM4BCtNbzg01ul0"
ESSENTIAL_ID="5885ea3a"
gh project item-edit --id "$ITEM_ID" --project-id "$PROJECT_ID" \
--field-id "$VALUE_FIELD_ID" --single-select-option-id "$ESSENTIAL_ID"
fi
Error handling
Common issues:
"project scope required"
gh auth refresh -s project"Field type not supported"
- Some field types (like parent_issue) cannot be edited via API
- Use web UI for unsupported fields
"Item not found"
- Verify item is in the project
- Check that item ID is correct (starts with
PVTI_)
"Invalid option ID"
- Option IDs change if field options are modified
- Re-fetch field configuration to get current IDs
Best practices
Value/Effort prioritization matrix:
- Essential + Light = Quick wins (do first!)
- Essential + Moderate = Core work (plan and execute)
- Essential + Heavy = Strategic investments (careful planning required)
- Useful + Light = Easy improvements (fill-in tasks)
- Useful + Moderate = Standard backlog work
- Useful + Heavy = Consider scope reduction or phasing
- Nice-to-have + Light = Low priority improvements
- Nice-to-have + Moderate/Heavy = Usually defer or reject
Status workflow:
Backlog→ Items not yet prioritized or lacking clear requirementsTodo→ Requirements defined, ready to pick up (next in queue)Doing→ Active work in progressDone→ Work completed and merged
Use issue dependencies instead of "Blocked" status:
- Set
blockedByrelationships using thegh-issue-dependenciesskill - Dependencies are more explicit and trackable than status alone
- Status should reflect work state, dependencies reflect constraints
Maintenance:
- Keep Status current as work progresses
- Set Value/Effort during triage and planning sessions
- Review
Backlogperiodically to prune or promote items toTodo - Move completed items to
Donewhen merged
Integration with workflows
Works well with:
gh-issue-dependenciesskill - Set Status=Blocked when dependencies existgit-issue-createagent - Add to project and set fields when creating issuesgit-issue-deliveragent - Update Status as work progresses- GitHub Actions - Automate field updates on events
Automation ideas:
- Auto-set Status=Doing when PR opens (work in progress)
- Auto-set Status=Done when PR merges
- Auto-set Value=Essential for security/critical labels
- Alert on Essential + Heavy items (require careful planning)
- Auto-promote Todo items to Doing when branch created