agentic-team 0.0.0-stage → 6.1.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 +184 -2
- package/bin/build-template.js +208 -0
- package/bin/index.js +1139 -0
- package/package.json +41 -4
- package/template/.claude-plugin/plugin.json +10 -0
- package/template/.orchestra/README.md +401 -0
- package/template/.orchestra/blueprints/README.md +87 -0
- package/template/.orchestra/blueprints/api-only.md +46 -0
- package/template/.orchestra/blueprints/component-crud-resource.md +25 -0
- package/template/.orchestra/blueprints/saas-starter.md +69 -0
- package/template/.orchestra/config.yml +277 -0
- package/template/.orchestra/roles/orchestrator.md +105 -0
- package/template/.orchestra/roles/product-manager.md +438 -0
- package/template/.orchestra/scripts/compact-diff.awk +45 -0
- package/template/.orchestra/stacks/README.md +81 -0
- package/template/.orchestra/stacks/_lib/common.sh +3095 -0
- package/template/.orchestra/stacks/_repo/setup.sh +1109 -0
- package/template/.orchestra/stacks/backend-hono/claude/commands/endpoint.md +13 -0
- package/template/.orchestra/stacks/backend-hono/claude/skills/api-endpoint/SKILL.md +111 -0
- package/template/.orchestra/stacks/backend-hono/claude/skills/testing/SKILL.md +75 -0
- package/template/.orchestra/stacks/backend-hono/setup.sh +5945 -0
- package/template/.orchestra/stacks/backend-hono/stack.md +195 -0
- package/template/.orchestra/stacks/mobile-android-native/claude/commands/component.md +13 -0
- package/template/.orchestra/stacks/mobile-android-native/claude/skills/design-component/SKILL.md +58 -0
- package/template/.orchestra/stacks/mobile-android-native/setup.sh +607 -0
- package/template/.orchestra/stacks/mobile-android-native/stack.md +138 -0
- package/template/.orchestra/stacks/mobile-expo/claude/commands/component.md +12 -0
- package/template/.orchestra/stacks/mobile-expo/claude/skills/design-component/SKILL.md +92 -0
- package/template/.orchestra/stacks/mobile-expo/setup.sh +470 -0
- package/template/.orchestra/stacks/mobile-expo/stack.md +141 -0
- package/template/.orchestra/stacks/mobile-ios-native/claude/commands/component.md +12 -0
- package/template/.orchestra/stacks/mobile-ios-native/claude/skills/design-component/SKILL.md +58 -0
- package/template/.orchestra/stacks/mobile-ios-native/setup.sh +468 -0
- package/template/.orchestra/stacks/mobile-ios-native/stack.md +130 -0
- package/template/.orchestra/stacks/web-nextjs/claude/commands/component.md +12 -0
- package/template/.orchestra/stacks/web-nextjs/claude/skills/design-component/SKILL.md +100 -0
- package/template/.orchestra/stacks/web-nextjs/claude/skills/design-tokens/SKILL.md +61 -0
- package/template/.orchestra/stacks/web-nextjs/setup.sh +128 -0
- package/template/.orchestra/stacks/web-nextjs/stack.md +170 -0
- package/template/.orchestra/stacks/web-vite-react/claude/commands/component.md +12 -0
- package/template/.orchestra/stacks/web-vite-react/claude/skills/design-component/SKILL.md +100 -0
- package/template/.orchestra/stacks/web-vite-react/claude/skills/design-tokens/SKILL.md +61 -0
- package/template/.orchestra/stacks/web-vite-react/setup.sh +185 -0
- package/template/.orchestra/stacks/web-vite-react/stack.md +177 -0
- package/template/.orchestra/trackers/github.sh +467 -0
- package/template/CLAUDE.md +54 -0
- package/template/agents/architect.md +83 -0
- package/template/agents/engineer-high.md +17 -0
- package/template/agents/engineer-low.md +17 -0
- package/template/agents/engineer-max.md +17 -0
- package/template/agents/engineer-medium.md +17 -0
- package/template/agents/engineer-xhigh.md +17 -0
- package/template/agents/lead.md +870 -0
- package/template/agents/milestone-reviewer.md +63 -0
- package/template/agents/orchestrator.md +105 -0
- package/template/agents/product-manager.md +438 -0
- package/template/agents/reviewer.md +301 -0
- package/template/agents/scaffolder.md +180 -0
- package/template/agents/tracker.md +202 -0
- package/template/commands/blueprint.md +23 -0
- package/template/commands/create-role.md +64 -0
- package/template/commands/export.md +45 -0
- package/template/commands/help.md +55 -0
- package/template/commands/hotfix.md +12 -0
- package/template/commands/orchestrator.md +12 -0
- package/template/commands/pm.md +18 -0
- package/template/commands/rewind.md +61 -0
- package/template/commands/setup.md +14 -0
- package/template/commands/start.md +29 -0
- package/template/commands/status.md +11 -0
- package/template/commands/sync.md +73 -0
- package/template/commands/verifier.md +53 -0
- package/template/hooks/audit-context.sh +153 -0
- package/template/hooks/enforce-role.sh +175 -0
- package/template/hooks/protect-system-files.sh +123 -0
- package/template/hooks/review-rounds.sh +172 -0
- package/template/rules/acceptance-check.orchestra.md +11 -0
- package/template/rules/analytics-kpi.orchestra.md +56 -0
- package/template/rules/code-standards.orchestra.md +34 -0
- package/template/rules/comments.orchestra.md +77 -0
- package/template/rules/commit-format.orchestra.md +20 -0
- package/template/rules/dependency-upgrade.orchestra.md +112 -0
- package/template/rules/design-parity.orchestra.md +170 -0
- package/template/rules/observability.orchestra.md +118 -0
- package/template/rules/performance.orchestra.md +186 -0
- package/template/rules/phase-limits.orchestra.md +3 -0
- package/template/rules/pull-request.orchestra.md +213 -0
- package/template/rules/role-boundaries.orchestra.md +117 -0
- package/template/rules/security.orchestra.md +106 -0
- package/template/rules/stuck-detection.orchestra.md +25 -0
- package/template/rules/testing-standards.orchestra.md +214 -0
- package/template/rules/tracker-authority.orchestra.md +190 -0
- package/template/rules/verification-gate.orchestra.md +56 -0
- package/template/skills/accessibility/SKILL.md +31 -0
- package/template/skills/android-testing/SKILL.md +112 -0
- package/template/skills/architecture/SKILL.md +175 -0
- package/template/skills/auth-setup/SKILL.md +105 -0
- package/template/skills/best-practices/SKILL.md +29 -0
- package/template/skills/code-optimizer/SKILL.md +27 -0
- package/template/skills/core-web-vitals/SKILL.md +32 -0
- package/template/skills/crud-api/SKILL.md +32 -0
- package/template/skills/debug/SKILL.md +28 -0
- package/template/skills/deployment/SKILL.md +104 -0
- package/template/skills/error-handling/SKILL.md +154 -0
- package/template/skills/frontend-design/SKILL.md +30 -0
- package/template/skills/fullstack-infrastructure/SKILL.md +108 -0
- package/template/skills/ios-testing/SKILL.md +100 -0
- package/template/skills/mobile-testing/SKILL.md +102 -0
- package/template/skills/observability/SKILL.md +91 -0
- package/template/skills/project-structure/SKILL.md +114 -0
- package/template/skills/push-notifications/SKILL.md +146 -0
- package/template/skills/react-best-practices/SKILL.md +31 -0
- package/template/skills/realtime/SKILL.md +146 -0
- package/template/skills/review/SKILL.md +82 -0
- package/template/skills/testing/SKILL.md +44 -0
- package/template/skills/web-quality-audit/SKILL.md +47 -0
- package/template/skills/web-testing/SKILL.md +120 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: best-practices
|
|
3
|
+
description: "Web application hardening — security headers, CSP, input handling, browser compatibility. Use for any phase preparing a web app for production."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: Best Practices
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
Phase involves web application security, compatibility, or production hardening.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
- [ ] HTTPS everywhere — no mixed HTTP/HTTPS content
|
|
13
|
+
- [ ] Content Security Policy (CSP) header configured
|
|
14
|
+
- [ ] Security headers set: X-Frame-Options, X-Content-Type-Options, Referrer-Policy
|
|
15
|
+
- [ ] No vulnerable dependencies (`npm audit` clean)
|
|
16
|
+
- [ ] Feature detection, not browser detection (`if ('fetch' in window)` not `if (isChrome)`)
|
|
17
|
+
- [ ] Valid HTML5 doctype, charset first in `<head>`
|
|
18
|
+
- [ ] Viewport meta tag present: `<meta name="viewport" content="width=device-width, initial-scale=1">`
|
|
19
|
+
- [ ] Passive event listeners for scroll/touch events
|
|
20
|
+
- [ ] No `innerHTML` with user input — use `textContent` or sanitize
|
|
21
|
+
- [ ] All user input validated + sanitized on both client and server
|
|
22
|
+
|
|
23
|
+
## Common Mistakes
|
|
24
|
+
- Mixed HTTP/HTTPS content → browsers block mixed requests
|
|
25
|
+
- XSS via `innerHTML` or `dangerouslySetInnerHTML` without sanitization
|
|
26
|
+
- Synchronous XHR blocking main thread → use `fetch` with async/await
|
|
27
|
+
- Browser detection (`navigator.userAgent`) → breaks on new browsers, use feature detection
|
|
28
|
+
- Missing security headers → easy attack vectors
|
|
29
|
+
- Using `eval()` or `new Function()` with user input → code injection
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-optimizer
|
|
3
|
+
description: "Performance work — query shape, memory, bundle, hot paths. Use for any phase that optimises existing code rather than adding behaviour."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: Code Optimizer
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
Phase involves performance optimization, refactoring for speed, or audit of existing code performance.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
- [ ] **Database:** N+1 queries eliminated, proper indexes on WHERE/JOIN columns, connection pooling configured
|
|
13
|
+
- [ ] **Memory:** No unbounded caches/arrays, streams used for large data, event listeners cleaned up
|
|
14
|
+
- [ ] **Algorithmic:** No nested loops over large datasets (O(n^2)), use Map/Set for lookups instead of Array.find
|
|
15
|
+
- [ ] **I/O:** Parallel fetch with `Promise.all` where independent, no sequential awaits for unrelated data
|
|
16
|
+
- [ ] **Bundle:** No barrel file imports (`import { x } from './utils'`), use direct imports for tree-shaking
|
|
17
|
+
- [ ] **Dead Code:** Remove unused imports, functions, files — verify with `npx tsc --noEmit` + grep
|
|
18
|
+
- [ ] **Caching:** Expensive computations cached (LRU, memoize), HTTP cache headers set for static assets
|
|
19
|
+
- [ ] **Rendering:** Avoid layout thrashing (batch DOM reads before writes), use `content-visibility: auto` for offscreen content
|
|
20
|
+
|
|
21
|
+
## Common Mistakes
|
|
22
|
+
- Sequential `await` for independent promises → use `Promise.all([a(), b(), c()])`
|
|
23
|
+
- Importing from barrel files (`index.ts` re-exports) → prevents tree-shaking, bloats bundle
|
|
24
|
+
- Array.find/filter in loops → O(n*m), convert to Map/Set for O(1) lookup
|
|
25
|
+
- Missing database indexes on frequently queried columns → full table scans
|
|
26
|
+
- Unbounded in-memory caches → memory leak over time, use LRU with max size
|
|
27
|
+
- Not cleaning up event listeners, intervals, subscriptions → memory leak
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: core-web-vitals
|
|
3
|
+
description: "Frontend performance against LCP, INP and CLS. Use for any phase targeting page experience metrics or a Lighthouse score."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: Core Web Vitals
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
Phase involves frontend performance optimization targeting Google's page experience metrics.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
- [ ] **LCP (Largest Contentful Paint) <= 2.5s:**
|
|
13
|
+
- Preload LCP image with `<link rel="preload" fetchpriority="high">`
|
|
14
|
+
- Inline critical CSS (< 14KB)
|
|
15
|
+
- No render-blocking JavaScript in `<head>` (defer or async)
|
|
16
|
+
- Server response time (TTFB) < 800ms
|
|
17
|
+
- [ ] **INP (Interaction to Next Paint) <= 200ms:**
|
|
18
|
+
- No long tasks (> 50ms) on main thread — break up with `requestIdleCallback` or `scheduler.yield()`
|
|
19
|
+
- Event handlers return quickly — defer heavy work
|
|
20
|
+
- Avoid forced synchronous layouts (read then write DOM, not interleaved)
|
|
21
|
+
- [ ] **CLS (Cumulative Layout Shift) <= 0.1:**
|
|
22
|
+
- All images/videos have explicit `width` and `height` or `aspect-ratio`
|
|
23
|
+
- No content injected above existing content after load
|
|
24
|
+
- Fonts use `font-display: swap` with `size-adjust` to minimize shift
|
|
25
|
+
- Reserve space for dynamic content (ads, embeds, lazy content)
|
|
26
|
+
|
|
27
|
+
## Common Mistakes
|
|
28
|
+
- Images without dimensions → causes layout shift on load
|
|
29
|
+
- Web fonts blocking text rendering → use `font-display: swap`
|
|
30
|
+
- Client-side rendering for LCP element → server-render or prerender it
|
|
31
|
+
- Synchronous third-party scripts in `<head>` → blocks rendering
|
|
32
|
+
- Dynamic banners/modals pushing content down → reserve space or use overlay
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: crud-api
|
|
3
|
+
description: "Creating a resource with standard create/read/update/delete routes. Use for any phase adding a new REST or RPC resource."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: CRUD API
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
Phase involves creating a new resource with standard create/read/update/delete operations.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
- [ ] Define resource schema (Zod or equivalent validation)
|
|
13
|
+
- [ ] Create migration for DB table
|
|
14
|
+
- [ ] Implement endpoints: POST (create), GET (list + detail), PUT/PATCH (update), DELETE
|
|
15
|
+
- [ ] Add input validation on all mutation endpoints
|
|
16
|
+
- [ ] Add pagination on list endpoint (cursor-based preferred over offset)
|
|
17
|
+
- [ ] Add filtering and sorting on list endpoint
|
|
18
|
+
- [ ] Return consistent error format (status code + message + details)
|
|
19
|
+
- [ ] Add proper HTTP status codes: 201 (created), 200 (success), 404 (not found), 422 (validation)
|
|
20
|
+
- [ ] Test all CRUD operations + edge cases (not found, duplicate, invalid input)
|
|
21
|
+
|
|
22
|
+
## Common Mistakes
|
|
23
|
+
- No pagination on list endpoints (will crash with large datasets)
|
|
24
|
+
- Using offset pagination (slow on large tables) → use cursor-based
|
|
25
|
+
- Not validating request body → runtime crashes
|
|
26
|
+
- Returning 200 for everything → use semantic HTTP codes
|
|
27
|
+
- DELETE without checking ownership → authorization bypass
|
|
28
|
+
|
|
29
|
+
## Patterns
|
|
30
|
+
- Schema → Type → Validation → Migration flow
|
|
31
|
+
- Repository pattern for DB access (separate query logic from handler)
|
|
32
|
+
- Consistent error response: `{ error: { code, message, details } }`
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debug
|
|
3
|
+
description: "Investigating a bug whose cause is not obvious — unexpected behaviour, a production incident, a flaky test. Use when the fix is not yet known."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: Debug
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
Phase involves investigating a complex bug, unexpected behavior, or production issue that isn't immediately obvious.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
- [ ] **Document current state:** exact error message, steps to reproduce, expected vs actual behavior
|
|
13
|
+
- [ ] **Map the system:** trace the execution path from input to error — which files, functions, APIs are involved?
|
|
14
|
+
- [ ] **Gather evidence BEFORE hypothesizing:** read logs, check git blame, inspect network requests, check env vars
|
|
15
|
+
- [ ] **Form hypotheses:** list 2-3 possible causes ranked by likelihood
|
|
16
|
+
- [ ] **Test each hypothesis minimally:** change ONE thing, observe result, revert if wrong
|
|
17
|
+
- [ ] **Check external factors:** dependency versions, API changes, environment differences (dev vs prod)
|
|
18
|
+
- [ ] **Verify the fix:** reproduce the original bug, apply fix, confirm it's resolved, check for regressions
|
|
19
|
+
- [ ] **Document root cause:** what happened, why, and what prevents it from recurring
|
|
20
|
+
|
|
21
|
+
## Common Mistakes
|
|
22
|
+
- Assuming the bug is where the error appears → trace upstream, the root cause is often elsewhere
|
|
23
|
+
- Changing multiple things at once → can't tell which change fixed it
|
|
24
|
+
- Not reproducing before fixing → you might fix a different bug
|
|
25
|
+
- Treating your own code with less skepticism → YOUR code is the most likely source
|
|
26
|
+
- Proposing fixes without evidence → "I think it might be X" without testing is guessing
|
|
27
|
+
- Not checking if the bug exists in other environments → might be env-specific
|
|
28
|
+
- Fixing the symptom, not the cause → bug will return in a different form
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deployment
|
|
3
|
+
description: "Getting a service to production and back again — health, release gating, smoke, rollback, migrations. Use for any phase that touches CI/CD, containers, environment configuration, or a deploy."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: Deployment
|
|
7
|
+
|
|
8
|
+
Implements `.claude/rules/observability.orchestra.md`. Read it first; this is
|
|
9
|
+
the working checklist.
|
|
10
|
+
|
|
11
|
+
## The fact everything else follows from
|
|
12
|
+
|
|
13
|
+
**Nothing here protects a release except being able to undo it.**
|
|
14
|
+
|
|
15
|
+
There is no percentage canary on the platforms this stack targets. What
|
|
16
|
+
stands between a broken build and every user is three things, in order: the
|
|
17
|
+
healthcheck that decides whether the new deployment is promoted, a smoke test
|
|
18
|
+
against the real URL afterwards, and putting the last good commit back when
|
|
19
|
+
that smoke fails.
|
|
20
|
+
|
|
21
|
+
Rollback is the same path as a normal deploy, deliberately. An untested
|
|
22
|
+
recovery path is not a recovery path.
|
|
23
|
+
|
|
24
|
+
## Health is two endpoints
|
|
25
|
+
|
|
26
|
+
| Endpoint | Question | Cost | Fails when |
|
|
27
|
+
|---|---|---|---|
|
|
28
|
+
| `/health` | is the process up? | no dependencies | it doesn't answer |
|
|
29
|
+
| `/ready` | can it serve? | probes every dependency | **503**, naming the one that failed |
|
|
30
|
+
|
|
31
|
+
The platform healthcheck points at **`/ready`**. This is load-bearing: the
|
|
32
|
+
previous deployment keeps serving until the new one answers 200, so a
|
|
33
|
+
readiness probe that returns 200 with an unreachable database does not
|
|
34
|
+
mislead a dashboard — it promotes a broken release.
|
|
35
|
+
|
|
36
|
+
- [ ] `/ready` probes every dependency the service cannot serve without
|
|
37
|
+
- [ ] it answers 503 and names the failed dependency, not a bare status
|
|
38
|
+
- [ ] there is a test that **makes it fail** — a probe that cannot fail is
|
|
39
|
+
worse than none
|
|
40
|
+
- [ ] adding a dependency adds its probe and its failing test in the same
|
|
41
|
+
change
|
|
42
|
+
- [ ] `healthcheckPath` in the platform config points at `/ready`, not
|
|
43
|
+
`/health`
|
|
44
|
+
|
|
45
|
+
## Releasing
|
|
46
|
+
|
|
47
|
+
- [ ] deploy is gated on the healthcheck, with an overlap window so the old
|
|
48
|
+
instance drains rather than being cut
|
|
49
|
+
- [ ] a smoke test runs against the deployed URL, not against localhost
|
|
50
|
+
- [ ] the smoke failing triggers rollback, and the rollback is exercised
|
|
51
|
+
- [ ] the `last-good-deploy` tag moves **only after the smoke passes** — so
|
|
52
|
+
it always names a release observed working, never one that merely
|
|
53
|
+
deployed
|
|
54
|
+
- [ ] release and commit sha reach the error monitor and every log line
|
|
55
|
+
|
|
56
|
+
## Environment
|
|
57
|
+
|
|
58
|
+
- [ ] every variable is read through one validating schema, and boot fails
|
|
59
|
+
loudly when a required one is missing
|
|
60
|
+
- [ ] `.env.example` is **generated from that schema**, never written beside
|
|
61
|
+
it — a hand-kept example is wrong the first time somebody forgets, and
|
|
62
|
+
a new engineer trusts it anyway
|
|
63
|
+
- [ ] `.env` gitignored, always
|
|
64
|
+
- [ ] a secret that was ever committed is rotated; deleting the commit is not
|
|
65
|
+
the fix
|
|
66
|
+
|
|
67
|
+
## Migrations
|
|
68
|
+
|
|
69
|
+
- [ ] run automatically on deploy, never by hand
|
|
70
|
+
- [ ] forward-compatible with the previous release, because both run at once
|
|
71
|
+
during the overlap window
|
|
72
|
+
- [ ] a destructive change is two deploys: stop using the column, then drop
|
|
73
|
+
it
|
|
74
|
+
|
|
75
|
+
## Containers
|
|
76
|
+
|
|
77
|
+
- [ ] multi-stage build, runtime stage carries no build tooling
|
|
78
|
+
- [ ] non-root user
|
|
79
|
+
- [ ] `.dockerignore` covers `node_modules`, `.git`, test output
|
|
80
|
+
- [ ] SIGTERM drains in-flight requests before exit — the overlap window is
|
|
81
|
+
wasted if the process dies instantly
|
|
82
|
+
|
|
83
|
+
## Feature flags
|
|
84
|
+
|
|
85
|
+
A risky change ships dark. The lookup must never be able to take the service
|
|
86
|
+
down: bounded by a timeout, failures reported and answered with the flag's
|
|
87
|
+
own fallback rather than thrown into a handler. For a kill switch the
|
|
88
|
+
fallback is **false** — if we cannot ask whether a risky path is allowed, the
|
|
89
|
+
answer is no.
|
|
90
|
+
|
|
91
|
+
Flags live in one typed registry. A string literal at a call site is how they
|
|
92
|
+
rot.
|
|
93
|
+
|
|
94
|
+
## Common mistakes
|
|
95
|
+
|
|
96
|
+
- **A readiness probe that returns a constant.** It passes review, passes
|
|
97
|
+
CI, and promotes a release with a dead database.
|
|
98
|
+
- Pointing the platform healthcheck at `/health`. Liveness answers yes while
|
|
99
|
+
nothing works.
|
|
100
|
+
- Rolling back by hand through a dashboard. The path nobody scripted is the
|
|
101
|
+
path nobody can run at 3am.
|
|
102
|
+
- Tagging the deploy as good when it deployed, rather than when it was
|
|
103
|
+
observed working.
|
|
104
|
+
- Secrets in the image, or in a build argument, which is the same thing.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: error-handling
|
|
3
|
+
description: "What to do when something fails — typed errors, propagation, what the user sees, and degrading instead of crashing. Use for any phase that adds a failure path, a catch, or an error response."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: Error Handling
|
|
7
|
+
|
|
8
|
+
The rule is in `.claude/rules/observability.orchestra.md` and a check
|
|
9
|
+
enforces it: **a catch either handles the error meaningfully or reports it and
|
|
10
|
+
rethrows.** `scripts/policy-check.mjs` fails the gate on an empty catch and on
|
|
11
|
+
a catch whose only body is a log.
|
|
12
|
+
|
|
13
|
+
That check proves a catch is not empty. It cannot tell whether the user got a
|
|
14
|
+
correct outcome. This skill is about the part that needs a person.
|
|
15
|
+
|
|
16
|
+
## The fact everything else follows from
|
|
17
|
+
|
|
18
|
+
**"Handled" means the caller gets a correct outcome — not that the crash was
|
|
19
|
+
hidden.**
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
try {
|
|
23
|
+
await chargeCard(order);
|
|
24
|
+
} catch (e) {
|
|
25
|
+
reportError(e);
|
|
26
|
+
return { ok: true }; // the gate passes. the customer was not charged.
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Reported, rethrown-shaped, and wrong. Nothing downstream can tell the
|
|
31
|
+
difference between a payment that succeeded and one that vanished. Deciding
|
|
32
|
+
which of those two this is, is the entire job.
|
|
33
|
+
|
|
34
|
+
## Three kinds of failure, three different answers
|
|
35
|
+
|
|
36
|
+
| Kind | Example | Answer |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| **Expected** | invalid input, not found, conflict | Not exceptional. Return it as a value or throw a typed error the boundary maps to a status. |
|
|
39
|
+
| **Transient** | timeout, 503 from a provider, deadlock | Retry if idempotent, with backoff and a bound. Then give up deliberately. |
|
|
40
|
+
| **A bug** | undefined is not a function, a broken invariant | Do not catch it here. Let it reach the boundary, be reported with its stack, and answer 500. |
|
|
41
|
+
|
|
42
|
+
The most common mistake is treating the third as the first: a broad `catch`
|
|
43
|
+
around a whole handler turns every bug into a polite message and the defect
|
|
44
|
+
is never seen again.
|
|
45
|
+
|
|
46
|
+
## Typed at the boundary
|
|
47
|
+
|
|
48
|
+
The backend stack ships `AppError` with a closed `ErrorCode` union, and
|
|
49
|
+
`toErrorBody` maps it to a status and a body. Use it.
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
throw new AppError("not_found", "Order not found");
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- **Never throw a bare `Error` across a route boundary.** It becomes a 500,
|
|
56
|
+
which tells the caller nothing and pages someone for a 404.
|
|
57
|
+
- **Never let internal detail into the response.** `toErrorBody` returns the
|
|
58
|
+
minimum for anything unrecognised, deliberately — a stack trace in a body
|
|
59
|
+
is an information leak, and the message often contains a query.
|
|
60
|
+
- The code is a **closed union**, not a string. A new failure mode is a new
|
|
61
|
+
member and a new status, decided once, rather than a literal invented at a
|
|
62
|
+
call site.
|
|
63
|
+
|
|
64
|
+
Adding a code is a real decision: it is part of the API contract, and a
|
|
65
|
+
client will branch on it.
|
|
66
|
+
|
|
67
|
+
## Validate once, at the edge
|
|
68
|
+
|
|
69
|
+
Parse input at the boundary and let everything inside work with a type that
|
|
70
|
+
cannot be invalid. A function that re-checks its arguments is a function that
|
|
71
|
+
does not trust its own signature — and the check will disagree with the
|
|
72
|
+
schema eventually.
|
|
73
|
+
|
|
74
|
+
That is why the boundary owns validation and the interior does not:
|
|
75
|
+
`.claude/rules/security.orchestra.md` puts it in the same place for the same
|
|
76
|
+
reason.
|
|
77
|
+
|
|
78
|
+
## Keep the cause
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
throw new AppError("internal", "could not load order"); // no
|
|
82
|
+
throw new Error("could not load order", { cause: original }); // yes
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Wrapping is fine; discarding is not. The original stack is the only thing
|
|
86
|
+
that says which line failed. When you rethrow, carry the cause; when you
|
|
87
|
+
report, report the cause too.
|
|
88
|
+
|
|
89
|
+
## What the user sees
|
|
90
|
+
|
|
91
|
+
Two audiences, two texts, and they are rarely the same string.
|
|
92
|
+
|
|
93
|
+
- **The user** gets something actionable: what happened, and what they can do.
|
|
94
|
+
Not an error code alone, and never a stack.
|
|
95
|
+
- **The operator** gets the detail, in the log, with the correlation id — so
|
|
96
|
+
a user quoting `x-request-id` from a bug report leads straight to the line.
|
|
97
|
+
The request logger echoes that header back for exactly this reason.
|
|
98
|
+
|
|
99
|
+
If a screen can fail, it has a failure state, and the failure state has a way
|
|
100
|
+
forward. `.claude/skills/review/SKILL.md` treats a missing one as a finding.
|
|
101
|
+
|
|
102
|
+
## Degrading instead of failing
|
|
103
|
+
|
|
104
|
+
Some dependencies are not required to answer. Say so explicitly, and say what
|
|
105
|
+
the answer is without them.
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
// Recommendations are a nice-to-have; the page renders without them.
|
|
109
|
+
const recommended = await getRecommendations(userId).catch((e) => {
|
|
110
|
+
report(e);
|
|
111
|
+
return [];
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
This is the one place an error is swallowed, and it carries a comment saying
|
|
116
|
+
why failure is acceptable — the exception named in the observability rule.
|
|
117
|
+
Two conditions, both required:
|
|
118
|
+
|
|
119
|
+
1. The feature is genuinely optional to the outcome.
|
|
120
|
+
2. The failure is still **reported**, so "optional" does not quietly become
|
|
121
|
+
"permanently broken".
|
|
122
|
+
|
|
123
|
+
For anything gating a risky path the fallback is **false** — the same
|
|
124
|
+
direction the feature-flag registry falls, and for the same reason.
|
|
125
|
+
|
|
126
|
+
## Failure paths are tested, not assumed
|
|
127
|
+
|
|
128
|
+
- Every catch you write has a test that reaches it. An untested error path is
|
|
129
|
+
usually a broken error path — it is the code least likely to have been run
|
|
130
|
+
even once.
|
|
131
|
+
- Provider failures are faked **at the HTTP boundary**, never by mocking your
|
|
132
|
+
own wrapper: the wrapper is where a provider's change bites you, so mocking
|
|
133
|
+
it tests nothing. `.claude/rules/testing-standards.orchestra.md`.
|
|
134
|
+
- The cases worth writing: a 500 from the provider, a timeout, a malformed
|
|
135
|
+
body, and the retry that eventually gives up.
|
|
136
|
+
|
|
137
|
+
Coverage will not tell you these exist. Mutation testing would, which is why
|
|
138
|
+
it is wired even while it waits on the compiler.
|
|
139
|
+
|
|
140
|
+
## Anti-patterns
|
|
141
|
+
|
|
142
|
+
- **`catch (e) { report(e) }` in a write path.** The caller now believes the
|
|
143
|
+
write happened.
|
|
144
|
+
- **Catching to convert everything to `null`.** The caller has no idea
|
|
145
|
+
whether "nothing" means empty or broken.
|
|
146
|
+
- **One broad try/catch wrapping an entire handler.** It catches your bugs
|
|
147
|
+
along with the expected failures, and turns both into the same response.
|
|
148
|
+
- **Retrying a non-idempotent write.** This is how a customer gets charged
|
|
149
|
+
twice.
|
|
150
|
+
- **A message that names the wrong actor.** "Something went wrong" when the
|
|
151
|
+
input was invalid sends the user looking in the wrong place.
|
|
152
|
+
- **Logging and rethrowing at every level.** One failure, six lines, and none
|
|
153
|
+
of them the one with the stack. Report where you handle it, not on the way
|
|
154
|
+
past.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-design
|
|
3
|
+
description: "Building UI that looks deliberate rather than generic — typography, colour, spacing, motion. Use for any phase where visual quality is part of the acceptance criteria."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: Frontend Design
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
Phase involves building UI that needs to look polished, professional, and distinctive — not generic.
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
- [ ] **Bold aesthetic direction:** commit to a clear visual concept — not timid, not generic
|
|
13
|
+
- [ ] **Distinctive typography:** avoid overused fonts (Inter, Roboto, Arial) — choose fonts with character
|
|
14
|
+
- [ ] **Cohesive color scheme:** limited palette (3-5 colors) with sharp accent colors
|
|
15
|
+
- [ ] **Intentional layout:** use asymmetry, overlap, or diagonal elements where appropriate — not everything grid-aligned
|
|
16
|
+
- [ ] **Layered shadows:** multiple transparent shadows instead of solid borders (`box-shadow: 0 1px 2px rgba(0,0,0,0.1), 0 4px 12px rgba(0,0,0,0.05)`)
|
|
17
|
+
- [ ] **Concentric border radius:** outer radius = inner radius + padding (nested elements)
|
|
18
|
+
- [ ] **Micro-interactions:** hover states, focus transitions, loading animations — all < 300ms
|
|
19
|
+
- [ ] **Staggered enter animations:** split elements, ~100ms delay between each
|
|
20
|
+
- [ ] **Font smoothing:** `-webkit-font-smoothing: antialiased` for crisp text
|
|
21
|
+
- [ ] **Tabular numbers:** `font-variant-numeric: tabular-nums` for data tables and counters
|
|
22
|
+
- [ ] **Optical alignment:** icons and text optically centered, not geometrically
|
|
23
|
+
|
|
24
|
+
## Common Mistakes
|
|
25
|
+
- Generic AI-slop aesthetics → every AI tool produces the same look, be distinctive
|
|
26
|
+
- Solid borders everywhere → layered transparent shadows look more refined
|
|
27
|
+
- Geometric centering for icons → optical centering looks correct to the eye
|
|
28
|
+
- Harsh easing functions → use `cubic-bezier(0.4, 0, 0.2, 1)` for natural motion
|
|
29
|
+
- Missing exit animations → enter with animation, exit abruptly looks broken
|
|
30
|
+
- System fonts without thought → typography is 80% of visual quality
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fullstack-infrastructure
|
|
3
|
+
description: "TypeScript and React conventions that hold in any app — types, hooks, rendering, data flow, performance, i18n. Which libraries, which structure and which tooling are decided by .orchestra/stacks/, not here. Use when writing TypeScript or React in any app."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TypeScript & React Conventions
|
|
7
|
+
|
|
8
|
+
What is true regardless of which stack scaffolded the app.
|
|
9
|
+
|
|
10
|
+
## What this file does not decide
|
|
11
|
+
|
|
12
|
+
It used to carry a tech stack table and a monorepo tree of its own, naming an
|
|
13
|
+
ORM, an auth scheme, an HTTP client and a component kit. Every one of those is
|
|
14
|
+
decided somewhere that can enforce it, and a skill restating a choice is a
|
|
15
|
+
second source of truth: whichever the agent reads last wins, and nothing
|
|
16
|
+
notices when they drift apart.
|
|
17
|
+
|
|
18
|
+
| Question | Answered by |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Which libraries, package manager, tooling | `.orchestra/stacks/<stack>/setup.sh` — it installs them |
|
|
21
|
+
| Where a new file goes | `.claude/skills/project-structure/SKILL.md` |
|
|
22
|
+
| Where a component comes from | the web `stack.md`, and `src/components/README.md` |
|
|
23
|
+
| What "handled" means for an error | `.claude/skills/error-handling/SKILL.md` |
|
|
24
|
+
| Testing, commits, security, observability | `.claude/rules/*.orchestra.md` |
|
|
25
|
+
|
|
26
|
+
What the stacks scaffold today, for orientation only: Drizzle rather than
|
|
27
|
+
Prisma, server-side sessions rather than JWT, `fetch` in
|
|
28
|
+
`src/integrations/<provider>/` rather than an Axios wrapper class, feature-first
|
|
29
|
+
`src/features/<domain>/` rather than a layer-first tree.
|
|
30
|
+
|
|
31
|
+
**If this file ever disagrees with a stack, the stack is right** — it is the
|
|
32
|
+
thing that actually ran.
|
|
33
|
+
|
|
34
|
+
## TypeScript
|
|
35
|
+
|
|
36
|
+
- `strict`, with no per-file exemptions.
|
|
37
|
+
- No `any`. Use `unknown` and narrow it — `any` disables the checker at
|
|
38
|
+
exactly the boundary you added it to guard.
|
|
39
|
+
- `interface` for object shapes, `type` for unions and intersections.
|
|
40
|
+
- Discriminated unions for anything with states. A boolean pair that can
|
|
41
|
+
express `loading && error` is a bug waiting for a screenshot.
|
|
42
|
+
- Explicit return types on exported functions. Inference is fine inside a
|
|
43
|
+
module and a liability across one — a return type that changes silently is
|
|
44
|
+
a breaking change nobody reviewed.
|
|
45
|
+
- Prefer a union of literals to an enum. It erases at compile time and
|
|
46
|
+
narrows without an import.
|
|
47
|
+
|
|
48
|
+
## React
|
|
49
|
+
|
|
50
|
+
- Function components only.
|
|
51
|
+
- Custom hooks are prefixed `use` — the linter's rules-of-hooks check keys
|
|
52
|
+
off the name, so a mis-named hook is simply unchecked.
|
|
53
|
+
- `useMemo` and `useCallback` where a measurement says they help. Applied by
|
|
54
|
+
reflex they add allocation and a dependency array to get wrong.
|
|
55
|
+
- Composition over prop drilling. Context for what is genuinely ambient
|
|
56
|
+
(theme, locale, session), not to avoid passing two props.
|
|
57
|
+
- Stable keys from the data. An array index makes React reuse the wrong node
|
|
58
|
+
the first time the list reorders, and the bug looks like corrupted state.
|
|
59
|
+
- `React.lazy` with `Suspense` at route boundaries.
|
|
60
|
+
|
|
61
|
+
## Data flow
|
|
62
|
+
|
|
63
|
+
- **Server cache and client state are different things.** Copying a response
|
|
64
|
+
into a client store gives you two truths and a stale one.
|
|
65
|
+
- Every backend call goes through a wrapper in `src/integrations/<provider>/`
|
|
66
|
+
— never a raw client call from a component. That is where the timeout, the
|
|
67
|
+
retry bound and the error mapping live, and it is the only place a test can
|
|
68
|
+
hold. See `.claude/skills/project-structure/SKILL.md`.
|
|
69
|
+
- Which cache or store library, if any, is the stack's decision. If a project
|
|
70
|
+
adopts one, it goes in the stack's `setup.sh` so it is installed and
|
|
71
|
+
covered — not named here.
|
|
72
|
+
|
|
73
|
+
## Classes vs functions
|
|
74
|
+
|
|
75
|
+
**Class** when there is lifecycle to hold: an SDK that needs init and
|
|
76
|
+
teardown, or shared configuration across calls.
|
|
77
|
+
**Function** when it is stateless and single-purpose — `formatDate`,
|
|
78
|
+
`slugify`.
|
|
79
|
+
|
|
80
|
+
Prefer writing a small utility to adding a dependency for it. Reach for a
|
|
81
|
+
package when the implementation is genuinely hard — dates, time zones,
|
|
82
|
+
collation — not when it is twelve lines.
|
|
83
|
+
|
|
84
|
+
## Performance
|
|
85
|
+
|
|
86
|
+
- Lazy load routes and anything heavy below the fold.
|
|
87
|
+
- Virtualize long lists.
|
|
88
|
+
- Debounce or throttle high-frequency events at the source, not in the
|
|
89
|
+
handler.
|
|
90
|
+
- Derive loading and error state from the request, not from booleans set by
|
|
91
|
+
hand in three places.
|
|
92
|
+
|
|
93
|
+
## Environment variables
|
|
94
|
+
|
|
95
|
+
Validated at startup against a schema, so the process refuses to boot on bad
|
|
96
|
+
configuration rather than failing on the first request that needs it.
|
|
97
|
+
|
|
98
|
+
`.env.example` is **generated from that schema**, never written beside it —
|
|
99
|
+
see `.claude/rules/security.orchestra.md`.
|
|
100
|
+
|
|
101
|
+
## i18n
|
|
102
|
+
|
|
103
|
+
Ask whether it is needed before the first string is written; retrofitting
|
|
104
|
+
means touching every component.
|
|
105
|
+
|
|
106
|
+
When it is: every user-facing string is a key, namespaced by feature. No
|
|
107
|
+
concatenated sentences — word order is not universal, and a sentence built
|
|
108
|
+
from three fragments cannot be translated correctly into most languages.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ios-testing
|
|
3
|
+
description: "Testing strategy for native iOS apps — Swift, SwiftUI, XCTest and XCUITest. Use for any phase that writes or changes tests in a native iOS app."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: iOS Testing
|
|
7
|
+
|
|
8
|
+
## The fact everything else follows from
|
|
9
|
+
|
|
10
|
+
**A unit test does not prove the app launches.**
|
|
11
|
+
|
|
12
|
+
An iOS app dies for reasons no XCTest sees: a missing Info.plist key, an
|
|
13
|
+
entitlement the provisioning profile lacks, a `@main` that throws before the
|
|
14
|
+
first view, a bundle resource that was never copied. The suite is green and
|
|
15
|
+
the app crashes on the splash screen.
|
|
16
|
+
|
|
17
|
+
So the launch test is not the top of a pyramid you get to later. It is the
|
|
18
|
+
first test worth writing.
|
|
19
|
+
|
|
20
|
+
## The layers
|
|
21
|
+
|
|
22
|
+
| Layer | What belongs here | Runs on |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| Unit | Pure logic and view models — no UIKit, no SwiftUI | Host, fast |
|
|
25
|
+
| View | SwiftUI views: state transitions and the accessibility tree | Simulator |
|
|
26
|
+
| Integration | The real networking stack, stubbed at the transport | Simulator |
|
|
27
|
+
| UI (XCUITest) | 3–5 journeys, one of them launch | Real simulator |
|
|
28
|
+
| Build | `xcodebuild` for a device architecture | The gate |
|
|
29
|
+
|
|
30
|
+
## Stub the transport, not your client
|
|
31
|
+
|
|
32
|
+
```swift
|
|
33
|
+
final class StubProtocol: URLProtocol { /* … */ }
|
|
34
|
+
|
|
35
|
+
let config = URLSessionConfiguration.ephemeral
|
|
36
|
+
config.protocolClasses = [StubProtocol.self]
|
|
37
|
+
let session = URLSession(configuration: config)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Register a `URLProtocol` subclass and the real `URLSession` runs — your
|
|
41
|
+
request building, your headers, your decoding, your error mapping.
|
|
42
|
+
|
|
43
|
+
Injecting a `MockAPIClient` instead tests the mock. The client is the thing
|
|
44
|
+
that breaks when the API changes, so it is the thing that must stay in the
|
|
45
|
+
test.
|
|
46
|
+
|
|
47
|
+
## Query the accessibility tree
|
|
48
|
+
|
|
49
|
+
```swift
|
|
50
|
+
app.buttons["Add water"].tap() // yes — the accessible name
|
|
51
|
+
app.buttons["btn_add_water"].tap() // no — an identifier nobody hears
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
XCUITest resolves elements through the accessibility tree, which is the same
|
|
55
|
+
tree VoiceOver uses. Query by label and **a control with no accessible name
|
|
56
|
+
fails the test** — accessibility becomes something the suite enforces.
|
|
57
|
+
|
|
58
|
+
Use `accessibilityIdentifier` only where the visible label genuinely changes
|
|
59
|
+
with locale or data, and keep the label correct anyway.
|
|
60
|
+
|
|
61
|
+
## Swift Testing for units, XCTest for UI
|
|
62
|
+
|
|
63
|
+
`import Testing` with `@Test` and `#expect` is the current framework for unit
|
|
64
|
+
and view tests — clearer failures, real parameterised cases, native async.
|
|
65
|
+
|
|
66
|
+
XCUITest is still XCTest. Do not try to unify them.
|
|
67
|
+
|
|
68
|
+
Both need `await` discipline: a `@MainActor` view model tested from a
|
|
69
|
+
non-isolated context passes locally and races in CI.
|
|
70
|
+
|
|
71
|
+
## Never
|
|
72
|
+
|
|
73
|
+
- **Snapshot tests as the main assertion.** A recorded PNG changes with every
|
|
74
|
+
OS point release, gets re-recorded without being read, and passes while the
|
|
75
|
+
button does nothing. Assert state and the accessibility tree instead.
|
|
76
|
+
- Testing that SwiftUI re-renders, or that `NavigationStack` navigates.
|
|
77
|
+
Assert that the action fires with the right argument.
|
|
78
|
+
- Sleeping to wait. `XCTestExpectation` and `waitForExistence(timeout:)`
|
|
79
|
+
exist; a `sleep` is a flake with a delay.
|
|
80
|
+
- A simulator-only definition of done. The simulator has no memory pressure,
|
|
81
|
+
no thermal throttling, no real camera and a different keyboard.
|
|
82
|
+
|
|
83
|
+
## The build is part of the suite
|
|
84
|
+
|
|
85
|
+
Build for a **device** architecture in the gate, not only the simulator.
|
|
86
|
+
Simulator builds are x86/arm64-host and skip code signing, so a missing
|
|
87
|
+
entitlement, an unsupported architecture or a bad bitcode setting only
|
|
88
|
+
appears when a real build is attempted.
|
|
89
|
+
|
|
90
|
+
A release build additionally runs optimisation and dead-code stripping,
|
|
91
|
+
which is where `#if DEBUG` mistakes surface.
|
|
92
|
+
|
|
93
|
+
## Release risk
|
|
94
|
+
|
|
95
|
+
An App Store release cannot be rolled back. There is no equivalent of an
|
|
96
|
+
over-the-air JavaScript update unless one was deliberately built.
|
|
97
|
+
|
|
98
|
+
That makes phased release and a server-side kill switch part of the testing
|
|
99
|
+
strategy rather than an operational afterthought — see
|
|
100
|
+
`.claude/rules/observability.orchestra.md`.
|