Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .cursor/rules/work-tracking.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ Before `git commit`, `git push`, **ship it**, or **check in** when the user did

**After linking:** set project Status to **In Progress** when starting substantial work; **Done** only when the user says ship/merge or work is complete on `main` (issue closed).

**Board backlog:** run `.\scripts\github\Sync-ProjectBoard.ps1` when retrospective or planned cards are missing; see [docs/ops/github-workflow.md](../../docs/ops/github-workflow.md).

**Hooks (mandatory locally):** run `.\scripts\install-githooks.ps1` once per clone — `commit-msg` rejects commits without `#<issue>` (or `feature/<id>-...` branch). PRs must reference an issue (CI workflow).

**Exception:** user explicitly says “no issue”, “chore only”, or “docs/rules only, skip issue”.

## Agent automation (`gh`)
Expand Down
27 changes: 27 additions & 0 deletions .githooks/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/sh
# Require a GitHub issue reference in every commit (enforces work-tracking.mdc).
# Install: .\scripts\install-githooks.ps1

MSG_FILE="$1"
MSG=$(cat "$MSG_FILE")

# Allow merge/revert/fixup commits
case "$MSG" in
Merge*|Revert*|fixup!*|squash!*) exit 0 ;;
esac

# Commit message contains #N
if printf '%s' "$MSG" | grep -qE '#[0-9]+'; then
exit 0
fi

# Branch feature/N-... without message ref (branch still ties to issue)
BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || true)
case "$BRANCH" in
feature/[0-9]*-*) exit 0 ;;
esac

echo "commit-msg hook: commit must reference a GitHub issue (#N) in the message," >&2
echo "or use branch feature/<id>-short-name." >&2
echo "Create an issue, add it to project board #3, then commit with: #<id>: summary" >&2
exit 1
32 changes: 32 additions & 0 deletions .github/workflows/pr-issue-link.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: PR issue link

on:
pull_request:
types: [opened, edited, synchronize, reopened]

permissions:
pull-requests: read

jobs:
require-issue:
runs-on: ubuntu-latest
steps:
- name: Check PR links a GitHub issue
env:
PR_BODY: ${{ github.event.pull_request.body }}
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
body="$PR_BODY"
title="$PR_TITLE"
combined="${title}
${body}"
if echo "$combined" | grep -qiE '(closes|fixes|resolves)\s+#[0-9]+'; then
echo "PR links an issue."
exit 0
fi
if echo "$combined" | grep -qE '#[0-9]+'; then
echo "PR references an issue number."
exit 0
fi
echo "::error::Pull request must reference a GitHub issue (Closes #N or #N in title/body)."
exit 1
36 changes: 36 additions & 0 deletions docs/ops/github-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,42 @@ Full ship: commit → push → PR → squash merge → issue closed → project

Load `.cursor/skills/feature-ship/SKILL.md` when the user says **ship** or **ship it**.

## Board sync (backlog)

The board must list **all shipped work (Done)** and **planned work (Todo)**. Run after creating retrospective issues or when the board drifts:

```powershell
.\scripts\github\Sync-ProjectBoard.ps1
```

Dry run: `.\scripts\github\Sync-ProjectBoard.ps1 -WhatIf`

The script is idempotent (skips issues whose titles already exist) and ensures closed issues **#2**, **#4**, **#6**–**#8**, **#10** are on project #3 with Status **Done**.

### Planned work (Todo on board)

| Theme | Issue title (created by sync script if missing) |
|-------|--------------------------------------------------|
| Tests | Run tests on file change (`OnFileChange` mode) |
| Tray UX | Open log viewer from tray context menu |
| Tray UX | WPF tray context menu (Phase 2, if #8 insufficient) |
| Optional module | Wire Azure DevOps polling module |
| Diagnostics | Verdict feedback loop for adaptive debounce |

Update this table when adding new planned issues.

## Enforce issue on every commit

**Local (required for agents and developers):**

```powershell
.\scripts\install-githooks.ps1
```

The `commit-msg` hook rejects commits whose message lacks `#<issue>` unless the branch is `feature/<id>-...` (merge/revert commits are exempt).

**CI:** [`.github/workflows/pr-issue-link.yml`](../../.github/workflows/pr-issue-link.yml) fails PRs that do not reference an issue (`Closes #N` or `#N` in title/body).

## Record of intent

Chat and Cursor plans are not the system of record. The **project board (#3)**, **Issues**, **PR descriptions**, and **`docs/`** are.
1 change: 1 addition & 0 deletions scripts/github/Create-UxPlanIssues.ps1
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# DEPRECATED — use Sync-ProjectBoard.ps1 (creates UX plan items as Done + planned Todo).
# Creates UX plan GitHub issues and adds them to BuildMonitor project #3.
# Run: .\scripts\github\Create-UxPlanIssues.ps1

Expand Down
Loading