GitHub Projects¶
Infrastructure work for scandora.net is tracked in GitHub Projects.
Project board: https://github.com/users/scandora/projects/1
Repository: https://github.com/scandora/scandora.net
Swim Lanes¶
Work items flow through five swim lanes:
| Lane | Meaning |
|---|---|
| Backlog | Idea captured, not yet actionable (may need scoping, labeling, or a body) |
| Ready | Actionable, no blockers, has labels + description |
| In Progress | Branch created, active work underway |
| In Review | PR open, awaiting merge |
| Done | Merged and closed |
Issue Hygiene Requirements¶
Every issue must have before it moves to Ready:
- At least one label
- A body with enough context to pick up and work (50+ characters)
- A Priority set on the project board (P0–P4)
The /start-issue skill enforces this — it auto-infers and applies labels when missing (using GitHub MCP),
warns on empty bodies, and only hard-stops if it cannot confidently infer labels from the issue content.
Labels¶
| Label | Use |
|---|---|
infrastructure |
Gateway, network, hardware work |
automation |
IaC, Ansible, Terraform, CI/CD |
documentation |
Docs improvements and architecture decisions |
bug |
Things that are broken |
enhancement |
Improvements to existing functionality |
cloud |
AWS, GCP cloud infrastructure |
monitoring |
Prometheus, Grafana, alerting |
Priority¶
Set on the project board (not as a GitHub label):
| Priority | Use |
|---|---|
| P0 | Critical — broken right now |
| P1 | High — significant impact, do soon |
| P2 | Medium — important, planned work |
| P3 | Normal — standard backlog |
| P4 | Low — nice to have |
GitHub Flow (Enforced)¶
All changes go through a branch — no exceptions, including skill files, hooks, and docs.
1. /start-issue <N> → creates branch, moves issue to In Progress
2. plan + implement → write plan, then /publish-plan to persist it on the issue's
"Proposed approach" section before starting implementation
3. commits on branch
4. /review → walks the diff, runs preflight checks, stops for agreement
no push, no PR — just inspection and discussion
5. /ready → pushes branch, creates PR with "Closes #N", posts verification comment
GitHub automation moves issue to In Review automatically
6. merge PR via GitHub UI
GitHub automation moves issue to Done automatically
7. /post-merge → verify board → Done (worktree: safe; classic: pulls main)
worktree path: does NOT remove worktree or delete branch here
classic path: also deletes local branch
check issue state: Auto-close workflow closes it automatically
when Closes #N is present — no manual action needed in normal path
worktree path ends with: "Run /restart to close and remove worktree"
8. /restart → end-of-session: audit state from git/gh (never memory), clean
stale branches, trim MEMORY.md, rewrite HANDOFF from live data,
bounded docs audit, final clean-state report
Phase 5 (worktree only): git worktree remove + branch delete
as final step (remove worktree FIRST, then branch) — CWD gone, user closes session
Closes #N is the automation trigger. Every PR body must include it. Without it,
the Pull request linked to issue, Pull request merged, and Auto-close issue workflows
don't fire — board moves and issue closure must be done manually. With it, the issue is
closed automatically when the PR merges; no manual close is needed or expected.
Enforcement:
- Pre-push hook (
.githooks/pre-push) blocksgit push origin main /start-issuehard-stops if issue has no labels, warns if body is empty/reviewis the agreement gate — run it before/ready, not after/readyenforcesCloses #Nas mandatory, not advisory/readyruns three preflight checks before creating the PR (see below)- GitHub auto-deletes branches on merge (makes post-merge pushes fail loudly)
GitHub Projects Automation Workflows¶
Seven workflows are configured and enabled on this project (Project Settings → Workflows):
| Workflow | Trigger | Action |
|---|---|---|
Auto-add to project |
Issue or PR created in repo | Adds item to board at Backlog |
Auto-add sub-issues to project |
Sub-issue created | Adds sub-issue to board |
Item added to project |
Item added manually | Sets initial status |
Pull request linked to issue |
PR opened with Closes #N |
Moves issue → In Review |
Pull request merged |
PR merged | Moves linked issue → Done |
Auto-close issue |
PR merged | Closes the linked issue |
Item closed |
Issue closed directly | Moves item → Done |
Gap — no built-in workflow for PR closed without merge: GitHub Projects does not offer a "Pull request closed without merge" trigger. If a PR is abandoned (closed without merging), move the board item back to In Progress using the wrapper script:
/review and /ready Preflight Checks¶
The /review skill is the agreement checkpoint — it walks the diff interactively,
runs all four gates below, and stops without creating a PR. Run it when you think work
is done but before committing to a PR.
The /ready skill enforces the same gates before creating a PR.
PREFLIGHT — is the branch complete?
- All changes committed,
git statusclean - No follow-on fixes anticipated
- Once
gh pr createis called the branch is final — commits to a merged branch go nowhere
SCOPE CHECK — one PR = one concern
- Diff addresses exactly one issue/question
- Unrelated bug fixes in pre-existing code must be extracted to their own branch first, then rebased in
- Bug fixes in new code you're adding are fine to include
DRIFT CHECK — is main ahead of this branch?
If main has commits touching your changed files, rebase before creating the PR:
Rebasing before PR creation is clean. Rebasing after a conflict is reported costs more time and risks mixing concerns during resolution.
VALIDATION GATE — evidence that the change was actually tested, not just planned.
One of the following is required before /review can produce its summary:
- Evidence — actual command output run this session demonstrating the changed behavior works. "ShellCheck passed" is syntax validation only and does not count as behavioral evidence.
- Explicit deferral — if the change targets an exact failure condition that cannot be reproduced pre-merge, state this explicitly with a reason and the exact post-merge test command.
If neither is present, /review stops and prompts for validation before continuing.
Minimum validation by change type:
| Change type | Minimum pre-merge validation |
|---|---|
| Shell script (new function/path) | Source the function, run it, show output |
| SSH/key handling | ssh-keygen -l -f <key_file> — prove key extracted correctly |
| Ansible playbook/role | run-*.sh --check --tags <tag> on any reachable host |
| Config/template | Show rendered output; assert expected values present |
| Docs/comments only | No runtime validation required — state this explicitly |
| Workflow/skill files | Invoke the modified skill to verify it loads |
Documentation Sync Rule¶
Docs and code ship together in the same PR.
When a PR touches workflow files, the corresponding documentation must be updated in the same commit:
| If you change... | Also update... |
|---|---|
.claude/commands/ready.md, start-issue.md, review.md, or post-merge.md |
docs/operations/github-projects.md |
.githooks/pre-push |
docs/operations/git-hooks.md |
CLAUDE.md (workflow sections) |
Relevant docs/operations/ page |
The /review skill Step 4 and /ready skill Step 2 both prompt explicitly for this check.
Skill invocation check (enforced in /review Step 4, part of doc-sync) — if any .claude/commands/*.md skill was
added or modified in the diff, invoke it before proceeding to /ready. Skill ! prefix commands must
be single operations: no | pipes, no && chains. A skill that fails to load is broken regardless of
how clean the diff looks in code review. Reading the diff is not a substitute for running the skill.
Board Status Updates¶
Use scripts/github/set-project-status.sh to move issues between columns:
Status values (case-insensitive): Backlog | Ready | "In Progress" | "In Review" | Done
# Examples
scripts/github/set-project-status.sh 75 "In Progress"
scripts/github/set-project-status.sh 37 "In Review"
scripts/github/set-project-status.sh 62 Done
The script retrieves the GitHub PAT from 1Password automatically (requires desktop app unlocked). It hard-codes the stable project/field node IDs and looks up the item node ID at runtime. If the issue is not yet on the board, the script automatically adds it before setting the status — no manual board-add step required.
When to use this manually:
/start-issuecalls it automatically (moves to In Progress)/post-mergecalls it whenCloses #Nwas missing from the PR body (moves to Done)- PR abandoned without merge: move back to In Progress manually
Using the GitHub CLI¶
Note:
ghon luna is aliased toop plugin run -- ghwhich requires an interactive TTY. In Claude Code sessions, use the PAT directly:GH_PAT=$(op item get "github_pat_mcp_claude" --vault scandora-automation --fields credential --reveal 2>/dev/null) GITHUB_TOKEN="$GH_PAT" /opt/homebrew/bin/gh issue list --repo scandora/scandora.netFor raw Projects v2 GraphQL (advanced use — prefer the wrapper script for board moves):
# Create an issue
gh issue create --title "Brief title" --label "infrastructure" --body "Details..."
# List open issues
gh issue list --repo scandora/scandora.net --state open
# View an issue
gh issue view 57 --repo scandora/scandora.net
GitHub MCP Integration¶
Claude Code interacts with GitHub Issues and the project board via the GitHub MCP server (user-level, available in all sessions).
See: MCP Authentication for setup details.
Commit and Branch Conventions¶
Commit messages:
Branch names:
Note:
/start-issueuses theEnterWorktreetool, which prefixes the actual git branch withworktree-(e.g.feat/60-zerotier-bootstrap→ git branchworktree-feat/60-zerotier-bootstrap). The worktree name you provide toEnterWorktreefollows the conventions above; theworktree-prefix is added automatically and is visible ingit branch --show-currentinside the worktree.