Tech employee playbook · day one
Welcome to criisp.fm
You are joining the team that builds a browser mix-revision deck: sample-locked A/B, a cassette shelf, and timestamped mix notes. This page is the getting-started guide — tools, Scrum, and the commands we actually run.
Day-one checklist
- Install Cursor (Mac Universal) and Node.js 22 LTS
- Ask Garett to invite you to the private repo garettwoolley/criisp-fm
- Clone, install, run — commands are in IDE setup
- Open the live Scrum board: Sprint 1 milestone (public) · after access, product Sprint 1
- Walk DEMO.md once on localhost:3000
-
Run
npm run lint,npm test,npm run audit -
Read the always-on Cursor rule
.cursor/rules/criisp.mdc
1. Language selection
We write the product in TypeScript (strict) on React 19 and Next.js 16 App Router, with Tailwind CSS v4 and Zustand for deck state. Audio is vanilla Web Audio — not a React library.
| Choice | Why this team uses it |
|---|---|
TypeScript
· strict: true in
tsconfig.json
|
Timecodes, version ids, and pin threads are easy to break with
implicit any. One language for UI and logic — we
are a one-engineer startup.
|
| Next.js 16.3.8 App Router | Default path to Vercel when sharing ships. We patched to 16.3.8 for GHSA-vcvr-r3jv-pc5j (next/og RCE). |
Web Audio in
lib/audio/deck-engine.ts
|
AudioContext is a process singleton. React must
not own it. A/B uses a 3ms equal-power crossfade.
|
We do not use Python, Go, or a separate API repo. There is no backend in the MVP. Mix files never leave the browser tab.
2. IDE selection and setup
The team IDE is Cursor. Download the Mac build from the official page (not a random mirror):
https://cursor.com/download → macOS → Universal
Setup (do this in order)
- Install Cursor and sign in (Agent will not run without it).
-
File → Open Folder → the
criisp-fmclone (not the parentcriispfolder). -
Install the recommended extensions when prompted:
Prettier
and
ESLint. They are listed in
.vscode/extensions.json. -
Confirm format-on-save. We already checked this in
.vscode/settings.json:editor.defaultFormatter = esbenp.prettier-vscodeand ESLint fix on save. - Terminal:
git clone https://github.com/garettwoolley/criisp-fm.git
cd criisp-fm
git checkout v2
npm install
npm run dev
App: http://localhost:3000 · this playbook locally: http://localhost:3000/playbook
VS Code is allowed only if GitHub Copilot and other agents are off. Approved AI is Cursor Tab + Cursor Agent in this repo — see §6. We do not mix agent products.
3. Development strategy — Scrum
We run Scrum, not Kanban. That is a process choice, not a tooling accident. The product is a web MVP, but we still want a frozen sprint goal so interview insights do not thrash the deck mid-week. New learning goes on the Product Backlog and waits for the next Sprint Planning (class: changes during a sprint are discouraged).
Roles (class: Product Owner, Development Team, Scrum Master)
| Role | Who | Does |
|---|---|---|
| Product Owner | Garett Woolley | Orders the Product Backlog, names the Sprint Goal, accepts work in the Sprint Review. |
| Scrum Master | Garett Woolley (until hire #3) | Protects the sprint from mid-stream scope, runs the five meetings, keeps WIP honest. When the team is three people, the new engineer takes Scrum Master so PO and SM are not the same person. |
| Development Team | Every engineer writing code, including you | No sub-roles. You pull from the Sprint Backlog, open a PR, and get the item to Definition of Done. |
Cadence
- Sprint length: 1 week, Monday 09:00 MT → Friday 16:00 MT.
- Current sprint: Sprint 1 — Oct 13–17, 2026 (due 17 Oct 2026). Same milestone on the private product repo after you are invited: criisp-fm/milestone/1.
- Sprint 1 Goal: a new engineer can clone the repo, run the quality gate, and find committed work on the board.
- Estimate: Fibonacci 1 / 2 / 3 / 5 / 8. Sprint 1 capacity is 8 points (playbook 5 + CI 3).
- Scope freeze: if a user interview on Wednesday changes our mind, it becomes a Product Backlog item for Sprint 2. We do not add it to Sprint 1.
Meetings (class: the five Scrum events)
| Event | When (Mountain Time) | How we run it |
|---|---|---|
| Backlog Grooming | Friday 14:00–14:30 | PO + Dev Team. Refine stories with the user-story template. Ready means acceptance criteria + points. |
| Sprint Planning | Friday 14:30–15:00 (or Mon 09:00) | PO states the Sprint Goal. Team pulls a batch onto the milestone — not a Kanban one-by-one pull. That batch is the Sprint Backlog. |
| Daily Scrum | 09:30–09:45, every weekday | 15 minutes. Yesterday / today / blocked. When you are the only engineer, post the three lines on the sprint milestone before 09:45. Zoom when two or more people are staffed. |
| Sprint Review | Friday 15:00–15:30 | Demo using DEMO.md. PO accepts or sends the story back. No slides. |
| Sprint Retrospective | Friday 15:30–16:00 | What helped the Sprint Goal, what blocked it, one process change for next week. Write the change as a backlog item if it is work. |
Definition of Done
- Issue is on the current sprint milestone
-
PR into
v2(untilv2merges tomain) -
CI green: lint, Prettier, Vitest,
npm audit --omit=dev, build - Review from CODEOWNERS (
@garettwoolley) - If you touched the deck, DEMO.md still plays
- Feature branch deleted after squash-merge
4. Git strategy and controls
Branching is GitHub Flow (class: short-lived
feature branch → pull request → main; best fit for
SaaS / startups). We are not running Git Flow —
there is no develop, release-*, or
hotfix-* branch.
Reality check: production-ready history lives on
main. The live product line is v2 until
that work is merged. Branch every story off v2
until the Scrum Master says otherwise.
git checkout v2
git pull origin v2
git checkout -b feat/persist-shelf
# ... commits ...
git push -u origin HEAD
gh pr create --base v2 --title "feat(shelf): persist cassettes in OPFS"
Commit convention
Conventional Commits, imperative, scoped:
feat(deck): drag cassette into the candidate well
fix(audio): keep A/B crossfade at 3ms equal-power
docs(playbook): add Sprint Review time
test(timecode): clamp negative seconds to zero
chore(deps): bump next to 16.3.8
Review / approval controls
-
Do not commit to
mainorv2directly. -
One approving review from
.github/CODEOWNERS
(
@garettwoolley). -
CI on every PR:
.github/workflows/ci.yml(lint, format, test, audit, build). -
Use the PR template
.github/PULL_REQUEST_TEMPLATE.md— paste the issue URL. - Squash merge. Delete the branch.
-
Never force-push
mainorv2. Never commit.env*, mix wav/aiff files, or API keys. -
Pre-commit hook (Husky) runs
npx lint-staged— Prettier + ESLint on staged files. Do not skip hooks (--no-verify) unless the Scrum Master agrees in the Daily Scrum.
5. Issue tracking
Tool: GitHub Issues. A sprint is a milestone. Columns are labels matching the class Scrum board (Product Backlog / Sprint Backlog / In Progress / Blocked / Done).
Live Sprint 1 board (open this): https://github.com/garettwoolley/criisp-fm-playbook/milestone/1
The product repo is private, so the public playbook repo carries the board a classmate or professor can open without an invite. After you are added to garettwoolley/criisp-fm, use the same Sprint 1 there: https://github.com/garettwoolley/criisp-fm/milestone/1.
Sprint Backlog
Empty — Sprint 1’s batch is already In Progress (planning pulled both Goal items).
Blocked
None.
File new work with New issue → User story. Do not drop work onto In Progress yourself during the week — that is a sprint change. Raise it in Daily Scrum; the PO parks it on the Product Backlog.
6. AI agents and controls
We are at class Stage 2: agents help us develop, with different jobs, inside one product (Cursor). We are not Stage 3 (cost-routed fleet wired to logs).
| Approved | Not approved |
|---|---|
| Cursor Tab (autocomplete) | GitHub Copilot, Windsurf, Replit Agent on this repo |
Cursor Agent / Composer, working tree = criisp-fm |
Pasting mix files, interview PII, or .env values into any model |
| Cursor Ask for “why does this fail?” | Merging an agent PR you have not read |
How to use Agent on a sprint item
-
Inspect / Plan (higher care): paste the GitHub
issue URL, ask Agent to read
DEMO.mdand.cursor/rules/criisp.mdcbefore it edits. -
Implementation: Agent writes the diff. You stay
on a
feat/…branch. -
Test / verification: Agent must run
npm testandnpm run lint. If it did not, you do. - Code review: you re-read every hunk. Say so in the PR template’s Agent notes.
The always-apply Cursor rule is
.cursor/rules/criisp.mdc. Hard lines: no backend unless
the ticket says so; no AudioContext in React state;
hardware colors
#F8F5F0 / #111215 /
#FF4800; rounded-none on chassis controls.
7. Code quality
| Control | Exact setup | Command |
|---|---|---|
| Linter |
ESLint 9 flat config:
eslint-config-next/core-web-vitals +
eslint-config-next/typescript +
eslint-config-prettier. File:
eslint.config.mjs.
|
npm run lint |
| Formatter |
Prettier 3.9 ·
.prettierrc.json (semicolons, double quotes,
trailing commas, print width 80). Format on save in Cursor.
|
npm run format (check) ·
npm run format:write
|
| Pre-commit |
Husky .husky/pre-commit →
npx lint-staged (Prettier +
eslint --max-warnings=0 on staged files).
|
runs on git commit |
| Vulnerability scan |
npm audit --omit=dev in CI. Next.js is on
16.3.8 for the next/og RCE. Remaining
braces advisory is in the ESLint plugin tree —
tracked as
issue #7. We will not
npm audit fix --force (it downgrades to Next 14).
|
npm run audit |
| CI |
GitHub Actions
.github/workflows/ci.yml on pull requests and on
push to main / v2. Node 22.
|
must be green to merge |
8. Testing frameworks
Class listed five startup test types. We are explicit about which ones exist today versus later.
| Type | Status | What we use |
|---|---|---|
| 1. Unit | Required on every PR |
Vitest 4.
vitest.config.ts aliases @/.
Live spec:
lib/audio/timecode.test.ts (zero-pad, clamp
negatives / NaN).
|
| 2. Component | Not yet | Add React Testing Library when shelf/wells regress. Do not invent it on an unrelated ticket. |
| 3. Integration | Not yet | No database. Zustand + engine wiring is still manual. |
| 4. API | N/A this MVP | There is no HTTP API. Do not add Postman for fun. |
| 5. End-to-end UI | Manual smoke today | Walk DEMO.md (shelf → wells → A/B → pin → reply → resolve) on every deck PR. Playwright after we deploy to Vercel. |
npm test # vitest run
npm run test:watch
Testing fits Scrum here: a story is not Done if CI’s Vitest job is red, and a deck story is not Done if DEMO.md fails in Review.
9. Other controls, tools, and procedures
Run, build, Node
package.json engines: node >= 20. CI
uses Node 22. Install from
nodejs.org.
npm run dev # http://localhost:3000
npm run build # required before you call a story Done
npm start # production server locally
Infrastructure / deploy (class: host + how it is created)
Today: local only. Mix File objects
live in Zustand; a refresh clears the shelf. When share ships we
will outsource infra to Vercel (class Option 3 —
not hand-rolled Terraform). One project, linked to
garettwoolley/criisp-fm, production branch
main after v2 merges. Preview deploys on
each PR.
Secrets
-
.gitignorealready ignores.env*. There are no API keys in the MVP. - When Vercel exists, secrets go in the Vercel project env UI — never in the client bundle, never in chat with Agent.
- Customer audio is not a secret file we store. Do not commit it.
On-call / incidents
No pager. Garett is the only contact. If localhost audio graphs stick, reload the tab (the engine is a singleton; a wedged AudioContext is recovered by refresh).
Product files you should know
DEMO.md— Review scriptVALIDATION_FINDINGS.md— interview notesIDEAS.md— parking lot, not Sprint Backlog-
lib/audio/deck-engine.ts— transport; do not reimplement in a component
Who to ping
Product Owner / Scrum Master: Garett Woolley · GitHub @garettwoolley