Mise
Marigold Hair Studiosample salonDay 1 of 2
ROLLOUT

Finish

One workspace per salon: its own database, API and agent service, stood up from the blueprint and checked before anything goes live. The files below are generated from the config, in the formats the Lollicut stack already reads.

Go-live gatewaits for approval
The config is still a proposal. Approve it in Apprentice first; the files below are a preview of what it would generate.open Apprentice →

Generated files

PREVIEW · FROM THE PROPOSED CONFIG
The steps to stand the salon up, with this repo's commands.
# Rollout: Marigold Hair Studio

Generated by Mise from `salons/marigold/salon.toml` against the Lollicut blueprint
(contract v1-booking-with-staff-optional-service-hac97: 42 endpoints, 206 fixtures).

## Before anything is deployed

7 engine changes are needed first. Until then the affected modules stay off for this salon.

- **Salon.timezone.** Times in America/New_York. Today: Fixed to America/Los_Angeles.
  - Where: `backend/supabase/migrations/20261114161314_booking_foundation.sql:9`, `backend/app/features/availability/engine.py:14`, `backend/app/features/settings/models.py:68`, `frontend/src/features/booking/dates.ts:5`
  - To lift: Drop the database check, then read the zone from the salon row in the engine, the settings API and the site. The contract validator and its fixtures assume Los Angeles too.
  - Holds back: booking_site, staff_dashboard, staff_agent, texting_agent, voice_line, reminders, payments
- **Service.duration_minutes.** Appointment length follows the service (45, 90 min). Today: Every service is one 30-minute block.
  - Where: `backend/supabase/migrations/20261114161314_booking_foundation.sql:22`, `backend/app/features/settings/models.py:17`, `backend/app/features/availability/engine.py:15`
  - To lift: A migration, an engine that sizes each appointment from its service, and contract fixtures for long services. It changes the overlap and availability rules, so it is the largest item.
  - Holds back: booking_site, staff_dashboard, staff_agent, texting_agent, voice_line
- **Salon.slot_step_minutes.** Slots every 15 min. Today: Slots every 30 min, buffer 0.
  - Where: `backend/app/features/settings/models.py:70`, `backend/app/features/settings/models.py:69`, `backend/app/features/settings/service.py:120`
  - To lift: Turn the step and buffer into settings values, and let the engine build its grid from them.
  - Holds back: booking_site, staff_dashboard, texting_agent, voice_line
- **Appointment.child.** The client books for themselves. Today: A parent books for a child.
  - Where: `backend/supabase/migrations/20261114161314_booking_foundation.sql:123`, `backend/app/features/bookings/models.py:54`
  - To lift: Make the child optional, so a client can book for themselves. The booking form, the duplicate guard, the agent prompts and the reminder wording all name the child.
  - Holds back: booking_site, staff_dashboard, staff_agent, texting_agent, voice_line, reminders
- **Payment.method.** Record credit payments. Today: Methods are cash, debit, other.
  - Where: `backend/app/features/payments/service.py:26`
  - To lift: Add the method to one tuple and its database check.
  - Holds back: payments
- **Agent prompts.** Agents that speak for Marigold Hair Studio, a hair salon for adult cuts and colour in Princeton. Today: Prompts name Lollicut, a kids' hair salon in Los Angeles.
  - Where: `agents/photon/lollicut_photon/prompt.py:26`, `agents/photon/voice/prompt.py:17`, `backend/app/features/agent/service.py:68`, `agents/photon/lollicut_photon/salon.py:232`
  - To lift: Read the salon's name, kind and city from GET /salon in the three prompts. Services, prices, hours and phone already load from the backend.
  - Holds back: staff_agent, texting_agent, voice_line
- **Booking site content.** A site with Marigold Hair Studio's own facts and look. Today: Copy, FAQ, photos and design are Lollicut's.
  - Where: `frontend/src/features/site/content.ts:100`
  - To lift: Serve the facts and FAQ from GET /salon and pick the look from a small set of themes.
  - Holds back: booking_site

2 pieces do not exist in the blueprint:

- **Connector · Google Business Profile.** Google Business Profile (hours and the booking link) stays the system of record. No connector yet. API access is granted per project on request. Not re-checked for this work; the owner can also edit the listing by hand.
- **Record import.** Bring past appointments in from the paper appointment book. Photograph the paper book or load an export, review each row, confirm it into history. Defined in the contract, not built.

## Steps

Each salon gets its own database, API and agent service. Run from the repo root.

1. **Database.** Create a Supabase project for this salon, then apply the migrations:
   `python backend/scripts/migrate_staging.py --yes-staging --env-file <salon env file>`
2. **Seed.** Load this salon's catalogue and hours: `psql "$SUPABASE_DB_URL" -f platform/salons/marigold/out/seed.sql`
3. **Secrets.** `PROJECT=<salon project> deploy/backend/secrets.sh <salon env file>` (creates the runtime account, the agent token and the scheduler token).
4. **API.** Copy `out/env.yaml` to `deploy/backend/env.yaml`, fill the three placeholders, then `PROJECT=<salon project> SERVICE=marigold-api deploy/backend/deploy.sh`. The script ends with a smoke booking.
5. **Settings.** Sign in as the owner and send `out/settings.put.json` to `PUT /settings` (read `expected_version` from `GET /settings` first).
6. **Wording.** Replace `backend/app/features/reminders/wording.toml` with `out/wording.toml`. The owner approves it before any real text.
7. **Agents.** `LOLLICUT_API_URL=<api url> agents/photon/deploy/cloudrun.sh`, with live sends off.
8. **Checks.** `python3 contracts/validate.py`, the backend test suite, and the agent evals:
   `cd agents/photon && .venv/bin/python -m evals.run_scripted --backend http --judge`
9. **Site.** A Vercel project with `NEXT_PUBLIC_API_BASE_URL` set to this salon's API.
10. **Owner test.** The owner books on the site and finds the booking on the staff calendar. Record what confused them.
11. **Go live.** Only after the owner approves the wording: set `PHOTON_LIVE=1` and allow-list the numbers.

## Not automated

Staff sign-in grants (they need each person's account), the phone number, and the owner's approval of every public sentence.
On disk: npm run mise -- compile marigold writes these to platform/salons/marigold/out/

Lollicut, measured

Spec to last integration mergeabout 9 hoursdocs/submission/devpost.md, from git log (Nov 14, 3:46 am to 12:56 pm ET)
Backend tests534 passed, 27 deferred skipsbackend/README.md (HAC-75, HAC-76, HAC-64, HAC-26)
Second salon, end to endnot measuredNo second salon has been stood up yet. "Days, not weeks" is a target until one is timed.