@coralai/sps-cli 0.41.2 → 0.43.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.
Files changed (168) hide show
  1. package/README.md +34 -3
  2. package/dist/commands/cardAdd.d.ts +1 -1
  3. package/dist/commands/cardAdd.d.ts.map +1 -1
  4. package/dist/commands/cardAdd.js +16 -6
  5. package/dist/commands/cardAdd.js.map +1 -1
  6. package/dist/commands/cardDashboard.js +1 -1
  7. package/dist/commands/cardDashboard.js.map +1 -1
  8. package/dist/commands/doctor.d.ts +9 -0
  9. package/dist/commands/doctor.d.ts.map +1 -1
  10. package/dist/commands/doctor.js +3 -314
  11. package/dist/commands/doctor.js.map +1 -1
  12. package/dist/commands/hookCommand.d.ts.map +1 -1
  13. package/dist/commands/hookCommand.js +6 -7
  14. package/dist/commands/hookCommand.js.map +1 -1
  15. package/dist/commands/pmCommand.js +1 -1
  16. package/dist/commands/pmCommand.js.map +1 -1
  17. package/dist/commands/projectInit.d.ts.map +1 -1
  18. package/dist/commands/projectInit.js +60 -37
  19. package/dist/commands/projectInit.js.map +1 -1
  20. package/dist/commands/setup.d.ts.map +1 -1
  21. package/dist/commands/setup.js +3 -30
  22. package/dist/commands/setup.js.map +1 -1
  23. package/dist/commands/skillCommand.d.ts +2 -0
  24. package/dist/commands/skillCommand.d.ts.map +1 -0
  25. package/dist/commands/skillCommand.js +235 -0
  26. package/dist/commands/skillCommand.js.map +1 -0
  27. package/dist/commands/tick.js +1 -1
  28. package/dist/commands/tick.js.map +1 -1
  29. package/dist/core/checklist.d.ts +22 -0
  30. package/dist/core/checklist.d.ts.map +1 -0
  31. package/dist/core/checklist.js +38 -0
  32. package/dist/core/checklist.js.map +1 -0
  33. package/dist/core/checklist.test.d.ts +2 -0
  34. package/dist/core/checklist.test.d.ts.map +1 -0
  35. package/dist/core/checklist.test.js +74 -0
  36. package/dist/core/checklist.test.js.map +1 -0
  37. package/dist/core/config.d.ts +1 -1
  38. package/dist/core/config.d.ts.map +1 -1
  39. package/dist/core/config.js +1 -1
  40. package/dist/core/config.js.map +1 -1
  41. package/dist/core/config.test.js +7 -4
  42. package/dist/core/config.test.js.map +1 -1
  43. package/dist/core/context.d.ts +1 -1
  44. package/dist/core/context.d.ts.map +1 -1
  45. package/dist/core/skillStore.d.ts +46 -0
  46. package/dist/core/skillStore.d.ts.map +1 -0
  47. package/dist/core/skillStore.js +197 -0
  48. package/dist/core/skillStore.js.map +1 -0
  49. package/dist/core/skillStore.test.d.ts +2 -0
  50. package/dist/core/skillStore.test.d.ts.map +1 -0
  51. package/dist/core/skillStore.test.js +190 -0
  52. package/dist/core/skillStore.test.js.map +1 -0
  53. package/dist/engines/EventHandler.test.js +3 -3
  54. package/dist/engines/EventHandler.test.js.map +1 -1
  55. package/dist/engines/MonitorEngine.js +2 -2
  56. package/dist/engines/MonitorEngine.js.map +1 -1
  57. package/dist/engines/SchedulerEngine.js +1 -1
  58. package/dist/engines/SchedulerEngine.js.map +1 -1
  59. package/dist/engines/StageEngine.js +3 -3
  60. package/dist/engines/StageEngine.js.map +1 -1
  61. package/dist/engines/engine-pipeline-adapter.test.js +2 -2
  62. package/dist/engines/engine-pipeline-adapter.test.js.map +1 -1
  63. package/dist/interfaces/TaskBackend.d.ts +3 -1
  64. package/dist/interfaces/TaskBackend.d.ts.map +1 -1
  65. package/dist/main.js +19 -17
  66. package/dist/main.js.map +1 -1
  67. package/dist/models/types.d.ts +16 -1
  68. package/dist/models/types.d.ts.map +1 -1
  69. package/dist/providers/MarkdownTaskBackend.d.ts +2 -1
  70. package/dist/providers/MarkdownTaskBackend.d.ts.map +1 -1
  71. package/dist/providers/MarkdownTaskBackend.js +28 -5
  72. package/dist/providers/MarkdownTaskBackend.js.map +1 -1
  73. package/dist/providers/registry.d.ts.map +1 -1
  74. package/dist/providers/registry.js +5 -7
  75. package/dist/providers/registry.js.map +1 -1
  76. package/package.json +1 -1
  77. package/project-template/.claude/hooks/start.sh +44 -0
  78. package/project-template/.claude/settings.json +1 -1
  79. package/skills/architecture-decision-records/SKILL.md +207 -0
  80. package/skills/backend/SKILL.md +62 -0
  81. package/skills/backend/references/api-design.md +168 -0
  82. package/skills/backend/references/caching.md +181 -0
  83. package/skills/backend/references/data-access.md +173 -0
  84. package/skills/backend/references/layering.md +181 -0
  85. package/skills/backend/references/observability.md +190 -0
  86. package/skills/backend/references/resilience.md +201 -0
  87. package/skills/backend/references/security.md +186 -0
  88. package/skills/backend-architect/SKILL.md +119 -0
  89. package/skills/code-reviewer/SKILL.md +143 -0
  90. package/skills/coding-standards/SKILL.md +60 -0
  91. package/skills/coding-standards/references/clean-code.md +258 -0
  92. package/skills/coding-standards/references/code-review.md +192 -0
  93. package/skills/coding-standards/references/commits-and-prs.md +226 -0
  94. package/skills/coding-standards/references/error-strategy.md +193 -0
  95. package/skills/coding-standards/references/naming.md +185 -0
  96. package/skills/coding-standards/references/tdd.md +171 -0
  97. package/skills/database/SKILL.md +53 -0
  98. package/skills/database/references/indexing.md +190 -0
  99. package/skills/database/references/migrations.md +199 -0
  100. package/skills/database/references/nosql.md +185 -0
  101. package/skills/database/references/queries.md +295 -0
  102. package/skills/database/references/scaling.md +203 -0
  103. package/skills/database/references/schema.md +191 -0
  104. package/skills/database-optimizer/SKILL.md +168 -0
  105. package/skills/debugging-workflow/SKILL.md +244 -0
  106. package/skills/devops/SKILL.md +55 -0
  107. package/skills/devops/references/ci-cd.md +204 -0
  108. package/skills/devops/references/containers.md +272 -0
  109. package/skills/devops/references/deploy.md +201 -0
  110. package/skills/devops/references/iac.md +252 -0
  111. package/skills/devops/references/observability.md +228 -0
  112. package/skills/devops/references/secrets.md +178 -0
  113. package/skills/devops-automator/SKILL.md +164 -0
  114. package/skills/frontend/SKILL.md +52 -0
  115. package/skills/frontend/references/accessibility.md +222 -0
  116. package/skills/frontend/references/components.md +206 -0
  117. package/skills/frontend/references/performance.md +219 -0
  118. package/skills/frontend/references/routing.md +209 -0
  119. package/skills/frontend/references/state.md +190 -0
  120. package/skills/frontend/references/testing.md +216 -0
  121. package/skills/frontend-developer/SKILL.md +115 -0
  122. package/skills/git-workflow/SKILL.md +355 -0
  123. package/skills/golang/SKILL.md +49 -0
  124. package/skills/golang/references/concurrency.md +284 -0
  125. package/skills/golang/references/errors.md +241 -0
  126. package/skills/golang/references/idioms.md +285 -0
  127. package/skills/golang/references/testing.md +238 -0
  128. package/skills/java/SKILL.md +50 -0
  129. package/skills/java/references/concurrency.md +194 -0
  130. package/skills/java/references/idioms.md +283 -0
  131. package/skills/java/references/testing.md +228 -0
  132. package/skills/kotlin/SKILL.md +47 -0
  133. package/skills/kotlin/references/coroutines.md +240 -0
  134. package/skills/kotlin/references/idioms.md +268 -0
  135. package/skills/kotlin/references/testing.md +219 -0
  136. package/skills/mobile/SKILL.md +50 -0
  137. package/skills/mobile/references/architecture.md +204 -0
  138. package/skills/mobile/references/navigation.md +158 -0
  139. package/skills/mobile/references/performance.md +152 -0
  140. package/skills/mobile/references/platform.md +166 -0
  141. package/skills/mobile/references/state-and-data.md +174 -0
  142. package/skills/python/SKILL.md +51 -0
  143. package/skills/python/THIRD_PARTY.md +14 -0
  144. package/skills/python/references/async.md +218 -0
  145. package/skills/python/references/error-handling.md +254 -0
  146. package/skills/python/references/idioms.md +279 -0
  147. package/skills/python/references/packaging.md +233 -0
  148. package/skills/python/references/testing.md +269 -0
  149. package/skills/python/references/typing.md +292 -0
  150. package/skills/qa-tester/SKILL.md +186 -0
  151. package/skills/rust/SKILL.md +50 -0
  152. package/skills/rust/references/async.md +224 -0
  153. package/skills/rust/references/errors.md +240 -0
  154. package/skills/rust/references/ownership.md +263 -0
  155. package/skills/rust/references/testing.md +274 -0
  156. package/skills/rust/references/traits.md +250 -0
  157. package/skills/security-engineer/SKILL.md +157 -0
  158. package/skills/swift/SKILL.md +48 -0
  159. package/skills/swift/references/concurrency.md +280 -0
  160. package/skills/swift/references/idioms.md +334 -0
  161. package/skills/swift/references/testing.md +229 -0
  162. package/skills/typescript/SKILL.md +51 -0
  163. package/skills/typescript/references/async.md +241 -0
  164. package/skills/typescript/references/errors.md +208 -0
  165. package/skills/typescript/references/idioms.md +246 -0
  166. package/skills/typescript/references/testing.md +225 -0
  167. package/skills/typescript/references/tooling.md +208 -0
  168. package/skills/typescript/references/types.md +259 -0
@@ -0,0 +1,216 @@
1
+ # Frontend Testing
2
+
3
+ Component tests, E2E (Playwright), visual regression. For TDD, see `coding-standards/references/tdd.md`.
4
+
5
+ ## The pyramid, frontend version
6
+
7
+ ```
8
+
9
+ │ Visual / E2E (5%) ← real browser, real flows
10
+ │ Integration (20%) ← component + key deps; real rendering
11
+ │ Unit (75%) ← functions, hooks, reducers; no DOM
12
+
13
+ ```
14
+
15
+ Invert this and tests become slow, flaky, and your fast feedback loop dies.
16
+
17
+ ## Unit tests — pure logic
18
+
19
+ For reducers, selectors, utility functions, validation. Same rules as any language.
20
+
21
+ ```
22
+ describe('priceWithTax', () => {
23
+ it('adds tax by rate', () => {
24
+ expect(priceWithTax(100, 0.2)).toBe(120);
25
+ });
26
+ });
27
+ ```
28
+
29
+ ## Component tests — Testing Library philosophy
30
+
31
+ Test the component through the accessibility tree, not through implementation internals.
32
+
33
+ ```
34
+ import { render, screen } from '@testing-library/react';
35
+ import { userEvent } from '@testing-library/user-event';
36
+
37
+ test('submit is disabled until email is valid', async () => {
38
+ render(<SignupForm />);
39
+ const email = screen.getByLabelText(/email/i);
40
+ const submit = screen.getByRole('button', { name: /sign up/i });
41
+
42
+ expect(submit).toBeDisabled();
43
+ await userEvent.type(email, 'a@x.com');
44
+ expect(submit).toBeEnabled();
45
+ });
46
+ ```
47
+
48
+ Key conventions:
49
+ - **Query by role** (`getByRole('button', { name: 'Save' })`) — that's what a screen reader sees.
50
+ - **Query by label / text** for inputs and visible content.
51
+ - **Never by className / test-id unless nothing else works.**
52
+ - **Never assert on implementation details** (internal state, prop changes, class names).
53
+
54
+ ## Mock at the network boundary
55
+
56
+ Don't mock internal hooks. Mock the fetch / WS. Tests stay honest.
57
+
58
+ ```
59
+ import { setupServer } from 'msw/node';
60
+ import { http, HttpResponse } from 'msw';
61
+
62
+ const server = setupServer(
63
+ http.get('/api/users/:id', ({ params }) =>
64
+ HttpResponse.json({ id: params.id, email: 'a@x.com' })
65
+ ),
66
+ );
67
+
68
+ beforeAll(() => server.listen());
69
+ afterEach(() => server.resetHandlers());
70
+ afterAll(() => server.close());
71
+
72
+ test('loads and renders user', async () => {
73
+ render(<UserCard id="u1" />);
74
+ expect(await screen.findByText('a@x.com')).toBeInTheDocument();
75
+ });
76
+ ```
77
+
78
+ MSW (Mock Service Worker) works for unit/integration tests and in the browser. Same mocks everywhere.
79
+
80
+ ## Async: `findBy` over `waitFor` + `getBy`
81
+
82
+ ```
83
+ # ✅ waits implicitly; throws if not found in time
84
+ expect(await screen.findByText('Welcome')).toBeInTheDocument();
85
+
86
+ # ❌ verbose
87
+ await waitFor(() => expect(screen.getByText('Welcome')).toBeInTheDocument());
88
+ ```
89
+
90
+ ## Don't sleep in tests
91
+
92
+ If `setTimeout(..., 500)` is the only way to make it pass, fake the timer:
93
+
94
+ ```
95
+ vi.useFakeTimers();
96
+ // interact
97
+ vi.advanceTimersByTime(500);
98
+ // assert
99
+ vi.useRealTimers();
100
+ ```
101
+
102
+ Real sleeps make tests slow and flaky.
103
+
104
+ ## Hook / composable tests
105
+
106
+ ```
107
+ import { renderHook, act } from '@testing-library/react';
108
+
109
+ test('useCounter increments', () => {
110
+ const { result } = renderHook(() => useCounter());
111
+ act(() => result.current.increment());
112
+ expect(result.current.count).toBe(1);
113
+ });
114
+ ```
115
+
116
+ Vue's equivalent uses `mount` with a minimal wrapper.
117
+
118
+ ## Store / reducer tests
119
+
120
+ Pure functions — test without a DOM.
121
+
122
+ ```
123
+ test('cartReducer adds item', () => {
124
+ const state = cartReducer(initial, { type: 'add', item });
125
+ expect(state.items).toHaveLength(1);
126
+ });
127
+ ```
128
+
129
+ If you need the store under Redux-Toolkit or similar, create a test-only store instance. Don't export globals shared across tests.
130
+
131
+ ## E2E — Playwright (or Cypress)
132
+
133
+ Playwright has clear advantages:
134
+ - First-class TypeScript, no CLI glue.
135
+ - Multi-browser (Chromium, Firefox, WebKit).
136
+ - Parallel by default.
137
+ - Network interception built in.
138
+
139
+ ```
140
+ import { test, expect } from '@playwright/test';
141
+
142
+ test('signup flow', async ({ page }) => {
143
+ await page.goto('/signup');
144
+ await page.getByLabel('Email').fill('a@x.com');
145
+ await page.getByLabel('Password').fill('correct horse battery staple');
146
+ await page.getByRole('button', { name: 'Create account' }).click();
147
+ await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible();
148
+ });
149
+ ```
150
+
151
+ Rules:
152
+ - **Write by role / label**, not CSS selectors.
153
+ - **Wait for state, not for time.** Playwright's `expect().toBeVisible()` auto-retries.
154
+ - **Own your data.** Seed the DB (API or fixture) before each test; tests shouldn't depend on state from other tests.
155
+ - **Keep E2E to happy-path + critical flows.** Unit / integration cover the combinatorics.
156
+
157
+ ## Visual regression
158
+
159
+ Tools: Playwright built-in screenshot diff, Chromatic (Storybook), Percy, Applitools.
160
+
161
+ ```
162
+ await expect(page).toHaveScreenshot('home.png');
163
+ ```
164
+
165
+ Traps:
166
+ - Flaky anti-alias / font rendering across OSes → run on Linux in CI only, accept minor diff tolerance.
167
+ - Time / random IDs in the screenshot → stub or mask.
168
+ - Snapshot explosion (one per page × browser × theme) → be selective.
169
+
170
+ Great for design systems and key pages. Less valuable for the long tail.
171
+
172
+ ## Storybook
173
+
174
+ Isolate components. One story per variant.
175
+
176
+ ```
177
+ export default { title: 'Button' };
178
+
179
+ export const Primary = () => <Button variant="primary">Save</Button>;
180
+ export const Disabled = () => <Button disabled>Save</Button>;
181
+ export const Long = () => <Button>Save my very long message</Button>;
182
+ ```
183
+
184
+ - Run component tests against stories (`play` function).
185
+ - Run a11y checks against stories (`@storybook/addon-a11y`).
186
+ - Use as visual regression fixture.
187
+
188
+ Kills the "how did the component look in that one state again?" question.
189
+
190
+ ## CI configuration
191
+
192
+ Typical split:
193
+
194
+ | Stage | Runs | On |
195
+ |---|---|---|
196
+ | Unit | Every commit | All PRs, fast fail |
197
+ | Integration / component | Every commit | All PRs |
198
+ | E2E happy path | Every commit | PRs, on staging |
199
+ | Visual regression | Daily + on design-touching PRs | Scheduled |
200
+ | Full E2E matrix | On main / pre-release | Nightly |
201
+
202
+ Run the cheap ones on every commit; save the expensive ones for what they uniquely catch.
203
+
204
+ ## Anti-patterns
205
+
206
+ | Anti-pattern | Fix |
207
+ |---|---|
208
+ | Testing internal state / prop of a component | Test behaviour the user experiences |
209
+ | Snapshot tests for entire pages | Brittle; use for specific outputs |
210
+ | `data-testid` everywhere | Rely on roles / labels first |
211
+ | Mocking React / Vue internals | You're testing the framework, not your code |
212
+ | Shared global state between E2E tests | Seed per-test; reset between |
213
+ | 50 E2E tests, 5 unit tests | Flip the pyramid |
214
+ | Waiting for `await page.waitForTimeout(1000)` | Wait for a condition / state |
215
+ | Testing against prod or shared staging | Test against ephemeral / dedicated env |
216
+ | CSS-class-based assertions (`toHaveClass('active')`) | Assert on observable effect (visible text, role, aria) |
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: frontend-developer
3
+ description: Persona skill — think like a frontend developer. Users, latency, accessibility, state clarity. Overlay on top of `frontend` + language skills. For patterns, load `frontend`.
4
+ origin: agency-agents-fork + original (https://github.com/msitarzewski/agency-agents, MIT)
5
+ ---
6
+
7
+ # Frontend Developer
8
+
9
+ Think like a frontend developer. This is a **mindset overlay** — load `frontend` for patterns.
10
+
11
+ ## When to load
12
+
13
+ - Building / reviewing UI
14
+ - Making a call on what state shape to use
15
+ - Reviewing a design for technical feasibility
16
+ - Debating component API, routing, or data fetching
17
+ - Triaging a frontend perf / a11y issue
18
+
19
+ ## The posture
20
+
21
+ 1. **Users don't see your code.** They see latency, layout shifts, broken keyboards. Measure what they experience.
22
+ 2. **State is the hard part.** Components are easy. Server state ≠ client state ≠ URL state — don't mix them.
23
+ 3. **Native first, custom second.** `<button>` beats `<div role="button">`. Always.
24
+ 4. **Every feature has a loading state AND an error state.** Design all three up front, not "happy path, will add later".
25
+ 5. **Accessibility is correctness.** Keyboard, contrast, screen reader. Not a final pass.
26
+ 6. **Perf is a feature, not an optimization pass.** Budgets in CI, not hope.
27
+ 7. **The browser is hostile.** Old versions, slow networks, third-party scripts, ad blockers. Degrade gracefully.
28
+
29
+ ## The questions you always ask
30
+
31
+ - **What does this look like at 300 ms latency?** Many interactions.
32
+ - **What if the fetch fails halfway?** Partial render, retry, error message.
33
+ - **What if the user presses Tab?** Does focus go where a keyboard user expects?
34
+ - **What state is this, exactly?** Local, shared, server, URL, derived?
35
+ - **Is this URL bookmarkable?** Would I land on the same view if I pasted it?
36
+ - **Which images / fonts / scripts block first paint?** Measure LCP.
37
+ - **Does this work with JavaScript disabled / broken?** (For critical content paths.)
38
+ - **Is this accessible with a screen reader?** Actually tested, not just "has alt attributes".
39
+ - **Who re-renders when this state changes?** Keep the blast radius small.
40
+ - **What does this cost in bundle bytes?** Every library has a weight.
41
+
42
+ ## The checklist
43
+
44
+ ### UX shape
45
+ - [ ] Loading state designed
46
+ - [ ] Error state designed with actionable message
47
+ - [ ] Empty state designed
48
+ - [ ] Disabled states clear (not just grayed out — provide the reason)
49
+ - [ ] Optimistic updates for user-initiated writes
50
+
51
+ ### Accessibility
52
+ - [ ] Semantic HTML throughout
53
+ - [ ] Keyboard-navigable
54
+ - [ ] Visible focus styles (`:focus-visible`)
55
+ - [ ] Screen-reader tested for critical flows
56
+ - [ ] Contrast ≥ WCAG AA (4.5:1 text / 3:1 UI)
57
+ - [ ] Respects `prefers-reduced-motion`
58
+
59
+ ### State
60
+ - [ ] Server data via a cache lib (TanStack Query / SWR / Apollo / equivalent)
61
+ - [ ] No duplicate sources of truth
62
+ - [ ] URL holds filters / selected tabs / deep state
63
+ - [ ] Forms validate client-side + server-side
64
+ - [ ] Drafts persisted where the user expects (offline / reload)
65
+
66
+ ### Performance
67
+ - [ ] LCP < 2.5 s, INP < 200 ms, CLS < 0.1 (at 75th percentile)
68
+ - [ ] Images sized to display; lazy below the fold
69
+ - [ ] Bundle analysis done; no 5 MB surprises
70
+ - [ ] Route-level code splitting
71
+ - [ ] Virtualization for long lists
72
+ - [ ] Web fonts preloaded with `font-display: swap`
73
+
74
+ ### Code
75
+ - [ ] Components do one thing
76
+ - [ ] Props typed
77
+ - [ ] Side effects in hooks / stores, not in render
78
+ - [ ] No `any` / untyped data
79
+ - [ ] Dead code / commented-out code removed
80
+
81
+ ## Tradeoffs you name
82
+
83
+ - **CSR vs. SSR vs. SSG** — per-page, based on content and SEO needs.
84
+ - **Controlled vs. uncontrolled** — controlled for complex forms, uncontrolled for simple.
85
+ - **Optimistic vs. pessimistic** — optimistic for routine writes, pessimistic for dangerous ones (payments, delete).
86
+ - **Animation vs. function** — animation is a detail; don't block interactions.
87
+ - **Client-side vs. server-side validation** — both, not one.
88
+
89
+ ## What you push back on
90
+
91
+ - **Designs that ignore loading / error / empty states.** Those ARE the user experience.
92
+ - **Accessibility-as-final-sprint.** Costs more to retrofit.
93
+ - **"Just wrap it in a div with onClick".** No.
94
+ - **Reactive libraries for static data.** Over-engineering.
95
+ - **Prop drilling 6 levels deep.** Context / composition.
96
+ - **Toasts / dialogs for critical errors.** Modals that block progress, then. Not a toast that vanishes.
97
+
98
+ ## Forbidden patterns
99
+
100
+ - `<div onClick>` where `<button>` / `<a>` fits
101
+ - Placeholder used as label
102
+ - Color as the only error signal
103
+ - Business logic in JSX
104
+ - `useEffect` to derive state (use computed values / `useMemo`)
105
+ - Untyped data at boundaries
106
+ - Images without `width`/`height` (layout shift)
107
+ - Toasts swallowing irrecoverable errors
108
+ - "Submit" enabled during in-flight submit (double-submit bug)
109
+ - Hand-rolled date pickers / selects that ignore keyboard / screen reader
110
+
111
+ ## Pair with
112
+
113
+ - [`frontend`](../frontend/SKILL.md) — the patterns.
114
+ - A language skill (`typescript`) — syntax and types.
115
+ - [`coding-standards`](../coding-standards/SKILL.md) — general principles.
@@ -0,0 +1,355 @@
1
+ ---
2
+ name: git-workflow
3
+ description: Workflow skill — git hygiene beyond commit-message style. Branching, rebasing, conflict resolution, recovering from mistakes. For commit-message format and PR sizing, see `coding-standards/references/commits-and-prs.md`.
4
+ origin: original
5
+ ---
6
+
7
+ # Git Workflow
8
+
9
+ Day-to-day git habits for keeping history useful and recovery cheap. For commit message style and PR sizing, load [`coding-standards/references/commits-and-prs.md`](../coding-standards/references/commits-and-prs.md).
10
+
11
+ ## When to load
12
+
13
+ - Starting a new feature branch
14
+ - Reviewing how to structure a series of commits
15
+ - Resolving a merge / rebase conflict
16
+ - Recovering from a "bad git operation"
17
+ - Onboarding to a repo with a specific workflow (trunk-based, GitFlow, etc.)
18
+
19
+ ## The posture
20
+
21
+ 1. **Commits are communication.** The history is read by your future self and your teammates. Make it readable.
22
+ 2. **Small, logical, atomic commits.** Each commit reverts cleanly. Each commit tells one story.
23
+ 3. **Rebase your own branch; never shared branches.** History rewriting on public branches breaks everyone.
24
+ 4. **Never `--force` without `--force-with-lease`.** The safer form checks no one else has pushed.
25
+ 5. **Lost work is usually recoverable.** `git reflog` remembers.
26
+ 6. **When in doubt, stash or branch before experimenting.** Cheap insurance.
27
+
28
+ ## Workflow patterns
29
+
30
+ Pick one per project and stick to it.
31
+
32
+ ### Trunk-based
33
+
34
+ Short-lived branches, merge to `main` at least daily. Best for CI-strong teams.
35
+
36
+ ```
37
+ main ─────────────●──────●──────●──────●──────
38
+ ↑ ↑ ↑ ↑
39
+ feature branches, 1–3 days each
40
+ ```
41
+
42
+ Pros: minimal merge pain, fast feedback, clear integration point.
43
+ Cons: needs strong CI and feature flags to ship incomplete work safely.
44
+
45
+ ### Feature-branch + PR (pragmatic default)
46
+
47
+ Named branches per feature, merged via PR to `main`. Branches live days to a week.
48
+
49
+ ```
50
+ main ─────●────────●────────●─────
51
+ \ / \ /
52
+ feature1 feature2
53
+ ```
54
+
55
+ Most teams. Rebase on `main` before merging to keep history linear.
56
+
57
+ ### GitFlow
58
+
59
+ `develop`, `release/*`, `hotfix/*` alongside `main`. Heavier; fits products with long support branches.
60
+
61
+ ```
62
+ main (release tags)
63
+
64
+ ├─ release/* (stabilization)
65
+
66
+ └─ develop
67
+ ├─ feature/*
68
+ └─ hotfix/* → main + develop
69
+ ```
70
+
71
+ Use when you ship monthly / quarterly and have parallel release support. Overkill for most web apps.
72
+
73
+ ## Branch naming
74
+
75
+ ```
76
+ <type>/<short-slug>
77
+
78
+ feat/partial-shipments
79
+ fix/auth-alg-none
80
+ chore/bump-node-20
81
+ refactor/extract-validator
82
+ ```
83
+
84
+ Include a ticket id if your team tracks: `fix/SEC-412-alg-none`.
85
+
86
+ Rules:
87
+ - Lowercase + hyphens.
88
+ - No personal names (`alice/wip`); one-off personal branches die without review.
89
+ - No `feature/` prefix — type is the prefix, and `feature/` duplicates.
90
+
91
+ ## The commit loop
92
+
93
+ Good session flow:
94
+
95
+ 1. `git status` before starting — clean? any leftover changes?
96
+ 2. Make a change; run tests.
97
+ 3. `git diff` — review before staging.
98
+ 4. `git add -p` — stage in logical chunks, not everything blindly.
99
+ 5. `git commit` — one logical change, good message.
100
+ 6. Repeat.
101
+
102
+ `-p` (patch) mode is underrated. It lets you split "one big edit" into several commits.
103
+
104
+ ## Rebase your own branch on `main`
105
+
106
+ Keeps a clean linear history and avoids dirty "Merge main into feature" commits.
107
+
108
+ ```bash
109
+ git fetch origin
110
+ git rebase origin/main
111
+ # resolve conflicts if any
112
+ git push --force-with-lease
113
+ ```
114
+
115
+ Never rebase a branch others are working on — they'll have conflicts and lose commits.
116
+
117
+ ## Interactive rebase — clean up your history
118
+
119
+ Before opening a PR:
120
+
121
+ ```bash
122
+ git rebase -i origin/main
123
+ ```
124
+
125
+ Opens an editor listing your commits. Actions:
126
+
127
+ | Action | Effect |
128
+ |---|---|
129
+ | `pick` | Keep as-is |
130
+ | `reword` | Change the commit message |
131
+ | `edit` | Stop to amend the commit |
132
+ | `squash` | Combine with the previous commit; edit message |
133
+ | `fixup` | Combine with previous; keep previous message |
134
+ | `drop` | Delete |
135
+
136
+ Use to squash WIP commits, fix typos in messages, reorder logically. Don't use on already-pushed-to-shared branches.
137
+
138
+ ## Handling conflicts
139
+
140
+ When rebase or merge hits a conflict:
141
+
142
+ ```bash
143
+ # git marks conflict files; you edit and resolve
144
+ <<<<<<< HEAD
145
+ your code
146
+ =======
147
+ their code
148
+ >>>>>>> branch
149
+
150
+ # After editing:
151
+ git add <resolved-files>
152
+ git rebase --continue # or git merge --continue
153
+
154
+ # To back out:
155
+ git rebase --abort
156
+ ```
157
+
158
+ Rules:
159
+ - **Read both sides.** Don't just pick one wholesale.
160
+ - **Ensure tests pass after the resolution.** A bad merge compiles but breaks behaviour.
161
+ - **Commit the resolution as is.** Don't mix in other changes.
162
+
163
+ ### `rerere` — reuse recorded resolutions
164
+
165
+ Turn on once, saves pain on repeated rebases:
166
+
167
+ ```bash
168
+ git config --global rerere.enabled true
169
+ ```
170
+
171
+ Git remembers how you resolved a given conflict; applies it automatically next time the same conflict appears.
172
+
173
+ ## Force-push safely
174
+
175
+ Rebasing changes commit SHAs, requiring a force-push. Use `--force-with-lease`:
176
+
177
+ ```bash
178
+ git push --force-with-lease
179
+ ```
180
+
181
+ `--force` overwrites the remote without checking. If someone else pushed to your branch, you silently overwrite their work. `--force-with-lease` fails safely in that case.
182
+
183
+ Better alias:
184
+
185
+ ```bash
186
+ git config --global alias.pf 'push --force-with-lease'
187
+ ```
188
+
189
+ ## Recovering lost work
190
+
191
+ Almost all "lost" git operations are recoverable via `reflog`.
192
+
193
+ ```bash
194
+ git reflog # list of everything HEAD has pointed to
195
+ # HEAD@{0}: rebase: ...
196
+ # HEAD@{1}: rebase: ...
197
+ # HEAD@{2}: commit: "WIP"
198
+ git checkout HEAD@{2} # go back to the state before you broke it
199
+ ```
200
+
201
+ If your last commit was broken and you ran `git reset --hard`:
202
+
203
+ ```bash
204
+ git reflog
205
+ git reset --hard HEAD@{1} # restore
206
+ ```
207
+
208
+ Works for ~90 days by default. The golden rule: **commit often. Committed work is almost never truly lost.**
209
+
210
+ ## `stash` — quick save
211
+
212
+ Interrupting to switch branches?
213
+
214
+ ```bash
215
+ git stash push -m "WIP: auth refactor"
216
+ git switch other-branch
217
+
218
+ # later
219
+ git switch original-branch
220
+ git stash pop # reapply and remove from stash
221
+ # or:
222
+ git stash apply stash@{0} # reapply but keep in stash
223
+ git stash list
224
+ ```
225
+
226
+ Stash names help when you accumulate several. Don't let stashes pile up — they're not backup.
227
+
228
+ ## Cherry-pick
229
+
230
+ ```bash
231
+ git cherry-pick <sha>
232
+ ```
233
+
234
+ Copy a commit from another branch. Handy for:
235
+ - Backporting a fix to a release branch.
236
+ - Salvaging one commit from an abandoned branch.
237
+
238
+ Avoid using cherry-pick as a regular integration strategy; it creates duplicate work in the history.
239
+
240
+ ## Worktrees — parallel branches
241
+
242
+ ```bash
243
+ git worktree add ../myrepo-release release/v2
244
+ # work in both directories simultaneously
245
+ git worktree remove ../myrepo-release
246
+ ```
247
+
248
+ One clone, multiple branches checked out in separate directories. Useful for long-running release branches, bisect, comparison.
249
+
250
+ ## `bisect` — find the commit that broke things
251
+
252
+ ```bash
253
+ git bisect start
254
+ git bisect bad # current is broken
255
+ git bisect good v1.2.0 # this tag was fine
256
+
257
+ # git checks out a commit in the middle; test it
258
+ git bisect good # or bisect bad
259
+ # repeat until git identifies the culprit
260
+ git bisect reset
261
+ ```
262
+
263
+ `git bisect run ./test.sh` automates it — git runs your script at each step.
264
+
265
+ ## `.gitignore` discipline
266
+
267
+ Keep it current. Default entries:
268
+
269
+ ```
270
+ # dependencies
271
+ node_modules/
272
+ .venv/
273
+ target/
274
+
275
+ # env / secrets
276
+ .env
277
+ .env.local
278
+ *.pem
279
+ *.key
280
+
281
+ # IDE / OS
282
+ .idea/
283
+ .vscode/
284
+ *.swp
285
+ .DS_Store
286
+
287
+ # build
288
+ dist/
289
+ build/
290
+ *.pyc
291
+ ```
292
+
293
+ If a file was committed by accident, ignoring it doesn't remove it — use `git rm --cached <file>` + commit.
294
+
295
+ ## `.gitattributes` — normalize line endings
296
+
297
+ Avoid CRLF / LF chaos across Windows + Mac + Linux:
298
+
299
+ ```
300
+ * text=auto eol=lf
301
+ *.sh text eol=lf
302
+ *.bat text eol=crlf
303
+ *.png binary
304
+ ```
305
+
306
+ Commit it; once everyone has it, cross-OS diffs go quiet.
307
+
308
+ ## Git hooks — local enforcement
309
+
310
+ - **pre-commit** — run linter / formatter / tests before a commit is allowed.
311
+ - **commit-msg** — enforce commit message format.
312
+ - **pre-push** — run tests before push.
313
+
314
+ Use a hook manager (`lefthook`, `husky`, `pre-commit`) so hooks are in the repo, shared with the team.
315
+
316
+ ```yaml
317
+ # lefthook.yml
318
+ pre-commit:
319
+ parallel: true
320
+ commands:
321
+ lint: { run: pnpm lint }
322
+ format-check: { run: pnpm format:check }
323
+ ```
324
+
325
+ Don't `--no-verify` your hooks. If a hook fails, fix the underlying issue.
326
+
327
+ ## Recovery cheat-sheet
328
+
329
+ | "I accidentally..." | Fix |
330
+ |---|---|
331
+ | Committed to wrong branch | `git reset --soft HEAD~1`, switch branches, recommit |
332
+ | Deleted a branch | `git reflog` → find SHA → `git branch <name> <sha>` |
333
+ | Force-pushed over someone | Coordinate; `git reflog` on their machine can recover |
334
+ | Committed a secret | Rotate the secret immediately; history rewrite is secondary |
335
+ | Lost uncommitted changes | `git reflog` only helps if committed; stashes via `git stash list` |
336
+ | Merged wrong branch | `git reset --hard HEAD~1` (before push), or `git revert` (after push) |
337
+ | Detached HEAD | `git branch <newname>` before switching away |
338
+
339
+ ## Forbidden patterns
340
+
341
+ - `git push --force` (without `--force-with-lease`)
342
+ - `--no-verify` to skip hooks because "they're annoying"
343
+ - 20+ `WIP` / `fix` commits pushed to main (squash them)
344
+ - Long-lived feature branches (weeks+) without merging / rebasing
345
+ - Editing `.gitignore` without committing the removals that `.gitignore` was meant to catch
346
+ - Rebasing a shared branch
347
+ - Committing secrets (even if planning to remove next commit)
348
+ - `git add -A` without review
349
+ - Keeping personal branches around in the remote for months
350
+ - Mixing rename + content change in one commit (hides the rename)
351
+
352
+ ## Pair with
353
+
354
+ - [`coding-standards/references/commits-and-prs.md`](../coding-standards/references/commits-and-prs.md) — commit messages + PR sizing.
355
+ - [`devops/references/ci-cd.md`](../devops/references/ci-cd.md) — branch protection + CI triggers.