---
id: "2.2"
title: "v1 PRD"
dept: product
status: draft
owner: Param
branded: false
last_verified: 2026-10-26
sources:
  - "brew origin/main b91e364: SCOPE.md:7-55, SPEC.md:11-20, CLAUDE.md:20-45, DUMMY.md:12-40"
  - "brew origin/main: build.js:222-239, build.js:363, build.js:395, build.js:1070-1076, confirm-remind.js:114"
  - "brew origin/main: feed-service.js:261-264, feed-service.js:375-376, feed-service.js:997-1014, feed-service.js:1364, feed-service.js:2400"
  - "brew origin/main: public/app.js:160, 276, 314, 319, 764-779, 1308, 1674, 4556, 4598; public/questions.js:36-40; public/live.js:344-349; public/post-open.js:43"
  - "brew origin/main: card-plan.js:36, team-brief.js:20, brief-status.js:8-11, handoff.js:7, jam-mail.js:4, digest.js:12, digest.js:54, server.js:645-646"
  - "brew origin/main: connectors/index.js:32-53, connectors/index.js:267, connectors/index.js:348, vault.js:3, auth.js:31-34, closed-gate.js:4"
  - "brew origin/main: drop.js:6, references.js:5, member-tuning.js:3, viral-gate.js:13, shelf.js:6, rival-ad.js:7, claims.js:219, jam2/make.js:289-292, finals.js:36, drafts-bg.js:13, moves-cadence.js:9, moves-cadence.js:409, remix.js:1789, watch-view.js:85, health.js:159"
  - "brew origin/main: tools/prod-env.sh:9, jam-brief.js:94-95, commit 0fc7cfc, commit 9ee9d14, commit 1520cba"
  - "brew .wt-prod docs/production.md:3-31"
  - "brew origin/main docs/brew-loop.md:44-61, docs/connectors-approvals.md"
  - "brand-directions/docs2/content/inventory.mjs, pages.mjs:262-280, data/plays.json, data/catalogue.json"
  - "memory: brew-access-rules, brew-feed-open-moves, brew-one-version, brew-proof-plain-make, brew-brief-mode, brew-jam-rca-2026-10-26, brew-v1-creative-stage, brew-one-stage, brew-prod-backend, prod-clean-only, brew-live-stores, brew-real-connectors, brew-connected-facts, brew-stories-and-cards, brew-community-seat"
---

# v1 PRD

## Answer

v1 reads a store and the world around it, writes its Plays, ranks them into a feed of drafted ideas, lets the team make each piece in a jam and hands it to whoever ships it, and it never posts, sends to customers, spends or measures.

## Today

v1 is what runs on production at feed.joinsquareup.com today, with the same code on staging and the demo site [src: brew .wt-prod docs/production.md:3] [src: SCOPE.md:27-30]. Every row below is a feature that exists on origin/main b91e364. The acceptance column is written so anyone can check it against the code or the live site.

### Access and onboarding

| Feature | What it does | Acceptance, checkable | Source |
|---|---|---|---|
| Sign in before a read | A Google sign in comes before the read starts. A free mail or another company's email cannot start a new read and sees one wall that points to the demo site | An email that fails `officialFor` gets the sign wall; the two staff domains in `FULL_ACCESS_DOMAINS` pass | [src: auth.js:31-34] [src: public/app.js:276] [src: memory brew-access-rules] |
| Reads per person | Three new brands a day per person, staff exempt | The fourth new brand in 24 hours returns "3 new brands a day per person" | [src: build.js:222-225] |
| Reading your store | Seven steps in a fixed order: open, brand, catalog, reviews, ads, site, answers, each with a real finding | Steps arrive in that order; a step that failed says it could not check, never "none" or 0 | [src: SPEC.md:92] [src: CLAUDE.md:12] |
| Five questions during the read | Seat, what comes first, channels, products to lead with, rivals | `public/questions.js` holds exactly these five ids; a skipped question is never asked again in setup | [src: public/questions.js:36-40] [src: public/app.js:762] |
| Setup after the read | Check, who, want, connect, team, with a refresh reopening the same step | `OB_AT` lists the five steps; a refresh on the check page reopens it | [src: public/app.js:764] |
| Seats | Five seats: founder, growth, brand, ecom, crm. Each re-ranks and re-words cards | `defaultWants` covers the five keys | [src: public/app.js:779] |
| Plays wait for the first feed open | A brand's first read writes its Plays only after someone opens the feed; reminders go at 3 hours and a day | `status.feedGate` set on a first read only; `remindFeed` sends the two emails | [src: build.js:239] [src: build.js:363] [src: confirm-remind.js:114] [src: memory brew-feed-open-moves] |
| Closed stores | A store read from a closed Shopify admin is team only | Anyone else gets "This store isn't open yet", never demo mode | [src: closed-gate.js:4] |

### Plays

| Feature | What it does | Acceptance, checkable | Source |
|---|---|---|---|
| The playbook | 65 Plays in six groups: 50 core, 13 from listening, 2 automation | `data/plays.json` in the docs counts 50, 13 and 2 | [src: brand-directions/docs2/data/plays.json] |
| Names | Plays, never moves, wherever a person reads them; ids, routes and files keep "move" | Labels read "Play 07", "Weekly play 3", "Timely play" | [src: public/app.js:319] [src: memory brew-qa-round2-2026-10-24] |
| Weekly Plays | Listening and automation Plays every week, numbered from 1001, never reused; automation Plays are plans the team runs | Numbers start at 1001; weekly cap `MOVES_WEEK_CAP_USD`, default $3 a brand | [src: moves-cadence.js:9] [src: moves-cadence.js:409] [src: docs/brew-loop.md:54] |
| Rewrites | A connected number that shifts 10 percent, a sold out product, team learnings or a new connection rewrites the Plays it touches, each within a cap | `LIVE_MATERIAL` 0.1, `LIVE_CAP_USD` $30, `LEARN_CAP_USD` $30, `CONNECT_CAP_USD` $40 | [src: build.js:1070-1076] [src: memory brew-move-freshness] |
| Every number backed | Numbers trace to a ledger entry or a cited source, else "to confirm" | A Play cover whose number does not match the catalog shows "to confirm" with the reason | [src: SPEC.md:13] [src: memory brew-read-stream-backfill] |
| PDFs | Each Play downloads as a PDF, drawn on download | A Play PDF opens for each of the five partners | [src: memory brew-lean-pipeline] [src: brew origin/main docs/audit-2026-10-24-design-partners.md] |

### The feed

| Feature | What it does | Acceptance, checkable | Source |
|---|---|---|---|
| Ranked feed | Cards from Plays, ideas, Heard, stories, watchers and margin notes, ranked per person | Ten cards show before "See the next ones" | [src: public/app.js:1674] [src: SCOPE.md:13] |
| Need your yes | Decision cards inside the top window, default 14, or the person's own number | `todayN` returns `perDay` or 14 | [src: public/app.js:1308] |
| Heart | A heart asks for one more card in that direction | The server makes one child card titled "One more in the direction you hearted" | [src: feed-service.js:997-1014] |
| Proof on every card | A shield opens "Why this, and the proof": each number matched to its fact, account, rival ad or quote; unbacked numbers are named | `GET /api/cards/:cid/evidence` answers for any card a person can see | [src: feed-service.js:2400] [src: memory brew-proof-plain-make] |
| Plain words | Titles, body, reasons and steps rewritten in everyday words, every number kept | Served cards pass through `PLAIN.apply` unless `PLAIN_OFF=1` | [src: feed-service.js:1364] |
| One version | Every make leads with one take; Redo it makes the next | Every family in `MAKE_N` is 1 | [src: card-plan.js:36] [src: memory brew-one-version] |
| Storefront hidden | The storefront column, cards, agent and tag are hidden in v1 | Visible only with `?storefront=1` | [src: public/app.js:160] [src: public/app.js:314] [src: SCOPE.md:13] |
| Story rings | Brand today, Trends, Popular ads, Industry news, How to; all five always show; 24 hour life | A ring whose stories expire reads its source again rather than hiding | [src: memory brew-stories-and-cards] |
| Viral videos | Short videos with at least 10 times the creator's usual views, at most 90 days old | `MIN_SCORE = 10, FRESH_DAYS = 90` | [src: viral-gate.js:13] [src: SCOPE.md:19] |
| Community cards | Reddit and forum ideas pass a gate: fresh in 14 days, in market, on topic, a real ask | A thread older than 14 days never becomes a card | [src: memory brew-community-seat] |
| Health rings | Creative, Storefront and AI answers scored from the read; unread parts left out | `healthFrom` scores only what was read | [src: health.js:159] [src: DUMMY.md:16] |

### Your store and what Brew watches

| Feature | What it does | Acceptance, checkable | Source |
|---|---|---|---|
| Sources | 68 sources in the inventory: 60 read today, 7 once an account connects, 1 off | Counts from `SOURCES` in the docs inventory | [src: brand-directions/docs2/content/inventory.mjs] |
| Watch page | What people say, where you sell, rival cards, AI standing, at `#v=watch` | `watchView` renders for any built brand | [src: watch-view.js:85] [src: SCOPE.md:15] |
| Paid source caps | treg first, Apify only for gaps, Apify capped per brand per month | `APIFY_BRAND_MONTH_CAP_USD` default $10 | [src: shelf.js:6] |

### The jam, which tomorrow is called Make it

| Feature | What it does | Acceptance, checkable | Source |
|---|---|---|---|
| Team jams | One jam per card, shared by the brand's team, with who made each message and version | A second person tapping the same card joins the same jam | [src: SCOPE.md:18] [src: memory brew-team-jams] |
| Guests | A guest of one jam may chat, edit the brief and make drafts, and may not share, send, approve, assign, discard or start paid makes | `GUEST_DO` and `GUEST_CHANGE_NO` hold the two lists | [src: feed-service.js:261] [src: feed-service.js:264] |
| Making buttons make | The card's button makes what it names, once per jam | `POST /api/changes/:chid/cta-make` | [src: remix.js:1789] |
| Paid makes ask first | A paid Studio make runs only with a confirmed price at or above the quote | `renderVideo` returns `needsConfirm` without `confirmUsd` | [src: jam2/make.js:289-292] |
| One stage | One name in the header, only the piece on the stage, a Draft, Make, Send bar, a Set-up tab | Guarded by `test/one-stage.test.js` | [src: memory brew-one-stage] |
| Deliverable tabs | A card can be made as another deliverable with "+", each with its own versions and brief | Each tab has its own team brief with a real recipient | [src: commit 1520cba] [src: memory brew-jam-rca-2026-10-26] |
| Make our version | A rival ad or viral video is read into a written breakdown; the image model never gets the rival's picture | `rival-ad.js` sends only the brand's product photo and the breakdown | [src: rival-ad.js:7] [src: SCOPE.md:19] |
| Claims check | Every surface that writes copy is checked; measured results need the store's study or an approved claim | `checkCopy` runs on drafts, finals and briefs | [src: claims.js:219] [src: memory brew-qa-round2-2026-10-24] |
| First drafts | Background drafts on the top cards for brands opened in the last 3 days | `DRAFTS_DAY_CAP_USD` default $4 a brand a day in code; docs/brew-loop.md still says $1.50 | [src: drafts-bg.js:13] [src: docs/brew-loop.md:60] |
| Finals | On production, finals are made on Gemini and Sloosh is off; on the demo site finals are simulated | `SLOOSH_CHECK=0` in the production env; `dummy()` on `DEMO_MODE` | [src: tools/prod-env.sh:9] [src: commit 0fc7cfc] [src: finals.js:36] |
| Jam v2 screen | Retired; its engine powers v1's Studio set-up | `?v=2` no longer exists | [src: commit 9ee9d14] |

### Hand-off and briefs

| Feature | What it does | Acceptance, checkable | Source |
|---|---|---|---|
| Send to | A brief written for one of seven recipients: your team, your agency, a designer, a media buyer, a creator, a video editor, or our team | `RECIPIENTS` holds the seven kinds | [src: team-brief.js:20] [src: memory brew-jam-rca-2026-10-26] |
| From your own email | Gmail compose with the email written, or a Mail or Outlook .eml draft, files downloaded beside it | The Gmail route opens `mail.google.com` with `to` filled | [src: public/app.js:4556] [src: public/app.js:4598] [src: memory brew-brief-mode] |
| To our team | The whole brief is emailed and tracked: sent, received, in progress, needs info, delivered; each step emails the sender | `STATUSES` and `NEXT` in brief-status.js; only staff move it | [src: brief-status.js:8-11] [src: SCOPE.md:20] |
| Brief numbers | Briefs are numbered BR-n per workspace, starting after 1041 | `nextTicket` starts at 1041 | [src: feed-service.js:375-376] |
| Read only brief page | `/h/<token>?full=1` shows the brief, versions and files with no login | Opens signed out | [src: handoff.js:7] |
| Copy and open | Copies a community post and opens the exact place to post it | Reddit opens `/r/<sub>/submit` with title and text | [src: public/post-open.js:43] [src: memory brew-copy-and-open] |

### Learnings and memory

| Feature | What it does | Acceptance, checkable | Source |
|---|---|---|---|
| Drop anything | Notes up to 4,000 characters, photos up to 8 MB, PDFs and decks read into a draft learning the team saves | Limits stated in drop.js | [src: drop.js:6] [src: memory brew-drop-learnings] |
| References | Photos, ads, looks, logos, people or clips with a job and a keep note | Each item has `label, job, keep` | [src: references.js:5] |
| Your feed | Less, normal or more per area, topics to lift, what hearts taught | `member-tuning.js` weights | [src: member-tuning.js:3] |
| Brand Book | The brand's whole profile, read by every maker, shareable as a page and files | `/<slug>/brand`, `.md`, `.json`, `llms.txt`, kit zip | [src: memory brew-brand-book] |

### Connections, team and emails

| Feature | What it does | Acceptance, checkable | Source |
|---|---|---|---|
| Read only connectors | Shopify, Meta Ads, Google Analytics, Google Ads, Klaviyo, Judge.me read only; Slack posts only to the brand's own threads | Marketplaces stays in `OFF` | [src: SCOPE.md:14] [src: connectors/index.js:32] |
| Freshness | Shopify and Meta every 3 hours, Google and Judge.me every 6, Klaviyo every 12; re-read when a member opens the brand | `EVERY_H` and `OPEN_H` | [src: connectors/index.js:37-40] [src: memory brew-connected-facts] |
| Stale data stops | After 3 failed reads or 72 hours without a good one, numbers are stale and stop being evidence | `STALE_FAILS 3`, `STALE_H 72` | [src: connectors/index.js:51-53] |
| Who connects | Only owners and admins connect or disconnect | `canConnect` | [src: connectors/index.js:348] |
| Protected connections | A protected brand never loses a live connection by accident; production protects arata-in | `PROTECTED_CONNECTIONS=arata-in` | [src: connectors/index.js:267] [src: tools/prod-env.sh:9] |
| Tokens | Encrypted in the brand's vault, never logged | `FEED_VAULT_KEY` | [src: vault.js:3] |
| Monday digest | One email per teammate on Monday from 09:00 brand time, no AI calls, skipped when nothing is new | `due` checks Monday 09:00 brand time; `DIGEST_OFF=1` stops it | [src: digest.js:12] [src: digest.js:54] [src: server.js:645-646] |
| Jam emails | Tags, asks and OK requests at once; replies batched to one email per jam per person every 15 minutes | Stated in jam-mail.js | [src: jam-mail.js:4] |
| Ask us to delete your data | A request by email; the team deletes within 7 days | The sheet says so, with no Dummy tag | [src: public/live.js:344-349] [src: DUMMY.md:22] |

### Simulated in v1, and where

| What | Where it appears | Source |
|---|---|---|
| Connected accounts and their numbers | Demo site only | [src: DUMMY.md:14-15] |
| Pro plan sheet, no billing | Kept on production by Param's call | [src: DUMMY.md:17] [src: memory prod-clean-only] |
| Teammate replies | Demo site only | [src: DUMMY.md:18] |
| Marketplaces | Coming soon cards | [src: DUMMY.md:20] |
| Finals | Demo site only | [src: DUMMY.md:21] |
| Listing photos with no image model | The brand's own catalog photos stand in | [src: DUMMY.md:23] |

### What v1 does not do

| Cut | What went | Source |
|---|---|---|
| Do it now | Real actions on accounts, the action tray, the agent runner, the safety policy, programs and routines that run themselves, scheduled starts, the stop rule and auto undo, the weekly spend limit, "Changes Brew made", undo, task trackers | [src: SCOPE.md:36] |
| Writing to accounts | Any API write to a brand's accounts | [src: SCOPE.md:37] |
| Sending to customers | Marketing email and WhatsApp, contacts, unsubscribe pages, lifecycle flows, holdouts | [src: SCOPE.md:38] |
| Measurement | The measuring engine, launch records, report back, A to D grades, results, the Out, Live and Result columns, follow up cards | [src: SCOPE.md:39] |
| Fake team flow | Scripted team replies, simulated Slack posting, a simulated "go live" | [src: SCOPE.md:40] |
| Audit Plays | The weekly weak area Plays; the counted scorecard stays as evidence | [src: SCOPE.md:41] |
| A daily card cap | The 10 a day free cap | [src: SCOPE.md:42] |
| Commerce plumbing | Payments, shipping, tax, roles management | [src: memory brew-name-and-scope] |
| Agencies and many brands | No agency login, no brand switcher | [src: brand-directions/docs2/content/pages.mjs:272-278] |

## Tomorrow

The redesign keeps every engine and changes what a person sees. Each item names its version and its tag.

| Item | Version | Tag | What changes |
|---|---|---|---|
| Three tabs, Today, Work, Your store, Settings behind your picture | v1 | Changes | The rail, Deck, Library and Learned fold into three tabs [src: brand-directions/_shared/product-model.md:51-65] |
| Five picks under Need your yes | v1 | Changes | One visible number, five, over today's ranked list; ten and the hidden 14 go |
| One closed card of five parts, 25 words at most | v1 | Changes | Card generation unchanged; the closed card shows the first sentence of today's text |
| Which of these do you handle | v1 | Changes | Replaces the five seats; mapping onto the seat field is a ranking risk to check |
| One Hand it off button | v1 | Changes | One sheet over today's routes: Me, My team, My agency or freelancer, Our team |
| One brief page | v1 | Changes | Old link forms redirect to it |
| Three quick questions, the reveal, the first win bar | v1 | New | Add ons behind their own switches |
| Groundwork: destination channel per pick, structured brief, decision log, one status field | v1 | New | Add ons that touch nothing that works today |
| The Deck, Jam v2 links, the bell, the floating button, the swipe tuner, the welcome card | v1 | Goes | Their data stays underneath [src: brand-directions/_shared/ia.md:155-176] |
| Measuring words in v1 | v1 | Goes | Removed in a Restyle; they return with v3 |
| Posting and scheduling | v2 | New | See the v2 PRD |

## How we do it

1. Read SCOPE.md and DUMMY.md before adding anything. A cut feature comes back only with Param's yes [src: CLAUDE.md:3-5].
2. Check an acceptance row against origin/main, never the working tree:
   ```
   git -C /Users/param/Documents/ChatGPT/brew grep -n "MAKE_N" origin/main -- card-plan.js
   git -C /Users/param/Documents/ChatGPT/brew grep -n "STATUSES" origin/main -- brief-status.js
   ```
3. Run the suite before any change ships:
   ```
   AI_MOCK=1 node --test test/*.test.js
   ```
4. Fix for every brand, heal saved data, and add a test or an audit for the class of bug [src: CLAUDE.md:20-40] [src: memory fix-as-product].
5. Audits to run after card, Brand Book or jam layout changes:
   ```
   node tools/audit-card-fit.mjs DIR
   node tools/audit-brand-book.mjs DIR
   node tools/audit-layout.mjs <jam share links>
   ```
6. Deploy to staging with `./deploy.sh`, then release to production only with `tools/promote.sh`, which runs the clean gate [src: brew .wt-prod docs/production.md:25-31].
7. When a row in this PRD changes in the code, update the row and its source the same day.

## Numbers

| Metric | Definition | Where measured | Status |
|---|---|---|---|
| Read time | Minutes from Build my feed to the last read step | Build status timestamps | About 3 to 4 minutes per the 15 Oct handover; not re-timed since [src: docs/handover/product/05-known-limitations.md:51] |
| Build cost | Dollars to write a brand's full set of Plays | `cost.json` per brand | About $12.6 a build on 16 Oct on Gemini 3.1 Pro [src: memory brew-go-live-2026-10-17]; production cap `BUILD_CAP_USD=45` [src: tools/prod-env.sh:9] |
| Acceptance pass rate | Share of rows in this PRD that pass on production | A walk of this table | Proposed |
| Test suite | Tests passing on origin/main | `AI_MOCK=1 node --test` | 1,173 passing at the jam audit close on 25 Oct [src: memory brew-v1-creative-stage] |

## Open

1. **Is the Pro plan sheet still wanted on production?** It shows a trial with no billing. Proposal: hide it until pricing is agreed, so no partner reads a plan we cannot sell yet.
2. **Do the "How we measure it" sections stay in v1 briefs?** The brief writes a measure plan for the team [src: jam-brief.js:94-95], and the redesign removes measuring words. Proposal: keep it in briefs as "How your team measures it", remove it from cards and the card page.
3. **Seats or Which of these do you handle first?** Proposal: ship the question as a filter first and keep the seat field as the ranking input until a test shows the same top five.
4. **The drafts cap.** Code says $4 a brand a day, the loop doc says $1.50. Proposal: keep $4 and fix the doc.
5. **Read time.** Proposal: time five reads on production this week and replace the 3 to 4 minute figure with the median.
