Query and manage the ExopenGitHub Product backlog on GitHub Projects v2
All operations target this project unless explicitly overridden:
PVT_kwDOBFiKmc05Iwuser.email = [email protected]Always use [email protected] for any GitHub operation (commits, issues, etc.). When "assign to me" is requested, use username androidand.
Always use this project when creating, querying, or updating backlog items.
gh issue create --repo ExopenGitHub/<repo>. Draft issues lack a repo tag and break board filtering.gh CLI over MCP tools for creating issues. The gh issue create command is simpler, more reliable, and automatically handles authentication. Use MCP tools for project-specific operations (adding to board, setting fields).--assignee androidand. Otherwise ask who to assign.feat/{issueNumber}-{slug}. See Step 6.This is the exact sequence to follow. Do not skip steps or reorder.
Analyze the prompt and match against the repo table below. If unclear, ask.
gh issue creategh issue create \
--repo ExopenGitHub/<repo> \
--title "<title>" \
--body "<markdown body>" \
--assignee androidand
Use the issue body template below for consistent formatting.
gh api graphql -f query='
query {
repository(owner: "ExopenGitHub", name: "<repo>") {
issue(number: <NUMBER>) { id }
}
}'
gh api graphql -f query='
mutation {
addProjectV2ItemById(input: {
projectId: "PVT_kwDOBFiKmc05Iw"
contentId: "<ISSUE_NODE_ID>"
}) { item { id } }
}'
Use the item ID from step 4 to set both fields in a single mutation:
gh api graphql -f query='
mutation {
status: updateProjectV2ItemFieldValue(input: {
projectId: "PVT_kwDOBFiKmc05Iw"
itemId: "<ITEM_ID>"
fieldId: "PVTSSF_lADOBFiKmc05I84AAZvX"
value: { singleSelectOptionId: "<STATUS_OPTION_ID>" }
}) { projectV2Item { id } }
initiative: updateProjectV2ItemFieldValue(input: {
projectId: "PVT_kwDOBFiKmc05Iw"
itemId: "<ITEM_ID>"
fieldId: "PVTSSF_lADOBFiKmc05I84NNwl6"
value: { singleSelectOptionId: "<INITIATIVE_OPTION_ID>" }
}) { projectV2Item { id } }
}'
After adding the issue to the board, create a feature branch in the local repo and push it. GitHub automatically links branches containing the issue number to the issue.
Branch naming convention: feat/{issueNumber}-{slug}
The slug is a short kebab-case summary derived from the issue title (max 5 words, lowercase, hyphens).
Examples:
feat/3200-er-modeling-e-conomicfeat/3201-fix-fortnox-token-refreshBefore creating a branch, always check if one already exists for this issue (locally or on the remote). A branch may exist if the issue was previously worked on, or if someone already started on it.
REPO_DIR="$WORKSPACE_ROOT/<local_folder>"
cd "$REPO_DIR"
git fetch origin
# Check remote branches for the issue number
EXISTING=$(git branch -r --list "*/<ISSUE_NUMBER>*" | head -1)
Also check by topic/name similarity -- sometimes branches exist for the same work but without the issue number:
git branch -r --list "*e-conomic*" --list "*er-modeling*" | head -5
If a likely match is found, warn the user and ask before proceeding.
Use gh issue develop to create branches. This command both creates the branch AND links it to the issue under the "Development" section on GitHub.
If no existing branch:
gh issue develop <ISSUE_NUMBER> \
--repo ExopenGitHub/<repo> \
--name "feat/<ISSUE_NUMBER>-<slug>" \
--base <default_branch>
Then check it out locally:
cd "$REPO_DIR"
git fetch origin
git checkout feat/<ISSUE_NUMBER>-<slug>
If an existing branch was found:
gh issue develop cannot link an existing branch. The workaround is:
gh issue develop to create and link it (creates from base)# Save current SHA
SHA=$(gh api repos/ExopenGitHub/<repo>/git/ref/heads/<branch> --jq '.object.sha')
# Delete remote branch
gh api -X DELETE repos/ExopenGitHub/<repo>/git/refs/heads/<branch>
# Create and link
gh issue develop <ISSUE_NUMBER> \
--repo ExopenGitHub/<repo> \
--name "<branch>" \
--base <default_branch>
# Restore commits
git push --force origin "$SHA:refs/heads/<branch>"
Always verify the branch appears in the issue's Development section:
gh issue develop --list <ISSUE_NUMBER> --repo ExopenGitHub/<repo>
Skip branch creation when:
Print a summary with:
Use this markdown structure for all issue bodies. Adjust sections to fit the task — remove sections that don't apply, but keep the structure consistent.
## Description
<1-3 sentences describing what needs to be done and why>
## Context
- <Relevant background, links to related issues, or prior work>
- <File paths, modules, or areas of the codebase affected>
## Acceptance criteria
- [ ] <Concrete, verifiable outcome>
- [ ] <Another outcome>
Keep it concise. Don't pad with boilerplate. If the user provides a short prompt, write a short description — don't inflate it.
PVTSSF_lADOBFiKmc05I84AAZvX98236657 = Ready for developmentee832dd0 = In progressdce8b7f5 = DonePVTSSF_lADOBFiKmc05I84NNwl66d1109db = V7 - Phase 130e9d796 = V7 - Phase 2c8e0a052 = V7 - Phase 3fc239093 = V7 - Phase 47638587b = V7 - Phase 59ce3281f = Kill the ETL7e3c6a34 = Complete Payloadf7408bc5 = Integrationsbdea0d09 = IC Tech3a22debe = Cloud Platform Modules4ac5048b = Cloud Platformf1bd264e = Customer Data Enrichment6833f7d7 = Technical UX633539ab = SecurityPVTF_lADOBFiKmc05I84AAZvVPVTF_lADOBFiKmc05I84AAZvWPVTF_lADOBFiKmc05I84AAZvYPVTF_lADOBFiKmc05I84AAZvZPVTF_lADOBFiKmc05I84NMOlUPVTF_lADOBFiKmc05I84NMOnOEvery task MUST be linked to a repository. Analyze the prompt for keywords, feature names, file paths, or technology references and match against the table below. If ambiguous, ask the user.
The Workspace root is the parent directory of all repos (typically ~/exopen). The WORKSPACE_ROOT env var is set by backlog.sh. The Local path column gives the absolute path to each repo as $WORKSPACE_ROOT/<folder>.
| Local folder | GitHub repo | Default branch | Keywords / signals |
|---|---|---|---|
| FusionHub | ExopenGitHub/FusionHub | main | integrations, sync, data pipeline, source systems, ER modeling, events, service bus, fortnox, visma, e-conomic, netvisor, tripletex, xero, poweroffice, prisma, sync jobs |
| eldvakt | ExopenGitHub/eldvakt | main | AI chat, Teams notification, Fastify, chat backend, access control |
| portal | ExopenGitHub/portal | main | frontend, React, Vite, UI, data-sources page, company domains, portal |
| Pumpstation | ExopenGitHub/Pumpstation | master | user management, company management, C#, .NET, email sending, admin emails |
| nexus | ExopenGitHub/nexus | master | infra, internal tooling, deployment, CI/CD, finance mart |
| eox7 | ExopenGitHub/eox7 | main | report app, v7, reports, selections, Excel |
| excel-addin | ExopenGitHub/excel-addin | main | Excel add-in, v6, spreadsheet |
| ExoKit | ExopenGitHub/ExoKit | main | shared libraries, kit, SDK |
| consolidation | ExopenGitHub/consolidation | main | consolidation, group reporting |
| planning-api | ExopenGitHub/planning-api | main | planning, budgeting, forecasting |
| pegasus | ExopenGitHub/pegasus | main | pegasus |
| NodeTools | ExopenGitHub/NodeTools | main | node tools, utilities |
| metaverse | ExopenGitHub/metaverse | main | metaverse, wow, way of working |
| mail-templates | ExopenGitHub/mail-templates | main | email templates, mail templates |
| it | ExopenGitHub/it | main | IT operations, internal IT |
gh project item-list 6 --owner ExopenGitHub --limit 50 --format json
gh api graphql -f query='
query {
organization(login: "ExopenGitHub") {
projectV2(number: 6) {
items(first: 50) {
nodes {
id
content {
... on Issue { title number repository { name } url }
... on DraftIssue { title }
}
fieldValues(first: 10) {
nodes {
... on ProjectV2ItemFieldSingleSelectValue {
name
field { ... on ProjectV2SingleSelectField { name } }
}
... on ProjectV2ItemFieldUserValue {
users(first: 5) { nodes { login } }
}
}
}
}
}
}
}
}'
When creating multiple issues, run the gh issue create commands in parallel, then batch the GraphQL mutations (add to project + set fields) into a single call using aliases:
gh api graphql -f query='
mutation {
add1: addProjectV2ItemById(input: { projectId: "PVT_kwDOBFiKmc05Iw", contentId: "<ID1>" }) { item { id } }
add2: addProjectV2ItemById(input: { projectId: "PVT_kwDOBFiKmc05Iw", contentId: "<ID2>" }) { item { id } }
}'
Then set fields for all items in another batched mutation.
gh project field-list 6 --owner ExopenGitHubproject scope with gh auth status