engsys 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +202 -0
- package/core/agents/aaron.md +152 -0
- package/core/agents/bert.md +115 -0
- package/core/agents/isabelle.md +136 -0
- package/core/agents/jody.md +150 -0
- package/core/agents/leith.md +111 -0
- package/core/agents/marcelo.md +282 -0
- package/core/agents/melvin.md +101 -0
- package/core/agents/nyx.md +152 -0
- package/core/agents/otto.md +168 -0
- package/core/agents/patricia.md +283 -0
- package/core/commands/design-audit-local.md +155 -0
- package/core/commands/design-audit.md +235 -0
- package/core/commands/design-critique.md +96 -0
- package/core/commands/file-issue.md +22 -0
- package/core/commands/generate-project.md +45 -0
- package/core/commands/implement-issue.md +37 -0
- package/core/commands/implement-project.md +40 -0
- package/core/commands/naturalize.md +61 -0
- package/core/commands/pre-push.md +29 -0
- package/core/commands/prep-review-collect.md +130 -0
- package/core/commands/prep-review-finalize.md +121 -0
- package/core/commands/prep-review-publish.md +113 -0
- package/core/commands/prep-review.md +65 -0
- package/core/commands/project-closeout.md +25 -0
- package/core/skills/agentic-eval/SKILL.md +195 -0
- package/core/skills/chrome-devtools/SKILL.md +97 -0
- package/core/skills/code-review/SKILL.md +26 -0
- package/core/skills/gh-cli/SKILL.md +2202 -0
- package/core/skills/git-commit/SKILL.md +124 -0
- package/core/skills/git-workflow-agents/SKILL.md +462 -0
- package/core/skills/git-workflow-agents/reference.md +220 -0
- package/core/skills/github-actions/SKILL.md +190 -0
- package/core/skills/github-issues/SKILL.md +154 -0
- package/core/skills/llm-structured-outputs/SKILL.md +323 -0
- package/core/skills/llm-structured-outputs/references/provider-details.md +392 -0
- package/core/skills/pre-push/SKILL.md +115 -0
- package/core/skills/refactor/SKILL.md +645 -0
- package/core/skills/web-design-reviewer/SKILL.md +371 -0
- package/core/skills/webapp-testing/SKILL.md +127 -0
- package/core/skills/webapp-testing/test-helper.js +56 -0
- package/core/templates/CLAUDE.md.tmpl +98 -0
- package/core/templates/adr-template.md +67 -0
- package/core/templates/gh-issue-templates/bug.md +39 -0
- package/core/templates/gh-issue-templates/content.md +42 -0
- package/core/templates/gh-issue-templates/enhancement.md +36 -0
- package/core/templates/gh-issue-templates/feature.md +39 -0
- package/core/templates/gh-issue-templates/infrastructure.md +41 -0
- package/core/templates/post-edit-reminders.sh.tmpl +19 -0
- package/core/templates/settings.json.tmpl +90 -0
- package/core/templates/settings.local.json.tmpl +3 -0
- package/core/workflows/agent-implementation-workflow.md +346 -0
- package/core/workflows/generate-project.md +258 -0
- package/core/workflows/implement-project-workflow.md +190 -0
- package/core/workflows/issue-tracking.md +89 -0
- package/core/workflows/project-closeout-ceremony.md +77 -0
- package/core/workflows/review-workflow.md +266 -0
- package/engsys.config.example.yaml +46 -0
- package/install +202 -0
- package/lessons-library/README.md +80 -0
- package/lessons-library/async-callbacks-verify-liveness.md +15 -0
- package/lessons-library/change-isnt-done-until-every-surface-updated.md +15 -0
- package/lessons-library/claim-then-act-for-irreversible-ops.md +16 -0
- package/lessons-library/co-commit-entangled-work.md +15 -0
- package/lessons-library/dependabot-triage-playbook.md +17 -0
- package/lessons-library/deploy-by-digest-and-verify-the-running-revision.md +15 -0
- package/lessons-library/enforce-your-guarantee-at-your-boundary.md +16 -0
- package/lessons-library/gate-changes-on-measurement-not-vibes.md +15 -0
- package/lessons-library/iac-first-no-console-changes.md +15 -0
- package/lessons-library/independent-objective-review-gate.md +15 -0
- package/lessons-library/keep-an-immutable-source-of-truth.md +15 -0
- package/lessons-library/long-agent-runs-checkpoint-not-poll.md +15 -0
- package/lessons-library/model-identity-with-stable-ids-and-provenance.md +15 -0
- package/lessons-library/operator-choices-are-first-class.md +15 -0
- package/lessons-library/prefer-tool-enforced-structured-output.md +15 -0
- package/lessons-library/prove-causation-before-acting.md +15 -0
- package/lessons-library/re-read-state-before-acting.md +14 -0
- package/lessons-library/read-layer-tolerates-unbackfilled-rows.md +15 -0
- package/lessons-library/shell-safety-pipefail-and-validate-before-teardown.md +14 -0
- package/lessons-library/shift-correctness-left-and-distrust-false-greens.md +15 -0
- package/lessons-library/stray-control-bytes-hide-changes.md +14 -0
- package/lessons-library/tests-can-assert-the-bug.md +15 -0
- package/lessons-library/verify-ground-truth-not-reports.md +15 -0
- package/lessons-library/worktrees-need-bootstrap-from-origin-main.md +15 -0
- package/lib/commands.js +356 -0
- package/lib/generate-team-avatars.mjs +251 -0
- package/lib/manifest.js +155 -0
- package/lib/render.js +135 -0
- package/lib/selftest.js +90 -0
- package/lib/util.js +89 -0
- package/lib/yaml.js +156 -0
- package/optional-agents/gary.md +86 -0
- package/optional-agents/jos.md +136 -0
- package/optional-agents/sandy.md +101 -0
- package/optional-agents/steve.md +161 -0
- package/package.json +43 -0
- package/stacks/cloud/aws/claude.fragment.md +17 -0
- package/stacks/cloud/aws/settings.fragment.json +39 -0
- package/stacks/cloud/aws/skills/aws-deployment-preflight/SKILL.md +165 -0
- package/stacks/cloud/aws/skills/cloud-architecture-aws/SKILL.md +265 -0
- package/stacks/cloud/azure/claude.fragment.md +17 -0
- package/stacks/cloud/azure/settings.fragment.json +45 -0
- package/stacks/cloud/azure/skills/azure-deployment-preflight/SKILL.md +175 -0
- package/stacks/cloud/azure/skills/cloud-architecture-azure/SKILL.md +211 -0
- package/stacks/cloud/cloudflare/claude.fragment.md +21 -0
- package/stacks/cloud/cloudflare/settings.fragment.json +31 -0
- package/stacks/cloud/cloudflare/skills/cloud-architecture-cloudflare/SKILL.md +294 -0
- package/stacks/cloud/cloudflare/skills/cloudflare-deployment-preflight/SKILL.md +175 -0
- package/stacks/cloud/gcp/claude.fragment.md +17 -0
- package/stacks/cloud/gcp/settings.fragment.json +40 -0
- package/stacks/cloud/gcp/skills/cloud-architecture-gcp/SKILL.md +208 -0
- package/stacks/cloud/gcp/skills/gcp-deployment-preflight/SKILL.md +137 -0
- package/stacks/db/mongo/skills/mongo-conventions/SKILL.md +96 -0
- package/stacks/db/prisma/claude.fragment.md +49 -0
- package/stacks/db/prisma/skills/docker-database-package-copy/SKILL.md +44 -0
- package/stacks/db/prisma/skills/prisma-conventions/SKILL.md +37 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/SKILL.md +184 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/references/benchmark-notes.md +47 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/references/official-links.md +53 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/SKILL.md +197 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/references/benchmark-notes.md +47 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/references/official-links.md +45 -0
- package/stacks/iac/bicep/claude.fragment.md +14 -0
- package/stacks/iac/bicep/settings.fragment.json +20 -0
- package/stacks/iac/bicep/skills/iac-bicep/SKILL.md +113 -0
- package/stacks/iac/cdk/claude.fragment.md +14 -0
- package/stacks/iac/cdk/settings.fragment.json +23 -0
- package/stacks/iac/cdk/skills/iac-cdk/SKILL.md +104 -0
- package/stacks/iac/terraform/claude.fragment.md +13 -0
- package/stacks/iac/terraform/settings.fragment.json +25 -0
- package/stacks/iac/terraform/skills/iac-terraform/SKILL.md +93 -0
- package/stacks/iac/terraform/skills/terraform-conventions/SKILL.md +87 -0
- package/stacks/lang/kotlin/skills/android-testing/SKILL.md +263 -0
- package/stacks/lang/kotlin/skills/jetpack-compose/SKILL.md +264 -0
- package/stacks/lang/kotlin/skills/kotlin-coroutines/SKILL.md +329 -0
- package/stacks/lang/python/skills/python-conventions/SKILL.md +61 -0
- package/stacks/lang/shell/skills/shell-scripting/SKILL.md +110 -0
- package/stacks/lang/swift/skills/swift-concurrency/SKILL.md +423 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/approachable-concurrency.md +80 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/concurrency-patterns.md +233 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/swiftui-concurrency.md +187 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/synchronization-primitives.md +341 -0
- package/stacks/lang/swift/skills/swift-testing/SKILL.md +497 -0
- package/stacks/lang/swift/skills/swift-testing/references/testing-advanced.md +106 -0
- package/stacks/lang/swift/skills/swift-testing/references/testing-patterns.md +504 -0
- package/stacks/lang/swift/skills/swiftdata/SKILL.md +334 -0
- package/stacks/lang/swift/skills/swiftdata/references/core-data-coexistence.md +504 -0
- package/stacks/lang/swift/skills/swiftdata/references/swiftdata-advanced.md +975 -0
- package/stacks/lang/swift/skills/swiftdata/references/swiftdata-queries.md +675 -0
- package/stacks/lang/swift/skills/swiftui-patterns/SKILL.md +371 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/architecture-patterns.md +486 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/deprecated-migration.md +1097 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/design-polish.md +780 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/platform-and-sharing.md +696 -0
- package/stacks/lang/typescript/skills/typescript-conventions/SKILL.md +91 -0
- package/stacks/platform/android/claude.fragment.md +40 -0
- package/stacks/platform/android/hooks/pre-push-gradle.sh +70 -0
- package/stacks/platform/android/settings.fragment.json +13 -0
- package/stacks/platform/android/skills/android-build-conventions/SKILL.md +247 -0
- package/stacks/platform/ios/claude.fragment.md +24 -0
- package/stacks/platform/ios/hooks/pre-push-xcodebuild.sh +82 -0
- package/stacks/platform/ios/settings.fragment.json +21 -0
- package/stacks/platform/ios/skills/xcodebuildmcp-simulator-logs/SKILL.md +76 -0
- package/stacks/platform/web/skills/frontend-testing/SKILL.md +246 -0
- package/stacks/platform/web/skills/react-conventions/SKILL.md +261 -0
- package/stacks/platform/web/skills/web-platform-conventions/SKILL.md +55 -0
- package/stacks/tooling/issue-tracker-github/claude.fragment.md +10 -0
- package/stacks/tooling/issue-tracker-github/settings.fragment.json +24 -0
- package/stacks/tooling/issue-tracker-github/skills/issue-tracker-github/SKILL.md +278 -0
- package/stacks/tooling/issue-tracker-linear/claude.fragment.md +17 -0
- package/stacks/tooling/issue-tracker-linear/settings.fragment.json +9 -0
- package/stacks/tooling/issue-tracker-linear/skills/issue-tracker-linear/SKILL.md +183 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Git Workflow for Agents - Reference
|
|
2
|
+
|
|
3
|
+
This is auxiliary, stack-agnostic reference material for the worktree workflow. The authoritative
|
|
4
|
+
guidance is [SKILL.md](SKILL.md). Commands here use placeholders like `<install-deps-command>`,
|
|
5
|
+
`<build-command>`, `<test-command>`, and `<project>` — substitute your project's actual tooling.
|
|
6
|
+
Examples are shown in bash; translate to your shell as needed.
|
|
7
|
+
|
|
8
|
+
## Helper Script Sketch
|
|
9
|
+
|
|
10
|
+
A `create-worktree` helper takes an issue number and slug, then:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Usage: create-worktree <issue-number> <slug>
|
|
14
|
+
ISSUE="$1"; SLUG="$2"
|
|
15
|
+
BRANCH="agent/${ISSUE}-${SLUG}"
|
|
16
|
+
WORKTREE="../worktrees/issue-${ISSUE}-${SLUG}"
|
|
17
|
+
|
|
18
|
+
cd <repo-root>
|
|
19
|
+
git fetch origin
|
|
20
|
+
git checkout main
|
|
21
|
+
git pull origin main
|
|
22
|
+
|
|
23
|
+
# Create worktree AND branch together
|
|
24
|
+
git worktree add "$WORKTREE" -b "$BRANCH"
|
|
25
|
+
|
|
26
|
+
cd "$WORKTREE"
|
|
27
|
+
[ -f ../../<project>/.env.local ] && cp ../../<project>/.env.local .env.local
|
|
28
|
+
<install-deps-command>
|
|
29
|
+
echo "Worktree ready at $WORKTREE on branch $BRANCH"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
A `cleanup-worktrees` helper lists worktrees, empties each directory (so removal does not fail with
|
|
33
|
+
"Directory not empty" — git won't delete non-git files like dependency dirs or build output), then
|
|
34
|
+
removes them and prunes stale references and merged `agent/` branches:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
cd <repo-root>
|
|
38
|
+
git worktree list
|
|
39
|
+
# For each non-primary worktree: empty its dir, then `git worktree remove <path> --force`
|
|
40
|
+
git worktree prune
|
|
41
|
+
git branch --merged main | grep 'agent/' | xargs -r git branch -d
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Single vs. Multi-Package Workflows
|
|
45
|
+
|
|
46
|
+
For a single package/module, install and build just that target. For a monorepo touching several
|
|
47
|
+
packages, install all workspaces and use the package manager's filter/scope mechanism to build only
|
|
48
|
+
the affected packages plus their dependents. The principle is the same regardless of language:
|
|
49
|
+
**build the changed package and everything that depends on it.**
|
|
50
|
+
|
|
51
|
+
## Database / Schema Migration Strategies
|
|
52
|
+
|
|
53
|
+
When a change includes a schema or data-layer migration, coordinate so parallel agents don't
|
|
54
|
+
corrupt a shared database.
|
|
55
|
+
|
|
56
|
+
- **Strategy 1 — Coordination (recommended for dev):** one agent creates and commits the migration;
|
|
57
|
+
others rebase on `origin/main` and apply pending migrations to their local DB before continuing.
|
|
58
|
+
- **Strategy 2 — Separate databases per worktree:** override the DB connection string in each
|
|
59
|
+
worktree's `.env.local`, create a uniquely-named database per worktree, and run migrations there.
|
|
60
|
+
- **Strategy 3 — Isolated dev database:** point each worktree at its own remote dev database.
|
|
61
|
+
|
|
62
|
+
After a migration lands, regenerate any generated client/codegen artifacts and rebuild dependent
|
|
63
|
+
packages.
|
|
64
|
+
|
|
65
|
+
## Infrastructure Validation
|
|
66
|
+
|
|
67
|
+
If the project uses infrastructure-as-code, validate locally before committing using the project's
|
|
68
|
+
IaC tool (Terraform `plan`/`validate`, Bicep `build` + deployment `what-if`/`validate`,
|
|
69
|
+
CloudFormation `validate-template`, Pulumi `preview`, etc.). Preview the diff against the target
|
|
70
|
+
environment before deploying. Never make changes through a cloud console that bypass the IaC.
|
|
71
|
+
|
|
72
|
+
## Troubleshooting
|
|
73
|
+
|
|
74
|
+
### Worktree creation fails
|
|
75
|
+
|
|
76
|
+
`fatal: '<branch>' is already checked out at '<path>'` — the branch is checked out elsewhere.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
git worktree list # find where it's checked out
|
|
80
|
+
git worktree remove <path> # remove if stale
|
|
81
|
+
# or pick a new branch name
|
|
82
|
+
git worktree add ../worktrees/issue-42-foo-v2 -b agent/42-foo-v2
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Worktree won't remove
|
|
86
|
+
|
|
87
|
+
`contains modified or untracked files` — commit/stash first, or force:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
git worktree remove --force <worktree-path>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`Directory not empty` — git does not delete non-git files (dependency dirs, build output). Empty the
|
|
94
|
+
directory first, then remove:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
rm -rf ../worktrees/issue-42-foo/*
|
|
98
|
+
git worktree remove ../worktrees/issue-42-foo
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Build fails after switching worktrees
|
|
102
|
+
|
|
103
|
+
Stale dependencies are the usual cause. Clean and reinstall:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
rm -rf <deps-dir> <lockfile>
|
|
107
|
+
<install-deps-command>
|
|
108
|
+
<build-command>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Tests fail with database errors
|
|
112
|
+
|
|
113
|
+
Point tests at a dedicated test database (separate connection string in `.env.local`/`.env.test`),
|
|
114
|
+
reset/seed it, and isolate the test DB per worktree if agents run in parallel.
|
|
115
|
+
|
|
116
|
+
### Merge conflicts during rebase
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
git fetch origin main
|
|
120
|
+
git rebase origin/main
|
|
121
|
+
# resolve conflicts, then:
|
|
122
|
+
git add <resolved-files>
|
|
123
|
+
git rebase --continue
|
|
124
|
+
# if it gets messy:
|
|
125
|
+
git rebase --abort
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
If the rebase stops on a commit already merged to main (expected for stacked branches):
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
git rebase --skip
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
After a successful rebase, force-push safely:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
git push --force-with-lease origin agent/<branch>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Disk-space pressure from many worktrees
|
|
141
|
+
|
|
142
|
+
Prefer a package manager that hard-links/dedupes dependencies, install only the workspaces you need,
|
|
143
|
+
and clean build artifacts and removed worktrees aggressively (`git worktree prune`).
|
|
144
|
+
|
|
145
|
+
## Advanced Workflows
|
|
146
|
+
|
|
147
|
+
### Cleaning up commit history
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
git rebase -i origin/main # squash/reword/drop commits
|
|
151
|
+
git push --force-with-lease # only if the branch isn't shared
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Cherry-picking / sharing work between worktrees
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# In source worktree: find the commit
|
|
158
|
+
git log --oneline
|
|
159
|
+
# In target worktree: apply it
|
|
160
|
+
git cherry-pick <commit-hash>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Sharing via committed-and-pushed commits (then `git fetch` + cherry-pick) is safer than copying
|
|
164
|
+
working-tree files.
|
|
165
|
+
|
|
166
|
+
### Switching issues mid-work
|
|
167
|
+
|
|
168
|
+
Commit WIP (`wip: save progress (#42)`), optionally push to preserve it, create/switch to the other
|
|
169
|
+
issue's worktree, and return later by `cd`-ing back.
|
|
170
|
+
|
|
171
|
+
## GitHub via gh CLI (preferred) and MCP (fallback)
|
|
172
|
+
|
|
173
|
+
Prefer `gh` CLI for issues, PRs, Actions, and project boards. Examples:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
gh issue create --repo <owner>/<repo> --title "..." --body-file tmp/issue-body.md --label "bug"
|
|
177
|
+
gh issue view 42 --repo <owner>/<repo>
|
|
178
|
+
gh pr create --base main --head agent/42-foo --title "fix(scope): ..." --body-file tmp/pr-body-42.md
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The `github` MCP server (configured in `.mcp.json`) is a fallback for when `gh` auth or network
|
|
182
|
+
fails. ProjectV2 (project boards) must always use `gh project` / `gh api graphql` — MCP does not
|
|
183
|
+
support them.
|
|
184
|
+
|
|
185
|
+
## Git Worktree Command Reference
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
git worktree list # list
|
|
189
|
+
git worktree list --porcelain # machine-readable
|
|
190
|
+
git worktree add <path> -b <branch> # new branch + worktree (preferred)
|
|
191
|
+
git worktree add <path> <branch> # existing branch (if not checked out elsewhere)
|
|
192
|
+
git worktree add <path> -b <branch> <sha> # from a specific commit
|
|
193
|
+
git worktree remove <path> # remove
|
|
194
|
+
git worktree remove --force <path> # ignore uncommitted changes
|
|
195
|
+
git worktree prune # drop stale references
|
|
196
|
+
git worktree prune --dry-run # preview
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
To "move" a worktree: note its branch, `git worktree remove` the old path, then `git worktree add`
|
|
200
|
+
at the new path.
|
|
201
|
+
|
|
202
|
+
## Diffing your branch against main
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
git diff main...HEAD # changes in your branch only (merge-base)
|
|
206
|
+
git diff main..HEAD # all differences between the two tips
|
|
207
|
+
git diff --name-only main...HEAD # file names only
|
|
208
|
+
git diff --stat main...HEAD # summary stats
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## FAQ
|
|
212
|
+
|
|
213
|
+
- **Multiple worktrees for one issue?** No — one issue, one worktree. Use commits to checkpoint and
|
|
214
|
+
share progress.
|
|
215
|
+
- **Committed in the main checkout by mistake?** Note the hash, `git reset --hard origin/main` in the
|
|
216
|
+
main checkout, then `git cherry-pick <hash>` in the worktree.
|
|
217
|
+
- **Run the same service in two worktrees at once?** Yes, but assign different ports (e.g. via a
|
|
218
|
+
`PORT` env var) to avoid collisions.
|
|
219
|
+
- **Worktrees for small fixes?** Only when isolation/parallelism justifies the setup overhead;
|
|
220
|
+
otherwise a plain branch in the main checkout is fine.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-actions
|
|
3
|
+
description: GitHub Actions workflow authoring guidance — the `${{ }}` expression function set, shell-injection and multi-line-output safety in `run:` steps, draft-gated CI triggers, and GraphQL rate-limit handling. Activate when editing `.github/workflows/*.yml`/`*.yaml`, authoring or reviewing GitHub Actions workflows, or debugging a CI gate that runs/skips unexpectedly.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GitHub Actions
|
|
7
|
+
|
|
8
|
+
Practical, hard-won guidance for authoring and reviewing GitHub Actions workflows.
|
|
9
|
+
GitHub is the assumed code host for every project here — PRs and CI live on GitHub — so
|
|
10
|
+
this skill is installed everywhere. It complements core `gh-cli` (which covers `gh run`,
|
|
11
|
+
`gh workflow`, `gh secret` from the command line); this skill is about the workflow YAML
|
|
12
|
+
itself.
|
|
13
|
+
|
|
14
|
+
Each lesson below is something that **looks right but is silently wrong**: it passes
|
|
15
|
+
review, ships, and then fails open (a gate never runs, a value truncates, an injection
|
|
16
|
+
lands). Apply the review checklist at the bottom to any workflow PR.
|
|
17
|
+
|
|
18
|
+
## 1. The `${{ }}` expression language has a tiny function set
|
|
19
|
+
|
|
20
|
+
GitHub Actions expressions are **not JavaScript**. The only built-in functions are:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
contains startsWith endsWith format join toJSON fromJSON hashFiles
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
There is **no** `toLower`, `toUpper`, `trim`, or `replace`. Typing one does not error —
|
|
27
|
+
the expression evaluates to an empty string **silently**, so a condition that was meant
|
|
28
|
+
to exclude something fails open and never excludes it.
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
# ❌ WRONG — toLower() does not exist; the whole expression is "" and the guard never fires
|
|
32
|
+
if: ${{ !contains(toLower(github.event.pull_request.title), 'release') }}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Workaround A — enumerate the case variants with the functions that do exist:
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
# ✅ Cover the common cases explicitly
|
|
39
|
+
if: |
|
|
40
|
+
!startsWith(github.event.pull_request.title, 'Release') &&
|
|
41
|
+
!startsWith(github.event.pull_request.title, 'release') &&
|
|
42
|
+
!startsWith(github.event.pull_request.title, 'RELEASE')
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Workaround B — do the string munging in a `run:` step (shell has real `tr`, `sed`, etc.)
|
|
46
|
+
and emit a normalized value as a step output, then branch on that:
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
- id: norm
|
|
50
|
+
env:
|
|
51
|
+
TITLE: ${{ github.event.pull_request.title }}
|
|
52
|
+
run: |
|
|
53
|
+
lower="$(printf '%s' "$TITLE" | tr '[:upper:]' '[:lower:]')"
|
|
54
|
+
echo "is_release=$(case "$lower" in release*) echo true;; *) echo false;; esac)" >> "$GITHUB_OUTPUT"
|
|
55
|
+
- if: steps.norm.outputs.is_release == 'false'
|
|
56
|
+
run: ...
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Reference: <https://docs.github.com/en/actions/learn-github-actions/expressions#functions>.
|
|
60
|
+
Any `toLower`/`toUpper`/`trim`/`replace` inside `${{ }}` is a bug — rewrite it.
|
|
61
|
+
|
|
62
|
+
## 2. `run:` step safety — outputs and injection
|
|
63
|
+
|
|
64
|
+
### Multi-line step outputs need a heredoc delimiter
|
|
65
|
+
|
|
66
|
+
Writing `echo "result=$value" >> "$GITHUB_OUTPUT"` captures only the **first line** when
|
|
67
|
+
`$value` is multi-line (e.g. a failed `gh api` JSON body, a `git log`/`git diff`
|
|
68
|
+
aggregation, anything piped through `jq`/`yq` without `-r .field`). Downstream steps then
|
|
69
|
+
branch on a truncated, present-but-stale string — silent state corruption.
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
# ❌ WRONG — truncates at the first newline
|
|
73
|
+
- id: convert
|
|
74
|
+
run: |
|
|
75
|
+
output="$(gh api graphql ... 2>&1)"
|
|
76
|
+
echo "result=$output" >> "$GITHUB_OUTPUT"
|
|
77
|
+
|
|
78
|
+
# ✅ CORRECT — heredoc delimiter; runner reads until the closing EOF
|
|
79
|
+
- id: convert
|
|
80
|
+
run: |
|
|
81
|
+
output="$(gh api graphql ... 2>&1)"
|
|
82
|
+
{
|
|
83
|
+
echo "result<<EOF"
|
|
84
|
+
echo "$output"
|
|
85
|
+
echo "EOF"
|
|
86
|
+
} >> "$GITHUB_OUTPUT"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The delimiter (`EOF`, or any unique string not present in the payload) tells the runner
|
|
90
|
+
to read to the matching closer instead of splitting on `\n`. When in doubt, use it — the
|
|
91
|
+
cost is two lines, the bug is invisible.
|
|
92
|
+
|
|
93
|
+
### Never inline-expand `${{ github.* }}` inside a `run:` body
|
|
94
|
+
|
|
95
|
+
`${{ ... }}` is **textually substituted before the shell parses the line**. If the value
|
|
96
|
+
contains shell metacharacters — quotes, backticks, `$(...)`, `;` — the shell executes
|
|
97
|
+
them. With attacker-influenced inputs (PR title, `head_ref`, branch name, issue body,
|
|
98
|
+
fork commit messages) this is direct command injection.
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
# ❌ WRONG — injection surface; substituted before the shell parses it
|
|
102
|
+
- run: |
|
|
103
|
+
gh api graphql -F id='${{ github.event.pull_request.node_id }}' -f query='...'
|
|
104
|
+
|
|
105
|
+
# ✅ CORRECT — pass via env:, dereference the (quoted) env var
|
|
106
|
+
- env:
|
|
107
|
+
PR_NODE_ID: ${{ github.event.pull_request.node_id }}
|
|
108
|
+
run: |
|
|
109
|
+
gh api graphql -F id="$PR_NODE_ID" -f query='...'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Rule of thumb: **`${{ ... }}` belongs in `with:`, `env:`, `if:`, and `name:` — not in
|
|
113
|
+
`run:` script bodies.** The bar is not "is this field safe today?" but "will the pattern
|
|
114
|
+
still be safe when someone copies it and substitutes the PR title?" Genuinely safe
|
|
115
|
+
exceptions: `${{ secrets.* }}` in an `env:` mapping, and `${{ runner.os }}` / `${{ matrix.* }}`
|
|
116
|
+
defined entirely by the workflow itself. For user-influenced data there are no exceptions.
|
|
117
|
+
|
|
118
|
+
(Optional but cheap: `pipx install zizmor && zizmor .github/workflows` flags the
|
|
119
|
+
`template-injection` category automatically.)
|
|
120
|
+
|
|
121
|
+
## 3. Draft-gated jobs need `ready_for_review` in the trigger
|
|
122
|
+
|
|
123
|
+
A job guarded by `if: github.event.pull_request.draft == false` only runs on events the
|
|
124
|
+
workflow is actually subscribed to. A `pull_request:` trigger with no `types:` key
|
|
125
|
+
defaults to `[opened, synchronize, reopened]` — which does **not** include
|
|
126
|
+
`ready_for_review`.
|
|
127
|
+
|
|
128
|
+
Consequence: you mark the PR Ready expecting the required gate to run, but no new run is
|
|
129
|
+
scheduled. The gated leg stays `SKIPPED` from the last draft run, and GitHub treats a
|
|
130
|
+
SKIPPED required check as satisfied — so the PR shows mergeable as a **hollow green**.
|
|
131
|
+
|
|
132
|
+
```yaml
|
|
133
|
+
# ❌ Marking Ready never schedules a run — ready_for_review isn't subscribed
|
|
134
|
+
on:
|
|
135
|
+
pull_request:
|
|
136
|
+
branches: [main]
|
|
137
|
+
|
|
138
|
+
# ✅ The draft→ready transition itself fires the workflow
|
|
139
|
+
on:
|
|
140
|
+
pull_request:
|
|
141
|
+
types: [opened, synchronize, reopened, ready_for_review]
|
|
142
|
+
branches: [main]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Add `synchronize` too (it's in the default set, but list it explicitly once you specify
|
|
146
|
+
`types:`, since specifying `types:` replaces the default entirely). Until the trigger is
|
|
147
|
+
fixed, the manual workaround is to force a `synchronize` event:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
git commit --allow-empty -m "chore: trigger CI after ready-for-review" && git push
|
|
151
|
+
gh pr checks <pr-number> --watch # confirm the gated leg shows COMPLETED/SUCCESS, not SKIPPED
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Before merging a draft-gated PR: confirm `mergeStateStatus == CLEAN` (not merely
|
|
155
|
+
`MERGEABLE`), the specific leg shows COMPLETED/SUCCESS, and that run was triggered **after**
|
|
156
|
+
the PR was marked Ready.
|
|
157
|
+
|
|
158
|
+
## 4. GraphQL / API rate limits — defer, don't block the run
|
|
159
|
+
|
|
160
|
+
`gh api graphql`, `gh project item-edit`, and `gh issue edit --add-assignee` consume the
|
|
161
|
+
**per-user** GraphQL budget (5,000/hr), shared across every tool and agent on that token.
|
|
162
|
+
A burst of parallel mutations drains it in minutes; the error is
|
|
163
|
+
`API rate limit already exceeded for user ID …`.
|
|
164
|
+
|
|
165
|
+
- **Don't block the whole run on it.** Capture the GraphQL-dependent work (assign issues,
|
|
166
|
+
flip board status) and continue with everything that doesn't need GraphQL. Most REST
|
|
167
|
+
calls (`gh issue view`, `gh pr create`, `gh api repos/...`) draw on the separate `core`
|
|
168
|
+
budget. Retry the deferred work after the `reset` timestamp passes (~15 min).
|
|
169
|
+
- **Mutate sequentially, not in parallel.** A tight `for` loop (one mutation per item)
|
|
170
|
+
is gentler than bursty parallel calls, which compound the problem.
|
|
171
|
+
- Peek before a long sequence of board mutations; below ~200 remaining, defer:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
gh api rate_limit --jq '.resources' # compare .graphql.remaining vs .core.remaining
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Review checklist (any workflow PR)
|
|
178
|
+
|
|
179
|
+
```text
|
|
180
|
+
[ ] No toLower/toUpper/trim/replace inside ${{ }} — only contains/startsWith/endsWith/
|
|
181
|
+
format/join/toJSON/fromJSON/hashFiles exist; munge strings in a run: step instead.
|
|
182
|
+
[ ] Every `>> $GITHUB_OUTPUT` for a possibly-multi-line value uses the heredoc
|
|
183
|
+
delimiter form (or the value is guaranteed single-line via `-r .field`/`head -n1`).
|
|
184
|
+
[ ] No ${{ github.* }} / ${{ steps.* }} / ${{ inputs.* }} inline-expanded inside a
|
|
185
|
+
run: body — pass via env: and dereference the quoted env var.
|
|
186
|
+
[ ] Any draft-gated required job: `ready_for_review` (and `synchronize`) is in the
|
|
187
|
+
pull_request: types: list, so marking Ready actually schedules the gate.
|
|
188
|
+
[ ] GraphQL-heavy steps tolerate a rate limit (defer, don't fail the run) and mutate
|
|
189
|
+
sequentially rather than in parallel.
|
|
190
|
+
```
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-issues
|
|
3
|
+
description: 'Create, update, and manage GitHub issues using MCP tools. Use this skill when users want to create bug reports, feature requests, or task issues, update existing issues, add labels/assignees/milestones, or manage issue workflows. Triggers on requests like "create an issue", "file a bug", "request a feature", "update issue X", or any GitHub issue management task.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GitHub Issues
|
|
7
|
+
|
|
8
|
+
Manage GitHub issues using `gh` CLI (preferred) with `user-github` MCP server as fallback.
|
|
9
|
+
|
|
10
|
+
**Important:** The GitHub MCP does **not** support GitHub Projects (ProjectV2). For project board operations (priorities, status, custom fields, waves), always use `gh project` or `gh api graphql`.
|
|
11
|
+
|
|
12
|
+
## Tool Priority
|
|
13
|
+
|
|
14
|
+
1. **`gh` CLI** (preferred) — full coverage, projects support, GraphQL access
|
|
15
|
+
2. **GitHub MCP** (fallback) — use when `gh` CLI has auth or connectivity issues
|
|
16
|
+
|
|
17
|
+
## Available MCP Tools (fallback only)
|
|
18
|
+
|
|
19
|
+
| Tool | Purpose |
|
|
20
|
+
| -------------------------------- | ---------------------- |
|
|
21
|
+
| `mcp__github__create_issue` | Create new issues |
|
|
22
|
+
| `mcp__github__update_issue` | Update existing issues |
|
|
23
|
+
| `mcp__github__get_issue` | Fetch issue details |
|
|
24
|
+
| `mcp__github__search_issues` | Search issues |
|
|
25
|
+
| `mcp__github__add_issue_comment` | Add comments |
|
|
26
|
+
| `mcp__github__list_issues` | List repository issues |
|
|
27
|
+
|
|
28
|
+
## Workflow
|
|
29
|
+
|
|
30
|
+
1. **Determine action**: Create, update, or query?
|
|
31
|
+
2. **Gather context**: Get repo info, existing labels, milestones if needed
|
|
32
|
+
3. **Structure content**: Use appropriate template from [references/templates.md](references/templates.md)
|
|
33
|
+
4. **Execute**: Use `gh` CLI first; fall back to MCP tools if CLI has issues
|
|
34
|
+
5. **Confirm**: Report the issue URL to user
|
|
35
|
+
|
|
36
|
+
## Creating Issues
|
|
37
|
+
|
|
38
|
+
### Using gh CLI (preferred)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Write body to tmp/ file first, then:
|
|
42
|
+
gh issue create \
|
|
43
|
+
--repo <owner>/<repo> \
|
|
44
|
+
--title "🐛 Bug: Description" \
|
|
45
|
+
--body-file tmp/issue-body-slug.md \
|
|
46
|
+
--label "bug,<component>"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Using MCP (fallback)
|
|
50
|
+
|
|
51
|
+
### Required Parameters
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
owner: repository owner (org or user)
|
|
55
|
+
repo: repository name
|
|
56
|
+
title: clear, actionable title
|
|
57
|
+
body: structured markdown content
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Optional Parameters
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
labels: ["bug", "enhancement", "documentation", ...]
|
|
64
|
+
assignees: ["username1", "username2"]
|
|
65
|
+
milestone: milestone number (integer)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Title Guidelines
|
|
69
|
+
|
|
70
|
+
- Start with type prefix when useful: `[Bug]`, `[Feature]`, `[Docs]`
|
|
71
|
+
- Be specific and actionable
|
|
72
|
+
- Keep under 72 characters
|
|
73
|
+
- Examples:
|
|
74
|
+
- `[Bug] Login fails with SSO enabled`
|
|
75
|
+
- `[Feature] Add dark mode support`
|
|
76
|
+
- `Add unit tests for auth module`
|
|
77
|
+
|
|
78
|
+
### Body Structure
|
|
79
|
+
|
|
80
|
+
Always use the templates in [references/templates.md](references/templates.md). Choose based on issue type:
|
|
81
|
+
|
|
82
|
+
| User Request | Template |
|
|
83
|
+
| ------------------------------- | --------------- |
|
|
84
|
+
| Bug, error, broken, not working | Bug Report |
|
|
85
|
+
| Feature, enhancement, add, new | Feature Request |
|
|
86
|
+
| Task, chore, refactor, update | Task |
|
|
87
|
+
|
|
88
|
+
## Updating Issues
|
|
89
|
+
|
|
90
|
+
Use `mcp__github__update_issue` with:
|
|
91
|
+
|
|
92
|
+
```text
|
|
93
|
+
owner, repo, issue_number (required)
|
|
94
|
+
title, body, state, labels, assignees, milestone (optional - only changed fields)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
State values: `open`, `closed`
|
|
98
|
+
|
|
99
|
+
## Examples
|
|
100
|
+
|
|
101
|
+
### Example 1: Bug Report
|
|
102
|
+
|
|
103
|
+
**User**: "Create a bug issue - the login page crashes when using SSO"
|
|
104
|
+
|
|
105
|
+
**Action**: Call `mcp__github__create_issue` with:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"owner": "github",
|
|
110
|
+
"repo": "awesome-copilot",
|
|
111
|
+
"title": "[Bug] Login page crashes when using SSO",
|
|
112
|
+
"body": "## Description\nThe login page crashes when users attempt to authenticate using SSO.\n\n## Steps to Reproduce\n1. Navigate to login page\n2. Click 'Sign in with SSO'\n3. Page crashes\n\n## Expected Behavior\nSSO authentication should complete and redirect to dashboard.\n\n## Actual Behavior\nPage becomes unresponsive and displays error.\n\n## Environment\n- Browser: [To be filled]\n- OS: [To be filled]\n\n## Additional Context\nReported by user.",
|
|
113
|
+
"labels": ["bug"]
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Example 2: Feature Request
|
|
118
|
+
|
|
119
|
+
**User**: "Create a feature request for dark mode with high priority"
|
|
120
|
+
|
|
121
|
+
**Action**: Call `mcp__github__create_issue` with:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"owner": "github",
|
|
126
|
+
"repo": "awesome-copilot",
|
|
127
|
+
"title": "[Feature] Add dark mode support",
|
|
128
|
+
"body": "## Summary\nAdd dark mode theme option for improved user experience and accessibility.\n\n## Motivation\n- Reduces eye strain in low-light environments\n- Increasingly expected by users\n- Improves accessibility\n\n## Proposed Solution\nImplement theme toggle with system preference detection.\n\n## Acceptance Criteria\n- [ ] Toggle switch in settings\n- [ ] Persists user preference\n- [ ] Respects system preference by default\n- [ ] All UI components support both themes\n\n## Alternatives Considered\nNone specified.\n\n## Additional Context\nHigh priority request.",
|
|
129
|
+
"labels": ["enhancement", "high-priority"]
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Common Labels
|
|
134
|
+
|
|
135
|
+
Use these standard labels when applicable:
|
|
136
|
+
|
|
137
|
+
| Label | Use For |
|
|
138
|
+
| ------------------ | ----------------------------- |
|
|
139
|
+
| `bug` | Something isn't working |
|
|
140
|
+
| `enhancement` | New feature or improvement |
|
|
141
|
+
| `documentation` | Documentation updates |
|
|
142
|
+
| `good first issue` | Good for newcomers |
|
|
143
|
+
| `help wanted` | Extra attention needed |
|
|
144
|
+
| `question` | Further information requested |
|
|
145
|
+
| `wontfix` | Will not be addressed |
|
|
146
|
+
| `duplicate` | Already exists |
|
|
147
|
+
| `high-priority` | Urgent issues |
|
|
148
|
+
|
|
149
|
+
## Tips
|
|
150
|
+
|
|
151
|
+
- Always confirm the repository context before creating issues
|
|
152
|
+
- Ask for missing critical information rather than guessing
|
|
153
|
+
- Link related issues when known: `Related to #123`
|
|
154
|
+
- For updates, fetch current issue first to preserve unchanged fields
|