Yoga studio chatbot for class questions and trial bookings
Website chatbot that answers class questions from studio facts and collects trial session requests for the studio to confirm, built with Node, TypeScript and
nodejstypescriptexpressanthropicclaude
Built 1 time, downloaded 0 times.
Install from your terminal
Run this in your project folder. It signs you in, shows what changes and asks before it overwrites a file.
npx claude-lab add yoga-studio-chatbot-for-class-questions-and-trial-bookings-97bb29CLAUDE.md# Yoga studio chatbot
## Purpose
A website chatbot for a yoga studio. It answers questions about classes and books trial sessions. It is a request system: the studio confirms every booking.
## Stack
- Node 22, TypeScript
- Express serves `public/chat.html` and the `/api/chat` and `/health` routes
- Anthropic SDK for replies (default model: Sonnet)
## Layout
- `src/server.ts`: HTTP routes
- `src/chat.ts`: reply logic, uses `data/studio.md` as the only source of facts
- `src/tools/bookTrial.ts`: trial booking tool (validation, write to `data/bookings.jsonl`, stubbed email notice)
- `data/studio.md`: studio facts (public information only)
- `data/bookings.jsonl`: booking records (personal data, never commit real records)
- `public/chat.html`: chat widget
- `tests/`: tests, including `tests/eval-questions.md`
## Commands
- `npm install`
- `npm run dev`: starts the server on PORT (default 3000)
- `npm test`
- `npm run typecheck`
- `npm run lint`
- `npm run build`
## Rules
- Answer only from `data/studio.md`. If the answer is not there, say you are not sure and offer to pass the question to the studio.
- Never invent prices, class times, teachers or policies.
- No medical advice. For injury or pregnancy questions, direct the user to the studio teacher or their doctor.
- Say you are an AI assistant at the start of each chat.
- A trial booking is a request until the studio confirms it. Never claim a spot is guaranteed. Never take payment.
- Limits: 20 messages per session, 1,000 characters per user message, capped reply length.
- Validate booking input on the server, not only in the browser.
## Gotchas
- `ANTHROPIC_API_KEY` comes only from the environment or `.env`. Never print, log or commit it.
- Do not read or create a real `.env`. Use `.env.example` as the template.
- Do not log full chat transcripts.
- Booking personal data goes only in `data/bookings.jsonl`. Store only the fields the booking needs.
- `STUDIO_NOTIFY_EMAIL` is the studio notice address. In v1 the notice can be a stub that logs to a file.
## Working habits
- Use plan mode for the first step of each phase in `PLAN.md`.
- Run `/clear` between phases.
- Before saying work is done, run the `verify` skill and show the results.
- Keep diffs focused on the current phase.
@REVIEW.md
.claude/agents/test-runner.md---
name: test-runner
description: Use to run the test suite and report failures. Keeps long test output out of the main session.
model: haiku
tools: Bash, Read
disallowedTools: Edit, Write
maxTurns: 15
---
You run the project's test suite and report only what failed.
Steps:
1. Run `npm test` from the project root.
2. If it exits 0, reply with one line: "All tests passed." and stop.
3. If it fails, list each failing test by name, with the first error line of its message.
4. Use Read on a failing test file only if the error line alone does not identify the test. Do not read other files.
Output format:
- `test name`: first error line
Rules:
- Never edit, create, or delete files.
- Do not paste full logs or stack traces.
- Run only `npm test`, plus Read for step 4.
- If the run cannot start (for example, node_modules is missing), say so in one line and suggest running `npm install`.
.claude/settings.json{
"model": "sonnet",
"effort": "medium",
"permissions": {
"defaultMode": "default",
"allow": [
"Bash(npm run *)",
"Bash(npm test)",
"Bash(npx tsc *)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(curl localhost:*)"
],
"ask": [
"Bash(git push *)",
"Bash(npm publish *)",
"Bash(git reset *)"
],
"deny": [
"Bash(rm -rf *)",
"Read(./.env)"
]
},
"env": {}
}
.claude/skills/add-studio-info/SKILL.md---
name: add-studio-info
description: Use when the studio gives new classes, prices, teachers, or policies, so data/studio.md and the eval questions stay accurate.
---
# Add studio info
Use this to update the studio facts the chatbot is allowed to use. `data/studio.md` is the only source for answers, so keep it accurate and complete.
## Steps
1. Ask the user to paste the new information exactly as the studio gave it. Do not guess missing details. If something is unclear, ask.
2. Read `data/studio.md`. Find the section that matches each new fact, using the existing headings:
- Studio overview
- Location and parking
- Class types and levels
- Weekly schedule
- Teachers
- Prices and packages
- Trial session policy
- Cancellation policy
- What to wear and bring
- Contact
3. Update the matching lines. Keep the section headings unchanged and in the same order. Remove a `[FILL IN]` placeholder only when you have the real fact.
4. Check for conflicts before saving:
- Two different prices for the same class or package
- Two different times for the same class on the same day
- A teacher listed in one section but missing from another
- A new fact that contradicts the trial or cancellation policy
If you find a conflict, stop and ask the user which version is correct. Do not pick one.
5. Do not add private or staff-only details. `data/studio.md` is public information only. If the user pastes something private, leave it out and tell them why.
6. Update `tests/eval-questions.md`:
- Add a question for each new class, price, teacher, or policy that a visitor is likely to ask.
- Update the expected answer for any question whose answer changed.
- Remove questions about information that no longer exists.
7. Run the verify skill before you finish. Report its results.
## Rules
- Never invent prices, times, teacher names, or policies to fill a gap. Leave `[FILL IN]` in place and tell the user what is still missing.
- Never write medical claims or promises of results.
- Keep each line short and factual, so the chatbot can quote it exactly.
- Show the user a short summary of what changed: sections edited, questions added or updated, and any open conflicts.
.claude/skills/verify/SKILL.md---
name: verify
description: Use after any code change to check typecheck, lint, tests, build and a live chat call in this project.
---
# Verify
Run this after every code change, before you say the work is done.
## Steps in order
1. Typecheck: `npm run typecheck`
2. Lint: `npm run lint`
3. Tests: `npm test`
4. Build: `npm run build`
5. Live chat call (see below)
Run every step even if an earlier one fails, so the report shows all results.
## Live chat call
1. Start the server in the background: `npm run dev &`
2. Wait until `curl -s localhost:3000/health` returns a response. If it does not respond after about 15 seconds, report the live check as failed.
3. Send one sample question:
```
curl -s -X POST localhost:3000/api/chat \
-H "Content-Type: application/json" \
-d '{"message": "What class types do you offer for beginners?"}'
```
Use the request field name defined in `src/server.ts` if it differs from `message`.
4. Pass only if the response is valid JSON, the reply text is non-empty, and the response is not an error.
5. Do not open `.env` or print `ANTHROPIC_API_KEY`. If the call fails because the key is missing, say so and stop. Do not try to fix it by reading secrets.
## Reporting
Report one line per step:
- `typecheck: PASS` or `typecheck: FAIL`
- `lint: PASS` or `lint: FAIL`
- `tests: PASS` or `tests: FAIL`
- `build: PASS` or `build: FAIL`
- `live chat: PASS` or `live chat: FAIL`
For each failing step, show only the failing lines of output, not the full log. For tests, name each failing test and its first error line.
If everything passes, say so in one sentence and do not repeat the logs.
## Cleanup
Stop the dev server before you finish, whether the checks passed or failed. Find the process listening on port 3000 and stop it. Confirm that port 3000 is free.
Do not leave a server running between tasks.
.env.example# Copy this file to .env and fill in your values. Never commit .env.
ANTHROPIC_API_KEY=YOUR_API_KEY
STUDIO_NOTIFY_EMAIL=YOUR_EMAIL
PORT=3000
INSTALL.md# Install and run the yoga studio chatbot
## What Claude Code is
Claude Code is a terminal assistant that reads your project, edits files, and runs commands. It asks your permission before doing things you have not allowed.
## What each file does
- CLAUDE.md: standing instructions Claude reads at the start of every session.
- SPEC.md: what the chatbot does and does not do.
- PLAN.md: five phases, each ending with a goal Claude must prove.
- REVIEW.md: checklist for reviewing changes before you merge.
- .claude/settings.json: project permissions and the default model.
- .claude/skills/: reusable steps such as verify and add-studio-info.
- .claude/agents/: a helper that runs tests without filling the main chat.
- data/studio.md: the only facts the chatbot may use.
- .env.example: template for your secrets. Copy it to .env.
- INSTALL.md: this guide.
## 1. Install Node 22
1. Go to nodejs.org and install version 22 or newer.
2. Check it worked: `node -v` should show v22 or higher.
## 2. Install Claude Code
On macOS or Linux, run:
```
curl -fsSL https://claude.ai/install.sh | bash
```
On Windows PowerShell, run:
```
irm https://claude.ai/install.ps1 | iex
```
If these commands fail, copy the current installer command from the official Claude Code setup page.
Check the install with `claude --version`. Then run `claude` and log in when prompted.
Logging into Claude Code is separate from the API key the chatbot uses.
## 3. Open the project
1. Create a folder called `yoga-chatbot`.
2. Save the project files into it, including the `.claude` folder.
3. Open a terminal inside the folder.
4. Run `claude`.
## 4. Add your API key
1. Sign in at console.anthropic.com and create an API key under API keys. Billing must be set up for the key to work.
2. Copy the template: `cp .env.example .env`
3. Open `.env` and replace `YOUR_API_KEY` with your key.
4. Replace `YOUR_EMAIL` with the email address that should receive trial booking notices.
Warning: never share your API key. Do not paste it into chats, screenshots, or code, and never commit `.env` to git.
## 5. Add your studio facts
Open `data/studio.md` and replace every [FILL IN] with your real information. Only facts in this file will appear in chatbot answers. If something is missing, the chatbot will say it is not sure.
## 6. Install the review plugins
Inside Claude Code, run these commands if the plugins are not listed:
```
/plugin marketplace add anthropics/claude-plugins-official
/plugin install code-review@claude-plugins-official
/plugin install security-guidance@claude-plugins-official
```
## 7. Start Phase 1
Paste this kickoff prompt into Claude Code:
```
/goal Phase 1 of PLAN.md is complete: a Node 22 and TypeScript project exists in this folder with npm scripts dev, test, typecheck, lint and build, GET /health returns status ok, and the verify skill passes. Check: run npm install, then npm run typecheck && npm run lint && npm test && npm run build, then start the dev server and run curl localhost:3000/health, and show the output of each command in the transcript. Constraints: create only the files Phase 1 of PLAN.md lists; allowed new dependencies are express, typescript, vitest, eslint, dotenv and the official Anthropic SDK, and nothing else; never create or read a real .env file, only .env.example with YOUR_API_KEY as the placeholder; do not edit CLAUDE.md, SPEC.md, REVIEW.md or data/studio.md; do not run git push or any command that deletes files. Turn bound: stop after 25 turns and report what is blocking. Done means every check exits with code 0, the health response shows status ok, and the transcript contains the output of each command.
```
## 8. Work through the phases
- Finish one phase, then run `/clear` before starting the next.
- Start each phase with its `/goal` prompt from PLAN.md.
- Stop a goal early with `/goal clear`.
- Check token use with `/usage`.
Use plan mode for the first step of each phase. Run the verify skill before you end a phase.
## Cost note
Sonnet is the default model. A short chat is estimated at about one cent or less in API usage, and longer chats cost more. Check your own usage in the Anthropic console and with `/usage` in Claude Code.
## Common errors and fixes
**Missing API key.** The error mentions ANTHROPIC_API_KEY. Check that `.env` exists in the project root, that your key is pasted in place of YOUR_API_KEY, and that you restarted `npm run dev` after editing it.
**Port in use.** The error says port 3000 is already in use. Either stop the other program, or change `PORT` in `.env` to another number such as 3001. On macOS or Linux, `lsof -i :3000` shows what is using the port.
**npm install failures.** Check `node -v` shows v22 or higher. Then delete the `node_modules` folder and run `npm install` again. If it still fails, copy the full error message into Claude Code and ask for help.
PLAN.md# Build plan: yoga studio chatbot
Five phases. Each phase ends with a /goal prompt that Claude can finish and prove.
## How to run each phase
- Start every phase with `/clear`.
- Use plan mode for the first step. Press Shift+Tab to switch to plan mode.
- Run the verify skill before you end the phase.
- Run `/goal clear` if a goal stops early or you want to change it.
- Check token use with `/usage` at the end of a phase.
## Phase 1: Scaffold
Goal: a working project skeleton with the right commands.
Work to do:
1. Create the project files: package.json, tsconfig.json, eslint config, vitest config, src/server.ts, and a placeholder test.
2. Add npm scripts: dev, test, typecheck, lint, build.
3. Add GET /health that returns status ok.
4. Create .env.example with YOUR_API_KEY as the placeholder. Do not create a real .env.
5. Run the verify skill.
Dependencies allowed in this phase: express, typescript, vitest, eslint, dotenv, and the official Anthropic SDK. Nothing else.
Phase 1 /goal:
```
/goal Phase 1 of PLAN.md is complete: a Node 22 and TypeScript project exists in this folder with npm scripts dev, test, typecheck, lint and build, GET /health returns status ok, and the verify skill passes. Check: run npm install, then npm run typecheck && npm run lint && npm test && npm run build, then start the dev server and run curl localhost:3000/health, and show the output of each command in the transcript. Constraints: create only the files Phase 1 of PLAN.md lists; allowed new dependencies are express, typescript, vitest, eslint, dotenv and the official Anthropic SDK, and nothing else; never create or read a real .env file, only .env.example with YOUR_API_KEY as the placeholder; do not edit CLAUDE.md, SPEC.md, REVIEW.md or data/studio.md; do not run git push or any command that deletes files. Turn bound: stop after 25 turns and report what is blocking. Done means every check exits with code 0, the health response shows status ok, and the transcript contains the output of each command.
```
Phase 1 is done when all five npm scripts exit 0 and `curl localhost:3000/health` returns ok.
## Phase 2: Studio knowledge
Goal: the chatbot answers only from the studio's real information.
Work to do:
1. Fill the data/studio.md template with the studio's real information. Ask the owner for each [FILL IN] item. Leave a placeholder where the owner has no answer yet.
2. Build the answer logic in src/chat.ts. It uses data/studio.md as the only context.
3. Add the refusal path: if the answer is not in the file, the reply says it is not sure and offers to pass the question on.
4. Fill tests/eval-questions.md with 10 questions and the expected answers.
5. Run the verify skill.
Phase 2 /goal:
```
/goal Phase 2 of PLAN.md is complete: the 10 questions in tests/eval-questions.md return answers that match data/studio.md, the chatbot invents no facts, and the verify skill passes. Check: run npm test, then POST each of the 10 questions to localhost:3000/api/chat with the dev server running, compare each reply with data/studio.md, and show the results in the transcript. Constraints: use data/studio.md as the only source of facts; do not hard-code any price, time or teacher name in src/; do not read or print ANTHROPIC_API_KEY; do not edit CLAUDE.md, SPEC.md or REVIEW.md; do not run git push or delete files. Turn bound: stop after 30 turns and report what is blocking. Done means all 10 answers match the file, no invented facts appear, and the transcript shows the comparison.
```
Phase 2 is done when all 10 eval questions match data/studio.md and no reply contains a fact missing from the file.
## Phase 3: Trial booking
Goal: a trial booking request is validated, saved, and noted to the studio.
Work to do:
1. Implement src/tools/bookTrial.ts.
2. Validate required fields (name, email, class choice, preferred date and time) and email format. Phone is optional.
3. Append each valid request as one line to data/bookings.jsonl.
4. Add a stubbed email notice that writes to a log file. Use STUDIO_NOTIFY_EMAIL as the recipient.
5. Write tests for 3 valid bookings and 3 invalid ones.
6. Run the verify skill.
Phase 3 /goal:
```
/goal Phase 3 of PLAN.md is complete: src/tools/bookTrial.ts validates and saves trial booking requests, tests cover 3 valid bookings and 3 invalid ones, and all tests pass. Check: run npm test and show the passing test names; run npm run typecheck and npm run lint and show their output. Constraints: validate on the server, not only in the browser; invalid input writes no line to data/bookings.jsonl; the email notice is a stub that logs to a file and does not send real mail; do not log full personal data beyond data/bookings.jsonl; do not read a real .env; do not run git push or delete files. Turn bound: stop after 25 turns and report what is blocking. Done means the 6 booking tests pass, the three invalid cases are rejected, and the transcript shows the test output.
```
Phase 3 is done when tests cover 3 valid and 3 invalid bookings, and all tests pass.
## Phase 4: Widget and safety
Goal: a working chat box on the website, with the disclosure and limits in place.
Work to do:
1. Build public/chat.html, a simple chat UI served by Express.
2. Show the AI disclosure line at the start of each chat.
3. Show the one-sentence privacy note in the widget.
4. Enforce a maximum of 20 messages per session, 1,000 characters per user message, and a reply length cap.
5. Check input length on the server, not only in the browser.
6. Show friendly error messages. Never show stack traces or keys.
7. Run the verify skill.
Phase 4 /goal:
```
/goal Phase 4 of PLAN.md is complete: public/chat.html loads, a full chat with a booking works in the browser test, the AI disclosure is shown, and the message and input limits are enforced by tests. Check: run npm test, then open localhost:3000 in the browser test and complete one chat that ends in a booking request; show the test output and confirm data/bookings.jsonl gained one line. Constraints: limits are checked on the server; errors show a friendly message with no stack trace or API key; do not log full chat transcripts; do not read a real .env; do not edit CLAUDE.md, SPEC.md or REVIEW.md; do not run git push or delete files. Turn bound: stop after 30 turns and report what is blocking. Done means the browser test passes, the limit tests pass, and the transcript shows both.
```
Phase 4 is done when the browser test completes a booking, and the limit tests pass.
## Phase 5: Deploy and handoff
Goal: the studio owner can run and maintain the chatbot.
Work to do:
1. Make a production build with `npm run build`.
2. Write the environment variable instructions in INSTALL.md. Describe ANTHROPIC_API_KEY, STUDIO_NOTIFY_EMAIL, and PORT.
3. Add a README section for the studio owner: how to update data/studio.md and how to read data/bookings.jsonl.
4. Check that no secrets are in git history.
5. Check that the commands in INSTALL.md match the commands that run.
6. Run the code-review plugin against REVIEW.md, then run the verify skill.
Phase 5 /goal:
```
/goal Phase 5 of PLAN.md is complete: npm run build passes, no secrets appear in git history, and INSTALL.md matches the running commands. Check: run npm run build and show the output; run git log -p and search for ANTHROPIC_API_KEY values and any real .env content, and show the search result; compare each command in INSTALL.md with package.json and show the match. Constraints: do not run git push; do not rewrite git history; do not delete files; do not edit data/studio.md or data/bookings.jsonl; do not read a real .env. Turn bound: stop after 20 turns and report what is blocking. Done means the build exits 0, the secret search finds no key or real .env content, and every INSTALL.md command exists in package.json.
```
Phase 5 is done when the build passes, no secrets are in git history, and INSTALL.md matches the running commands.
## After launch
- Review new booking requests in data/bookings.jsonl at least once a day.
- Confirm each request with the family or student by email or phone.
- Update data/studio.md with the add-studio-info skill when the schedule, prices, or teachers change.
- Run the verify skill after any code change.
REVIEW.md# Review checklist
Use this list in /code-review and before merging any change. CLAUDE.md imports this file.
## Secrets and personal data
- No secrets, API keys, or real personal data in code, tests, or committed files.
- .env is never committed. Only .env.example with placeholders is in git.
- Logs do not include full personal data or full chat transcripts.
- Booking records in data/bookings.jsonl are not committed to git.
## Grounded answers
- Every answer must be grounded in data/studio.md.
- Flag any hard-coded price, class time, or teacher name in code or prompts.
- Replies must say "not sure" and offer to pass the question to the studio when data/studio.md has no answer.
## Safety and medical limits
- No medical claims or promises of results in prompts or replies.
- Injury or pregnancy questions must point to the studio teacher or a doctor.
- The chatbot must state that it is an AI assistant at the start of each chat.
- A booking is described as a request, never as a confirmed or guaranteed spot.
## Input and errors
- Booking input is validated on the server, not only in the browser.
- Message length (1,000 characters) and session limit (20 messages) are enforced on the server.
- Errors return a friendly message.
- Errors do not expose stack traces or API keys.
## Tests
- Each new tool has at least one passing test and one failing-input test.
- Tests do not call the live Anthropic API unless marked as manual.
## Scope and dependencies
- Diffs stay focused on the phase being worked on. Flag unrelated changes.
- Justify any new package in the PR description.
- Allowed packages for v1: express, typescript, vitest, eslint, dotenv, and the official Anthropic SDK.
SPEC.md# Yoga studio chatbot: v1 spec
## Purpose
A chat box on the studio website that answers questions about classes and takes requests for a trial session.
## Users
Prospective students on the studio website who want to know about classes and book one free or discounted trial.
## In scope
- Answer questions about class types, levels, times, teachers, prices, location, parking, what to wear, and the cancellation policy. Answers come only from data/studio.md.
- Collect a trial booking request with: name, email, phone (optional), class choice, and preferred date and time.
- Save each request as one line in data/bookings.jsonl.
- Send the studio an email notice for each request, using STUDIO_NOTIFY_EMAIL. In v1 this can be a stub that writes to a log file.
- Say that it is an AI assistant at the start of each chat.
- Explain in one sentence in the widget what personal data is stored and why.
## Out of scope for v1
- Payments and taking deposits.
- User accounts or logins.
- Live calendar sync. Booking requests are checked by a person.
- Medical advice of any kind.
- Languages other than English.
## Rules the chatbot follows
- If the answer is not in data/studio.md, it says it is not sure and offers to pass the question to the studio.
- It never invents prices, class times, teacher names, or policies.
- For injury or pregnancy questions, it directs the user to the studio teacher or their doctor.
- A trial booking is a request until the studio confirms it. The chatbot never says a spot is guaranteed and never takes payment.
## Limits
- Maximum 20 messages per chat session.
- Maximum 1,000 characters per user message.
- Replies are capped in length.
- Limits are enforced on the server, not only in the widget.
## Privacy
- Store only the fields the booking needs.
- Do not log full chat transcripts.
- Booking personal data is kept only in data/bookings.jsonl.
- Secrets stay in .env, which is never committed.
## Cost
- Default model is Sonnet.
- The estimated cost per conversation is written in INSTALL.md.
## Acceptance tests
1. The 10 sample questions in tests/eval-questions.md get answers that match data/studio.md.
2. Three full booking flows each create one record in data/bookings.jsonl.
3. Three invalid booking inputs are rejected with a friendly message and no record is written.
4. The chatbot refuses to invent a price or class time that is not in data/studio.md.
5. The message and session limits are enforced by tests.
6. The widget shows the AI disclosure and the privacy sentence.
## Done means
- `npm run typecheck`, `npm run lint`, `npm test`, and `npm run build` all exit with code 0.
- `npm run dev` starts the server, and `GET /health` returns ok.
- The 10 eval questions and 3 booking flows pass their checks.
- data/studio.md has no [FILL IN] placeholders left before go-live.
data/studio.md# Studio facts
Note: this file is public information only. Do not add private, staff-only, or personal details here.
The chatbot may only state facts written in this file. If a fact is missing, the chatbot says it is not sure.
Replace every [FILL IN] with your real information. Keep the section headings.
## Studio overview
- Name: [FILL IN]
- What we teach: [FILL IN]
- Who classes suit: [FILL IN]
- Opened: [FILL IN]
## Location and parking
- Address: [FILL IN]
- Nearest public transport: [FILL IN]
- Parking: [FILL IN]
- Accessibility: [FILL IN]
## Class types and levels
- [FILL IN class name]: [FILL IN short description, level, length in minutes]
- [FILL IN class name]: [FILL IN short description, level, length in minutes]
- [FILL IN class name]: [FILL IN short description, level, length in minutes]
## Weekly schedule
| Day | Time | Class | Teacher | Level |
|-----|------|-------|---------|-------|
| [FILL IN] | [FILL IN] | [FILL IN] | [FILL IN] | [FILL IN] |
| [FILL IN] | [FILL IN] | [FILL IN] | [FILL IN] | [FILL IN] |
Schedule changes: [FILL IN how often the schedule changes and where the latest version is shown]
## Teachers
- [FILL IN name]: [FILL IN public bio, one or two lines, and the classes they teach]
- [FILL IN name]: [FILL IN public bio, one or two lines, and the classes they teach]
## Prices and packages
- Drop-in class: [FILL IN price]
- 5-class pack: [FILL IN price and validity period]
- 10-class pack: [FILL IN price and validity period]
- Monthly membership: [FILL IN price and what it includes]
- Concessions: [FILL IN who qualifies and the price]
## Trial session policy
- Number of free or discounted trial sessions per person: [FILL IN number]
- Trial price: [FILL IN price, or "free"]
- Trial booking: a request until the studio confirms it by email.
- Trial limits: [FILL IN, for example one trial per person per class type]
## Cancellation policy
- Cancelling a class: [FILL IN notice period and what happens if you are late]
- Cancelling a package or membership: [FILL IN]
- Missed classes: [FILL IN]
## What to wear and bring
- What to wear: [FILL IN]
- What to bring: [FILL IN, for example water, towel, mat]
- Mats and props: [FILL IN whether provided and any cost]
- Arrival time: [FILL IN]
## Contact
- Email: [FILL IN]
- Phone: [FILL IN]
- Website: [FILL IN]
- Opening hours for the front desk: [FILL IN]