Status: Approved (owner, 2026-10-05)
Source: Owner's request, 2026-10-05 ("I want to deploy the app to a Cloudflare hosted domain"; then "want to host on railway.com"). Answers to Q-001–Q-010 on 2026-10-05. Extends001-ai-projects-coreNFR-001 and FR-036, and the 001 constraint "Runs locally only"
Last Updated: 2026-10-05
Today the app runs only on the owner's Mac, at localhost, with no sign-in.
This spec puts a second copy of the app online:
As the owner I want to open the app at my own domain from any browser So that I can use it when I'm away from my Mac or when it's off
Acceptance Criteria:
https://<my domain> shows the sign-in gate, and after signing in, the apphttp://<my domain> ends up at the https addressAs the owner I want a sign-in gate in front of the whole hosted app So that nobody else can read my details and chats or spend my paid keys
Acceptance Criteria:
As the owner I want to put my latest version online with one command on my Mac So that I decide exactly when the hosted app changes
Acceptance Criteria:
As the owner I want the local copy to work exactly as today So that I can keep developing and using it on my Mac
Acceptance Criteria:
localhost works as today, with no sign-in, and with its own dataWHEN the owner opens the domain in a browser THE SYSTEM SHALL serve the hosted app over a secure (https) connection, after the sign-in (FR-002).
IF the domain is opened with plain http:// THE SYSTEM SHALL send the browser to the same page on https://.
The domain is bought and managed on Cloudflare by the owner (D-004). The hosted app runs on Railway (D-002).
WHEN a browser that isn't signed in asks the hosted app for anything (a page, the app's data, a button press, research) THE SYSTEM SHALL show only the sign-in page, or refuse the request, SO THAT nothing of the app or its data is shown or changed before the sign-in.
*Extends 001 NFR-001 ("One local user, with no sign-in"): the local copy keeps no sign-in (FR-013); the hosted copy has one.*
Superseded by 023 FR-001 (2026-10-07): any address on the list in the hosting settings signs in this way; the list holds the owner and people acting for them (023-sign-in-email-list). The original text is kept below for history.
WHEN someone enters an email address on the sign-in page IF it is the owner's address THE SYSTEM SHALL email a one-time code to it, and open the app when the code is entered.
IF it is any other address, or the code is wrong or expired THE SYSTEM SHALL not let them in.
The owner's address is set in the hosting settings, not in the code (D-005).
WHEN the owner has signed in on a browser THE SYSTEM SHALL keep that browser signed in for 7 days, then ask for a new code (D-006).
THE SYSTEM SHALL not offer the hosted app, or any part of it, at any address that skips the sign-in, including the address the hosting service gives the app by default.
WHEN the owner uses the hosted app after signing in THE SYSTEM SHALL behave as the local app does under the current specs, including:
WHEN research runs on the hosted app THE SYSTEM SHALL show it live and let it run until it finishes or reaches the research time limit (10 minutes by default, 003 NFR-002), as on the Mac. The connection through the domain must not end it earlier.
THE SYSTEM SHALL keep the hosted copy's data (details, projects, chats, research, options, sources, marks, reminders) across restarts of the hosted app and across releases.
*Extends 001 FR-036: the hosted copy keeps its own database on the hosting service; the local copy keeps backend/data/app.db.*
WHEN the hosted app is opened for the first time THE SYSTEM SHALL start with no data and ask for the user details, as a new local install does (D-003).
THE SYSTEM SHALL take the hosted copy's settings (the AI model, provider keys, search key, TypeSafe key, Opik settings, the owner's email address) from the hosting service's settings. They are never stored in the code repository.
*The "owner's email address" item is superseded by 023 FR-002 (2026-10-07): a list of one or more allowed addresses. The rest of FR-010 stands.*
The same settings as the local settings file are available; local-only models (Ollama) are not usable online (Out of Scope). A missing or wrong key behaves as it does locally: the app starts, and the problem shows as an error when it is used (001 FR-035).
WHEN the owner runs the release command on the Mac THE SYSTEM SHALL publish the app as it is on the Mac at that moment, and the domain shows the new version once the release finishes (D-007).
Pushing to GitLab, or any other action, shall not release.
THE SYSTEM SHALL never send the local settings file (backend/.env, with its keys) or the local data folder (backend/data/, with the local database) to the hosting service in a release.
THE SYSTEM SHALL keep the local copy working exactly as today: the same start commands, localhost, no sign-in, its own database (D-009).
THE SYSTEM SHALL include a short hosting section in the README that covers:
https://<domain> → sign-in page → enter email → code arrives by email → enter it → the user details form (empty hosted copy) → as today.The real checks (P-005) need all of these. Until the owner has them, only the local parts can be checked.
product.md: the vision ("a local, single-user app"), Out of Scope ("multi-user hosting": owner-only hosting is now in scope), privacy risk (hosted data at Railway, traffic through Cloudflare);tech-stack.md: Deployment target, Auth, Configuration (hosted settings), the release command;conventions.md: "Single local user. There is no auth" (the hosted copy has a sign-in gate), what leaves the machine.Decision: The hosted app has one user, the owner. A sign-in gate stands in front of all of it. Data stays shared as today (one set of details, projects and chats). *Changed by 023 D-001 and D-002 (2026-10-07): the owner and people acting for them, all sharing the one copy of the data.* Reason: Without a gate, anyone could read the owner's details and chats and spend the paid keys. Real multi-user support would change almost every spec. Source: Q-001 (owner, 2026-10-05) Impacts: FR-002 to FR-005, US-002, Out of Scope
Decision: The app runs on Railway. The domain is managed on Cloudflare and points to it. Reason: Owner's choice; works when the Mac is off. Source: Q-002 (owner, 2026-10-05) and the original request Impacts: FR-001, FR-008, FR-010, NFR-001, NFR-005
Decision: No local data is copied to the hosted app. Source: Q-003 (owner, 2026-10-05) Impacts: FR-009, Out of Scope
Decision: The owner buys a domain on Cloudflare. This is a prerequisite outside the app. Source: Q-004 (owner, 2026-10-05) Impacts: FR-001, Constraints
Decision: The owner signs in by entering their email address and the code sent to it. Only the owner's address is allowed. *Changed by 023 D-002 (2026-10-07): the addresses on the list are allowed (023 FR-001).* Reason: No password to manage or leak. Source: Q-005 (owner, 2026-10-05) Impacts: FR-003
Source: Q-006 (owner, 2026-10-05) Impacts: FR-004, NFR-004
Decision: A new version goes live only when the owner runs the release command on the Mac. Reason: Nothing goes live by accident, and it works with the code on GitLab. Source: Q-007 (owner, 2026-10-05) Impacts: FR-011, Out of Scope
Decision: The hosted data has no backups. Source: Q-008 (owner, 2026-10-05) Impacts: Out of Scope, FR-014, Risks
Decision: The local copy keeps working as today, with its own data, separate from the hosted copy. Source: Q-009 (owner, 2026-10-05) Impacts: FR-013, US-004
Decision: The app's pages don't change. The README gives the address that ends the sign-in on the current browser. Reason: The owner mostly uses their own devices; the sign-in service already offers sign-out. Source: Q-010 (owner, 2026-10-05) Impacts: FR-014
Status: answered Answer: Only the owner, behind a sign-in gate. Decision: D-001
Status: answered Answer: Yes: host on Railway. Decision: D-002
Status: answered Answer: Start fresh. Decision: D-003
Status: answered Answer: No domain yet; one will be bought. Decision: D-004
Status: answered Answer: Email one-time code. Decision: D-005
Status: answered Answer: 7 days. Decision: D-006
Status: answered Answer: One deploy command from the Mac. Decision: D-007
Status: answered Answer: No backups. Decision: D-008
Status: answered Answer: Yes, both. Decision: D-009
Status: answered Answer: A sign-out address, written in the README. Decision: D-010
These are extended, not replaced: they stay true for the local copy.
| Metric | Target / Signal | Notes |
|---|---|---|
| Done-when | With the Mac off, from a browser that never visited: https://<domain> → sign-in → code by email → details form → a guided run reaches four options with sources and trust labels; a mark, a reminder with a notification, a round and Research again with Confirm all work | Needs the owner's domain, Railway and Cloudflare accounts, and keys |
| Gate | A browser without sign-in, another email address, and the hosting service's own address for the app all fail to show anything of the app or its data | |
| Releases | After a release, the hosted data is unchanged; the release sent neither backend/.env nor backend/data/ | |
| Local | localhost works as before, with its own data |
| Risk | Impact | Mitigation |
|---|---|---|
| Hosted data is lost (account, plan or storage problem) with no backup | Medium | Owner's choice (D-008); stated in the README (FR-014). Backups can be a later spec |
| The hosting service's own address bypasses the gate | High | FR-005; checked at review |
| Long research is cut off by the connection between the domain and the hosted app | High | FR-007; checked with a real research run of several minutes |
| A release publishes unfinished local changes, because it sends the app as it is on the Mac | Medium | The owner runs releases on purpose (D-007); the README says what is sent |
| Times on the hosted server differ from the owner's time zone | Low | Reminder times are already chosen in the browser (009); checked with a reminder at review |
| Paid keys used by an unwanted visitor | High | FR-002 to FR-005 |
| Monthly cost higher than expected | Low | One service, one data store (NFR-005); costs stated in the README |
localhost, as today.example.com), bought and managed on Cloudflare.mnk-frontend and the owner's backend on the merged mainStatus: Approved (2026-10-06; amended at design approval the same day: FR-006, Q-005; amended the same day after moving ontomain: renumbered from 017, spec 017's look, Superseded Baseline for 017 — re-confirmed by the owner with the tasks, 2026-10-06)
Source: Owner's PRD "The seven-step journey (stepper)", based on the owner's Questions-step mockup, 2026-10-06; approved by the owner the same day with D-001–D-010 and the proposed answers to Q-001, Q-002, Q-004 and Q-005. Part of the stepper redesign. Changes011-single-page-chat-collapsible-sidebar(one page, section index, where a chat opens), through it008-step-navigation-research-again, and the section-index lines of017-new-look-ungraded-minds. Drafted as 017 and renumbered to 018 on 2026-10-06, becausemainhad shipped 017 (the new look) in the meantime (P-004)
Last Updated: 2026-10-06
Today a chat is one long page with sections in time order (Questions, Research, Options, Round N, Research N) and a small index of marks next to the scrollbar (spec 011).
This spec turns a chat into a guided journey of seven steps in three groups:
| Discover | Decide | Act |
|---|---|---|
| Questions · Research · Options | Evaluate · Compare · Choose | Next steps |
This spec:
The redesign has other parts. The look (colours, type, line icons, the name Ungraded Minds) has shipped as spec 017, and the stepper is built in that look. The app shell, the goal bar, the Questions page redesign, and the Evaluate, Compare, Choose and Next steps pages each get their own spec.
025-answer-suggestions; the counter and Go ahead stay out.*As the student I want to see all seven steps, which ones are done and which one I'm on So that I know how far I've come and what's next
Acceptance Criteria:
As the student I want to open any step I've reached So that I can re-read my answers or the research without losing my place
Acceptance Criteria:
As the student I want the app to take me to the next step when the AI finishes So that I don't have to hunt for the result
Acceptance Criteria:
As the student I want every current feature to still be there So that the new layout doesn't cost me anything
Acceptance Criteria:
Partly superseded by 026 FR-010 (2026-10-07) (026-question-tone-and-limits): the first step is named Reflections on screen; the rest of the bar is unchanged.
Partly superseded by 028 FR-001 (2026-10-08) (028-your-story-paths): the first step is named Your story.
Partly superseded by 034 FR-001 and FR-002 (2026-10-09) (034-summit-and-compass): the bar is drawn as a winding trail, with a Compass tab at the left end and a Summit tab at the right end (tabs, not steps), and a boot where the journey is.
WHILE a journey (chat) is open THE SYSTEM SHALL show a stepper bar above the step page with three groups, in this order, each with a small uppercase label:
Each step shows a state mark (FR-002) and its name.
Partly superseded by 034 FR-002 and FR-003 (2026-10-09) (034-summit-and-compass): the Compass and Summit tabs have no state mark; while Scout or Compass is in progress or at its checkpoint, the journey is on that tab, so no step is in progress.
THE SYSTEM SHALL show each step in exactly one state:
| State | Meaning | Look |
|---|---|---|
| Done | The journey has moved past it | a tick |
| In progress | Where the journey is now | a filled circle |
| Available | Unlocked, but neither done nor in progress | an empty circle |
| Locked | Not reachable yet | muted, with a lock, can't be clicked |
At most one step is In progress (FR-003).
Separately, the step being viewed is highlighted with a soft coloured background, and screen readers hear that it is the current step (NFR-002). The viewed step and the in-progress step are often the same, but not always.
Partly superseded by 034 FR-003 (2026-10-09) (034-summit-and-compass): while Scout or Compass is in progress or waits at its checkpoint, its tab is where the journey is (rule 2 then names that tab, not Questions).
THE SYSTEM SHALL work out each step's state from what is already saved for the journey (and, for a failed Research again, from the page as it is now), never from a separately saved status (D-003).
The in-progress step is the first of these that applies:
Chats from before saved options and read-only chats follow FR-016 instead.
Unlock and done rules:
| Step | Unlocked when | Done when |
|---|---|---|
| Questions | always | research has started at least once, and Questions isn't in progress |
| Research | the first research run has started | the journey has options, and Research isn't in progress |
| Options | the journey has options | never in this spec (the Evaluate spec decides) |
| Evaluate | its spec has shipped and the journey has options | as its spec decides |
| Compare | its spec has shipped and 2 or more options are shortlisted | as its spec decides |
| Choose | its spec has shipped and 1 or more options are shortlisted | as its spec decides |
| Next steps | its spec has shipped and an option is chosen | as its spec decides |
An unlocked step that is neither done nor in progress is Available.
Until their specs ship, Evaluate, Compare, Choose and Next steps are Locked with the reason "Coming soon".
A step that was unlocked locks again only if the saved data it depends on goes away (for example, later: clearing every shortlist mark locks Compare and Choose again). If that step is being viewed, its page stays and says why it is now locked, instead of vanishing.
WHEN the student hovers over or focuses a locked step THE SYSTEM SHALL show why it's locked, for example:
WHEN the student clicks an unlocked step, or chooses it with the keyboard THE SYSTEM SHALL show that step's page at once. This sends nothing to the server, uses no AI and adds nothing to the chat. It also works while the AI is working (as 011 D-009).
The first time a step is shown after the journey is opened, its page starts at the top, except Questions during a conversation, which starts at the latest question. When the student returns to a step within the same open journey, it shows as they left it: the same place on the page, the same open or closed research lists, the same level tab and the same card in each options viewer (D-009).
THE SYSTEM SHALL keep the open journey and its viewed step in the page address, so a reload reopens the same journey on the same step (D-006). It SHALL also remember the last viewed step of each journey in this browser, so reopening a journey from the list returns to that step.
Opening a journey and leaving it also add a Back entry, so the browser's Back button can return to the journey and step shown before (Q-005). *Added at design approval, 2026-10-06.*
FR-007 overrides both when something needs the student's attention.
Partly superseded by 034 FR-011 (2026-10-09) (034-summit-and-compass): rule 2 opens the tab holding the waiting question, the missing question (Retry) or the waiting checkpoint.
WHEN a journey is opened (from the list, by a reload, or from a reminder) THE SYSTEM SHALL show the first step that applies:
*Replaces 011 FR-007.*
Partly superseded by 034 FR-011 (2026-10-09) (034-summit-and-compass): choosing or changing to Scout or Compass shows its tab; the checkpoint's other-path button shows its tab; Start looking shows Research.
WHEN the student presses a button that starts or settles work THE SYSTEM SHALL show the step where its result appears:
WHILE the student is viewing the step where the AI is working THE SYSTEM SHALL move them along when:
IF the student is viewing a different step when one of these happens THE SYSTEM SHALL not move them. Instead it shows an "updated" dot on the step that changed, and removes the dot when the student views that step (D-005). The dots last while the journey stays open.
Partly superseded by 026 FR-010 (2026-10-07): the page and its title are Reflections; the rest is unchanged.
Partly superseded by 028 FR-001, FR-009 and FR-012 (2026-10-08): the page is Your story; in journeys started since 028 it holds the path chooser, the progress pill ("Question N of about M · You're on: … · change") and the checkpoint cards (028-your-story-paths).
THE SYSTEM SHALL show on the Questions page:
*Replaces 011 FR-004 (Go to options brought the Options section into view) and 011 FR-006 (the message box at the bottom of every chat).*
THE SYSTEM SHALL show on the Research page:
*Replaces 011 FR-005 (a new Research N section at the bottom of the page).*
THE SYSTEM SHALL show on the Options page everything in today's Options section, with the same behaviour:
WHILE a Research again run waits for confirmation THE SYSTEM SHALL keep the Options page read-only, as today (marks, Remind and Add more about me unavailable, Research again hidden), and show the note "Confirm or discard the new research first." with a link to the confirm list on Research (D-010).
WHILE research runs or the AI is writing THE SYSTEM SHALL keep the mark buttons, Remind, Research again and Add more about me unavailable, as today (008 FR-005).
*Replaces 011 FR-003 (the Options section after the first research).*
THE SYSTEM SHALL never show a locked step's page because of a click. IF a remembered step or a page address points to a step that is now locked, THE SYSTEM SHALL show the journey's in-progress step instead (or the step FR-016 names for older chats).
THE SYSTEM SHALL start every step page with its title and a one-line subtitle (see User Experience Notes). Later specs may add a short status on the right of the header (for example "Question 4 of about 8" or "4 of 6 marked"). This spec adds none.
WHEN the step after the viewed one is unlocked THE SYSTEM SHALL show a Continue to <step> button at the bottom of the page, which shows that step. Example: on Research, once options exist, "Continue to Options". Pressing it sends nothing to the server.
THE SYSTEM SHALL no longer show the one-page chat with its section headings, or the index of marks next to the scrollbar.
*Replaces 011 FR-001, FR-002 and FR-008 to FR-012.*
Partly superseded by 020 FR-012 (2026-10-06): the lock reasons and notices say "journey" instead of "chat" ("This journey is from before guided recommendations.", "This journey is from before saved options.", "This journey is finished."), and New chat is New journey (020-my-goals-onboarding). The original text is kept below for history.
THE SYSTEM SHALL show older chats in the stepper as follows (D-008):
A chat from before saved options whose research failed follows FR-003: Research is in progress with Retry, and a successful Retry saves options as in any other chat.
Kept, and made true by 036 FR-001, FR-004 and FR-005 (2026-10-09) (036-compact-stepper-sidebar-summary): the stepper had been scrolling sideways at every supported width. Since 036 it fits on one row from 1,280px to 1,920px, with only a small scroll at the narrowest windows with the sidebar open, and still scrolls below about 640px.
product.md (vision step 4, the "Run a guided chat" and "Update the options" use cases, the glossary entries Section, Round and Research again); the conventions file layout, if components change.Decision: Each step has its own page. Rounds and research runs keep their time order inside their step. Reason: It matches the mockup and keeps each page short. It reverses 011 D-001 (one page in time order), but the history stays readable because time order is kept inside each step. Source: Owner's PRD; Q-001 (confirmed at approval, 2026-10-06) Impacts: FR-005, FR-009 to FR-011, FR-015
Decision: The stepper always shows all seven steps. Evaluate, Compare, Choose and Next steps are Locked with "Coming soon" until their specs ship. Reason: The student sees the whole path from day one, and later specs only fill in pages and unlock rules. Source: Owner's PRD; Q-002 (confirmed at approval, 2026-10-06) Impacts: FR-001, FR-003, FR-004
Decision: Each step's state comes from the journey's existing data every time it is shown. Reason: No new data, no upgrade of the database, and states can't drift from the real data. Source: Owner's PRD (confirmed at approval, 2026-10-06) Impacts: FR-002, FR-003, Constraints
Decision: "Round N" becomes a sub-heading on Questions, and each research run is "Research N" on Research. They are no longer top-level parts of the page. Reason: Each step then holds one kind of activity. Source: Owner's PRD (confirmed at approval, 2026-10-06) Impacts: FR-009, FR-010
Decision: The app moves the student only if they are viewing the step where the AI is working, or they pressed the button that started or settled the work. Otherwise the changed step gets a dot. Reason: It keeps 011's rule of never pulling the reader away (011 D-009). Source: Owner's PRD (confirmed at approval, 2026-10-06) Impacts: FR-008, NFR-005
Decision: The page address names the open journey and its viewed step, so a reload reopens both. The last viewed step of each journey is also remembered in this browser. Reason: US-002 asks that a reload keeps the step. Today a reload doesn't even keep the open chat, so the address must name the journey too. An address also works with the browser's Back button (Q-005). Source: Owner's PRD recommends the address; Q-004. Naming the journey in it was proposed in the draft and confirmed at approval (2026-10-06) Impacts: FR-006, FR-007, FR-012
Decision: The message box is at the bottom of the Questions page and nowhere else. Add more about me moves the student there. Reason: Typing is answering questions, which is the Questions step. Today's message box is at the bottom of every chat (011 FR-006); keeping it on every step would put a second way of adding information on Research and Options. Source: Proposed in the draft, confirmed by the owner at approval (2026-10-06) Impacts: FR-009, FR-011
Decision: Read-only chats from before guided recommendations show only Questions. Finished chats from before saved options show Questions and Research as Done, open on Research and keep Options locked. Reason: These chats can't reach options, so the general rules (FR-003) would leave them with no sensible step. The owner's database has both kinds (chats 2 and 5). Source: Proposed in the draft, confirmed by the owner at approval (2026-10-06) Impacts: FR-003, FR-007, FR-016
Decision: The first time a step is shown after opening a journey, it starts at the top (Questions in a conversation: at the latest question). Returning to it within the same open journey shows it as the student left it. Reason: The owner's PRD asked for both "starts at the top" (FR-005) and "shows it as I left it" (US-002). This reading satisfies both. Source: Proposed in the draft, confirmed by the owner at approval (2026-10-06) Impacts: FR-005
Decision: While a Research again run waits for confirmation, the Options page shows "Confirm or discard the new research first." with a link to the confirm list. Reason: Today this note sits above the message box, and the Options section is read-only without saying why. With one page per step, the confirm list is on another page, so Options needs to say where to go. Source: Owner's PRD (it described this as today's behaviour; today the note is only above the message box, with no link). Confirmed at approval (2026-10-06) Impacts: FR-011
Status: answered (owner, at approval, 2026-10-06) Answer: One page per step (D-001).
Status: answered (owner, at approval, 2026-10-06) Answer: Show them, locked with "Coming soon", so the student sees the full path (D-002).
Status: deferred to the Evaluate and Next steps specs Answer for now: Options (FR-007). Probably Next steps later.
Status: answered (owner, at approval, 2026-10-06) Answer: In the address, together with the journey, plus the last step per journey in browser storage for reopening from the list (D-006).
Status: answered (owner, at approval, 2026-10-06) Answer: Yes for steps the student chose (a click, Continue, Go to options, Add more about me). Automatic moves (FR-008) don't add a Back entry, so Back never lands on a page the student didn't choose. Amended at design approval (2026-10-06): opening and leaving a journey also add a Back entry (FR-006).
product.md replaces "Section" with Step, Step group and Journey (Constraints).| Metric | Target / Signal | Notes |
|---|---|---|
| Done-when | A new journey: Questions → automatic move to Research (live) → automatic move to Options. Jumping back to Questions and Research and forward again sends no requests (browser network tab). A reload keeps the journey and step. Decide and Act steps are locked with their reasons | Checked in the browser with a real model |
| No lost behaviour | Mark, rule out with a reason, Remind, level tabs, viewer swipes and keys, Research again → Confirm → Options, Add more about me → round → Research again, Retry after a forced failure, reopening during a background turn | Checked in the browser |
| Existing chats | Every chat in a copy of the owner's database opens on the right step without errors | Including the legacy chat 2 and the pre-005 chat 5 |
| Comprehension | The owner, or a test student, can name the current step and what unlocks the next one | Asked without help |
| Risk | Impact | Mitigation |
|---|---|---|
| Reverses spec 011 shortly after it shipped | Medium | Rounds and runs keep their time order inside steps; settle Q-001 before design |
| The student misses a result that finished on another step | Medium | The "updated" dot (FR-008) and Continue buttons (FR-014) |
| Four locked steps feel like a broken promise | Low | Clear "Coming soon" reasons; the Evaluate spec comes next |
| Rebuilding the Options page makes 012 Issue 1 worse | Medium | Fix 012 Issue 1 first (Constraints) |
| A background turn's step can't be told from what the page loads (round or Research again) | Medium | The design checks this first. FR-007 point 3 needs it, and the server must not change |
98029e1f); a real hosted turn to confirmStatus: Approved (2026-10-06)
Source: Owner's requests, 2026-10-06: "I want to change the default model for thinking / discovery to deepseek. If tokens finish use fallback as gemini" (Q-001 to Q-005), then "I also want a settings tab on the left which can be used to toggle the thinking and research models independently" (Q-006 to Q-009). Changes013-deepseek-firecrawlFR-001, FR-003 and D-005,001-ai-projects-coreFR-025 and FR-034,003-guided-recommendationsFR-016 and FR-018, and016-reset-all-dataFR-003 (see Superseded Baseline)
Last Updated: 2026-10-06 (approved by the owner as drafted, including D-007, D-008 and D-011; renumbered from 018 to 019 because 018 is used in another worktree)
Today the owner's copies of the app (local and hosted) use Google Gemini for everything: the questions ("Thinking…") and the research. The model can only be changed in the backend settings file, followed by a restart.
With this spec:
As the owner I want DeepSeek to ask the questions and do the research by default So that the app runs on the cheaper model
Acceptance Criteria:
As the owner I want Gemini to finish the work when DeepSeek is out of credit So that chats keep working until I top up
Acceptance Criteria:
As the owner I want a Settings page in the sidebar where I choose the Thinking model and the Research model separately So that I can switch models without editing files or restarting
Acceptance Criteria:
THE SYSTEM SHALL start with DeepSeek (deepseek:deepseek-flash, D-007) as the Thinking model and the Research model in the owner's local and hosted copies and in the settings template, until another model is chosen on the Settings page (FR-010).
Gemini (the model used today) is the fallback model in the same places (FR-002).
THE SYSTEM SHALL offer a backend setting for a fallback model, in the same "provider:model" form as the other model settings. One fallback model serves both stages. Changing it requires restarting the backend.
IF no fallback model is set THE SYSTEM SHALL behave exactly as today: DeepSeek running out of credit shows a Model error or Research error with Retry (013 FR-003).
IF the fallback model is set but its key is missing or wrong THE SYSTEM SHALL still start, and the problem shows only if the fallback is needed (FR-006).
WHEN a DeepSeek model refuses a request because the DeepSeek account is out of credit IF a fallback model is set THE SYSTEM SHALL do that step with the fallback model and finish the turn, without showing a Model error or Research error and without asking for Retry.
This applies to every step that uses the AI:
The student's answers, the searches already shown and everything saved earlier stay as they are. Once a turn has switched, the rest of that turn uses the fallback model (D-008).
Partly superseded by 030 FR-005 and FR-006 (2026-10-08) (030-opencode-go-models): an OpenCode Go model that refuses because Go's usage limit is reached switches to the Go fallback (OPENCODE_GO_FALLBACK_MODEL, DeepSeek Flash). Every other failure of a non-DeepSeek model still shows the usual error. The original text is kept below for history.
IF a DeepSeek model fails for any other reason (missing or wrong key, rate limit, overload, outage, refused request, unknown model) OR the stage is set to a model that isn't DeepSeek, and that model fails THE SYSTEM SHALL NOT use the fallback model. It shows the Model error or Research error with Retry, exactly as today (001 FR-025, 003 FR-016, 013 FR-003).
WHEN a new turn starts (a new chat's first question, an answer, a round, Research again, or Retry) THE SYSTEM SHALL try the model chosen for that stage first, even if an earlier turn switched to the fallback.
This means the app goes back to DeepSeek on its own after a top-up, without a restart.
IF DeepSeek is out of credit and the fallback model then fails THE SYSTEM SHALL show the usual Model error (questions) or Research error (research) with Retry, and the message says both: "DeepSeek is out of credit, and the fallback model failed: <details>".
Partly superseded by 030 FR-008 (2026-10-08): a switch from an OpenCode Go model shows its own note, "OpenCode Go has reached its usage limit, so DeepSeek Flash answered. Go's limit resets on its own, or pick another model in Settings.", in the same place and style. The original text is kept below for history.
WHEN a turn switched to the fallback model THE SYSTEM SHALL:
The note shows once per turn that switched, not once per step. It is not saved with the chat.
Partly superseded by 021 FR-001 (2026-10-07) (021-sidebar-menu): Settings is the last menu entry, pinned at the bottom of the sidebar below Reminders (no longer "Reminders due"); on the collapsed strip it is the last of the four menu icons. The original text is kept below for history.
Partly superseded by 033 FR-005 (2026-10-12) (033-deep-research-toggle): while Deep Research is on, that page's Research model dropdown is disabled; its current value is still shown.
THE SYSTEM SHALL show a Settings entry in the sidebar, below Reminders due. It is also reachable when the sidebar is collapsed (011), as an icon with the name "Settings" on hover. It opens the Settings page in the main area, as Reminders due does (009). In the hosted copy, it is behind the sign-in like every other page (014).
Partly superseded by 030 FR-001 (2026-10-08): the owner's copies and the template also list Kimi K2.6, DeepSeek V4 Flash and GLM-5.3 Flash from OpenCode Go (opencode-go:<model>), each marked "(OpenCode Go)". The original text is kept below for history.
THE SYSTEM SHALL offer, for both choices, the models listed in a backend setting, each shown by a readable name (for example "DeepSeek Flash", "DeepSeek V4 Pro", "Gemini 3.8 Flash"). The starting models (FR-001) are always in the list, even if the setting leaves them out. Changing the list requires restarting the backend.
The owner's copies and the template list DeepSeek Flash, DeepSeek V4 Pro and Gemini 3.8 Flash (D-009).
Partly superseded by 026 FR-010 (2026-10-07) (026-question-tone-and-limits): the label reads Thinking (the reflections), because the journey's first step is called Reflections on screen. The two choices and how they save are unchanged.
THE SYSTEM SHALL show two choices on the Settings page, Thinking (the questions) and Research (research and option cards), each set to the model in use now.
WHEN the owner picks a different model for one of them THE SYSTEM SHALL save it at once, show that it was saved, and use it from the next turn of every chat, without a restart. The other choice doesn't change.
WHILE a turn is running THE SYSTEM SHALL let that turn finish on the models it started with.
Partly superseded by 031 FR-007 (2026-10-08) (031-exa-web-search): a Reset also puts the Web Search choice back to the starting service, and that choice is kept the same way. The original text is kept below for history.
Partly superseded by 033 FR-005 (2026-10-12) (033-deep-research-toggle): while Deep Research is on, the Research model choice cannot be changed on the Settings page; it becomes changeable again when Deep Research is switched off.
THE SYSTEM SHALL keep the chosen models until they are changed on the Settings page, through backend restarts and releases.
WHEN a Reset is confirmed (016) THE SYSTEM SHALL put both choices back to the starting models (FR-001) (D-011). *Extended by 026 FR-004 (2026-10-07): the Reset also puts the question tone and limits back to Balanced, 1 and 5.*
IF a chosen model is no longer in the list (FR-009) THE SYSTEM SHALL use the starting model for that stage, and the page shows it as the choice.
Partly superseded by 030 FR-009 (2026-10-08): when the list has an OpenCode Go model, the same paragraph also shows "When OpenCode Go's limit is reached: DeepSeek Flash" (or "No fallback is set for OpenCode Go."). The original text is kept below for history.
THE SYSTEM SHALL show, below the two choices, which model takes over when DeepSeek is out of credit ("When DeepSeek is out of credit: Gemini 3.8 Flash"), or "No fallback is set." It can't be changed on the page (D-012).
Partly superseded by 030 FR-010 (2026-10-08): the README and the template also name OpenCode Go and the provider behind each Go model, and OpenCode Go receives a random code per journey. Payloads are unchanged. The original text is kept below for history.
THE SYSTEM SHALL send the chosen model and the fallback model exactly what it sends any model today: the student's details without the name, the project and the answers, and the options with their marks and reasons (003 NFR-001, 013 FR-007). The README and the settings template must say that a chat's turns may go to more than one provider.
tech-stack.md: the new settings, and "one main model plus an optional research model, changing either requires a restart" becomes "starting models in the settings file, chosen in the app from a list, plus an optional fallback model";product.md: the Settings page, and details may go to more than one model provider in one chat.Decision: DeepSeek is the starting model for both the questions and research, including turning the recommendation into option cards. The Gemini fallback covers both. Reason: Owner's choice. It saves the most, and the fallback covers the risk 013 noted about DeepSeek's research. Source: Q-001 (owner, 2026-10-06) Impacts: FR-001, FR-003, US-001
Decision: Only DeepSeek's out-of-credit refusal switches to the fallback. Every other DeepSeek problem shows today's errors. Reason: "If tokens finish" means credit. A broken DeepSeek setup should be seen, not hidden behind Gemini (and Gemini's bill). Source: Q-002 (owner, 2026-10-06) Impacts: FR-003, FR-004, Out of Scope
Decision: A turn that switched shows an amber note in the chat and writes a log warning. Reason: The owner should know when to top up and that Gemini is being billed. Source: Q-003 (owner, 2026-10-06) Impacts: FR-007, US-002
Decision: Each new turn tries the chosen model first. Reason: After a top-up the app returns to DeepSeek by itself. The cost is one fast refused call per turn while the credit is empty. Source: Q-004 (owner, 2026-10-06) Impacts: FR-005, NFR-002
Decision: The owner's local and hosted settings and the settings template start on DeepSeek with the Gemini fallback. Without any model setting, the app keeps its current built-in model and has no fallback. Reason: Owner's choice. Other setups keep working as before. Source: Q-005 (owner, 2026-10-06) Impacts: FR-001, FR-002, Out of Scope
Decision: "Thinking" in the requests means the questions stage, which the chat shows as "Thinking…". It is not DeepSeek's thinking mode, which stays off (013). Reason: It matches the app's own label for that stage. Source: Drafting, 2026-10-06 Impacts: FR-010, Out of Scope
Decision: The starting model is deepseek:deepseek-flash, the example from 013. DeepSeek V4 Pro is on the Settings page's list. Reason: It's the fast, cheaper model, like Gemini Flash today. Source: Drafting, 2026-10-06; confirmed by the owner at approval, 2026-10-06 Impacts: FR-001, FR-009
Decision: After a step switches, the remaining steps of that turn go straight to the fallback model, and the next turn tries the chosen model again. Reason: A zero balance won't recover within a few seconds. This avoids a refused call per step and repeated waits inside one research run. Source: Drafting, 2026-10-06; confirmed by the owner at approval, 2026-10-06 Impacts: FR-003, NFR-002
Decision: Each choice on the Settings page picks from a list of models set in the settings file, shown by readable names. The owner's copies list DeepSeek Flash, DeepSeek V4 Pro and Gemini 3.8 Flash. Reason: Owner's choice. More flexible than a two-way switch, and no typos, unlike a typed name. Source: Q-006 (owner, 2026-10-06) Impacts: FR-009, Out of Scope
Changed by 030 D-003 (2026-10-08): OpenCode Go models have their own fallback for Go's usage limit. Gemini and other models still have none.
Decision: Only a DeepSeek model running out of credit switches to the fallback. A stage set to Gemini (or any other model) shows today's errors when it fails. Reason: Owner's choice. Gemini's limits are rate quotas, not prepaid credit, so "out" is hard to tell from "busy". Source: Q-007 (owner, 2026-10-06) Impacts: FR-004, Out of Scope
Decision: The chosen models are saved with the app's data and survive restarts and releases. The settings file gives only the starting choice. A Reset puts both back to the starting models. Reason: Owner's choice. The hosted copy shouldn't forget the choice on every release. Source: Q-008 (owner, 2026-10-06). The Reset part changes 016 FR-003, which keeps the settings through a Reset; confirmed by the owner at approval, 2026-10-06 Impacts: FR-011, Superseded Baseline
Changed by 026 D-005 (2026-10-07): the page also has the Reflections section (tone, fewest and most questions). The fallback still stays in the settings file.
Decision: The Settings page has only the two model choices. The fallback model is set in the settings file and only shown on the page. Reason: Owner's choice. Smallest page. Source: Q-009 (owner, 2026-10-06) Impacts: FR-002, FR-012, Out of Scope
Status: answered Answer: The questions and research. Decision: D-001
Status: answered Answer: Only DeepSeek running out of credit. Decision: D-002
Status: answered Answer: Yes, with a small note in the app. Decision: D-003
Status: answered Answer: On every new turn. Decision: D-004
Status: answered Answer: The owner's local and hosted copies and the settings template. The built-in default doesn't change. Decision: D-005
Status: answered Answer: Models from a fixed list. Decision: D-009
Status: answered Answer: No. Decision: D-010
Status: answered Answer: Until changed; restarts and releases keep it. Decision: D-011
Status: answered Answer: No, it stays in the settings file. Decision: D-012
| Metric | Target / Signal | Notes |
|---|---|---|
| Done-when (in credit) | A new chat: questions → research → options → a round → Research again → Confirm, all on DeepSeek, with no note | Needs DeepSeek credit |
| Done-when (out of credit) | The same run completes on Gemini, with the note on each turn and no error card | Needs an empty DeepSeek account or a simulated out-of-credit answer (Constraints) |
| Recovery | After DeepSeek works again, the next turn uses DeepSeek with no restart | |
| Settings | Research set to Gemini on the page → the next chat asks with DeepSeek and researches with Gemini, no restart; the choice survives a restart; a Reset puts it back to DeepSeek | |
| No hidden failures | A wrong DeepSeek key → Model error with Retry, Gemini not used. No fallback set → today's error. A stage on Gemini failing → today's error |
| Risk | Impact | Mitigation |
|---|---|---|
| DeepSeek handles research or the option cards poorly (013 risk) | Medium | Checked with a real run before review. Errors show with Retry. Research can be set to Gemini on the Settings page |
| The owner's DeepSeek account can't easily be emptied, so the real out-of-credit answer is never seen before release | Medium | Design defines how the out-of-credit answer is recognised and how it's simulated for the check |
| Gemini quietly takes over for a long time and costs more than expected | Low | The note on every switched turn (FR-007) and the log warning |
| A turn that switches mid-research mixes both models' work | Low | Accepted (Constraints). The time limit still applies |
| A model on the list has no key set, and choosing it only fails on the next turn | Low | The usual error with Retry; the owner picks another model on the page |
4b1c3736, last commit 8d667c1 plus local changes, with 016's Reset), so the hosted copy shows these issues until a follow-up release. The parallel 017 worktree teal-rook no longer exists (its worktree and branch are both gone as of 2026-10-12), so there is nothing left to reconcile.Status: Approved (2026-10-06)
Source: PRD "New look for UngradedMinds (proposed spec 017)" by @Happiness, 2026-10-06, pasted by the owner. Design: the canvas "Ungraded Minds – Desktop Flow" (14 screens and a component sheet). Changes how screens look in001,003,007,008,009,011,012,015and016; changes no behaviour
Last Updated: 2026-10-06
The app works, but it doesn't yet look or sound like the product in the new designs: a warm companion for Indian students, not a developer tool. This spec gives every screen the app has today the look from the designs: colours, type, shapes, buttons, cards, trust labels, dialogs, messages, drawings, the logo and the name "Ungraded Minds".
It changes how the app looks, not what it does. Anything the designs show that the app can't do today stays out (see Out of Scope); each of those needs its own spec.
Design elements the app has no behaviour for stay out, even where a mock-up shows them:
| Shown in the designs | Why it is out |
|---|---|
| Choosing a goal and a decide-by date; the pinned goal strip; Edit goal warning | The app has projects with a description, not goals *Partly superseded by 020 FR-001 and FR-006 (2026-10-06): goals, with an optional decide-by date, are now chosen on the New goal form and listed in My Goals; the pinned goal strip stays out.* |
| Date of birth, class, board and state fields on About you | The details form asks for name, location, age and educational background (D-007) *Superseded by 020 FR-018 (2026-10-06): onboarding step 1 now asks for the year of birth (not a full date of birth), class, board and state, among other fields.* |
| Tab bar with Discover, Decide and Act; tab states (done, outdated) | A chat is one page in time order with a section index (011) |
| Evaluate, Compare, Choose and Next steps screens | No such steps exist |
| Home with My Journey and the journey bar; a rail with Home and My Journey | No such screens exist (D-003) |
| Ask drawer | There is no free chat after the options exist (product boundaries) |
| Tappable answer chips and "Question 4 of about 8" | Questions are free text with no set count today (D-005) *Partly superseded by 025 FR-001 (2026-10-07): questions now come with suggested-answer chips; the question counter stays out.* |
| Class 8–9 version with softer copy and brighter tiles | The app has no age-based version *Partly superseded by 020 FR-018 (2026-10-06): "Class 8–9" is now a choice on onboarding step 1; the softer copy and brighter tiles stay out.* |
| Toast messages such as "Added to shortlist" | New feedback the app doesn't give today (D-004) |
| Options as a two-column grid | Options show one card at a time in a viewer (012, D-001) |
| Icons for projects and chats in the collapsed sidebar | The thin strip holds only the expand button and the reminders-due count (011 FR-013, D-003) *Partly superseded by 021 FR-006 (2026-10-07): the strip has one icon per menu entry, including My Goals; still no icon per goal or journey.* |
Also out:
As a student I want every screen to look warm and consistent So that the app feels like a companion that shows me the path
Acceptance Criteria:
As a student I want each source on an option to show clearly how far it can be trusted So that I can judge a claim at a glance
Acceptance Criteria:
As a student I want my mark on each option to be obvious from its colour and label So that I can scan my list quickly
Acceptance Criteria:
As a student I want to see what the app is doing during research, and what I can do if it fails, in calm, plain words So that a failure doesn't feel alarming
Acceptance Criteria:
As a student I want dialogs to say what will happen and make the safe choice easy to find So that I never lose anything by accident
Acceptance Criteria:
As a student I want text I can read comfortably and controls I can reach with the keyboard So that the app works for me however I use it
Acceptance Criteria:
As the owner I want a list of every difference between a screen and its design So that I can approve the look by reading this document
Acceptance Criteria:
Exact colours, sizes and spacing come from the designs' component sheet. These requirements say what must be true.
Partly superseded by 029 FR-006 (2026-10-08) (029-first-run-and-brand-polish): the name is written in the app's heading font (not a handwritten script), a little bigger, with "Un" in blue. The words and where the name appears are unchanged.
Partly superseded by 020 FR-017 (2026-10-06): the first-run details screen is now onboarding step 1, Tell us about you, which is also shown once as Update your details to students whose details were saved in the old form (020-my-goals-onboarding). The original text is kept below for history.
THE SYSTEM SHALL show the name as two words, Ungraded Minds, in the browser tab title, the sidebar header, the start screen and the first-run details screen.
Documents, the README and package names keep their names, as in 011 D-004.
*Replaces the one-word "UngradedMinds" in 011 FR-015.*
Partly superseded by 037 FR-002 (2026-10-10) (037-basecamp-and-sidebar-polish): there is no separate start screen any more. The app opens on Basecamp, which shows the logo as its title, with the line and + New goal, only when there are no goals.
Partly superseded by 029 FR-006 (2026-10-08) (029-first-run-and-brand-polish): the name beside the heart is in the heading font with "Un" in blue, not "a rounded handwritten script"; in the sidebar the heart is slightly smaller so the name fits.
Partly superseded by 020 FR-017 (2026-10-06): the first-run details screen is now onboarding step 1 (also shown once as Update your details); the logo has its line "Your future isn't a grade." there only, not on step 2 (020-my-goals-onboarding). The original text is kept below for history.
THE SYSTEM SHALL show the logo from the designs: a blue heart with a green and an orange figure, with the name in a rounded handwritten script:
Partly superseded by 020 FR-017 (2026-10-06): the first-run logo lockup is on onboarding step 1 and on the one-time Update your details screen, and not on step 2 (020-my-goals-onboarding). The original text is kept below for history.
THE SYSTEM SHALL show "Your future isn't a grade." only in the first-run logo lockup, and no other tagline anywhere.
The start screen keeps its description line "Get researched recommendations for what you want to achieve." (003); it is a description, not a tagline.
THE SYSTEM SHALL address the student as "you" and "your" in every text meant for them, never in a parent's voice, and never use the name "Mera Bachha".
*Today's texts already meet this; the rule keeps it so.*
THE SYSTEM SHALL show nothing as a score, rank, winner or comparison with other students.
The levels (Easy, Medium, Hard, Not fit) stay, shown as plain labels: one neutral style, none of them red, Not fit in neutral grey (D-002).
THE SYSTEM SHALL show pages on a pale blue-white background, and cards in white with rounded corners and soft, low-contrast shadows.
Partly superseded by 029 FR-006 and D-005 (2026-10-08) (029-first-run-and-brand-polish): the handwritten script is used only for short encouraging lines; the logo's name is in the heading font.
THE SYSTEM SHALL show headings in deep navy in a bold, rounded sans-serif, and body text in slate. A handwritten script is used only for the logo and short encouraging lines (the logo line and the first-run note, FR-019).
THE SYSTEM SHALL use royal blue for main actions and links. Pastel tiles (mint, sky, peach, lavender, blush, teal) carry a matching, stronger icon colour.
THE SYSTEM SHALL use simple line icons with one consistent line weight wherever the app shows a symbol today (expand and collapse, close ×, the viewer's ‹ ›), and for the drawings in FR-029.
THE SYSTEM SHALL show body text at 16px or larger on every screen, and no label, badge or count below 13px.
*Today, badges, the reminders count and section headings are 12–12.8px; they grow to at least 13px. 012 FR-007's 16px base stays.*
THE SYSTEM SHALL show:
Each form, dialog and picker has one main button. The Reset button in the corner stays quieter than the main actions (016 NFR-001).
THE SYSTEM SHALL give every control a hover look and a clear keyboard-focus ring. A control that shows only an icon shows its name on hover, and screen readers hear that name.
THE SYSTEM SHALL give text fields and choice chips (the rule-out quick picks, the reminder quick picks, the level tabs) one shared rounded look. A chosen chip is filled blue.
THE SYSTEM SHALL keep cutting long names off with "…" and showing the full name on hover, as today (001 FR-028).
THE SYSTEM SHALL keep today's layout at the top: no top bar, the logo in the sidebar header, and Reset floating in the top right corner of the main area (016 FR-001, 016 design TD-005). The chat's "<project> / <chat>" line stays at the top of the chat (001 FR-010). The student's name is not shown (D-013).
Partly superseded by 037 FR-008 (2026-10-10) (037-basecamp-and-sidebar-polish): the sidebar and the strip are light grey (#eceff3), not white; the open item stays soft blue.
Partly superseded by 021 FR-001 and FR-006 (2026-10-07) (021-sidebar-menu): the sidebar's items and order are now the menu My Details, My Goals (with the goals), Reminders, Settings, with Reminders and Settings pinned at the bottom; the 72px strip holds Expand and the four menu icons. The 260px width, white surface and soft blue open item stay. The original text is kept below for history.
Partly superseded by 036 FR-007 (2026-10-09) (036-compact-stepper-sidebar-summary): the open sidebar is no longer 260px; it is about 272px at a 1,280px window, growing to about 304px on large windows. The 72px strip, the white surface and the soft blue open item stay. Goal and journey rows now carry a small symbol (036 FR-008, FR-009).
THE SYSTEM SHALL keep the sidebar's items, order and behaviour, at 260px wide when open. It is white, and the open item is soft blue.
WHEN the sidebar is collapsed THE SYSTEM SHALL show a slim strip 72px wide (today 44px) holding the same things as today: the Expand sidebar button and the reminders-due count (011 FR-013, D-003).
THE SYSTEM SHALL keep the chat's contents centred at up to 1,100px wide (012 FR-006), and centre the other pages (a project, General, New project, Reminders due) at up to 880px (D-014). The chat's section index stays next to the scrollbar, restyled.
THE SYSTEM SHALL be designed for windows 1,280–1,920px wide. This spec adds no mobile layout.
Superseded by 020 FR-013 to FR-018 and FR-023 (2026-10-06): the first run has two steps, Tell us about you and What would you like help with?, with a thin progress bar and "Step 1 of 2" or "Step 2 of 2", new fields on step 1 and Next instead of Continue, and a handwritten note on each step's illustration panel; Your details (formerly General) shows step 1's fields without the panel (020-my-goals-onboarding). The original text is kept below for history.
WHEN the first-run details form is shown THE SYSTEM SHALL show two columns:
There is no progress bar, because the form has one step. General shows the same fields in the new card and field look, without the illustration.
THE SYSTEM SHALL show the AI's questions (Discovery and rounds) as white speech bubbles on the left, and the student's answers as blue bubbles on the right. The latest question, while it waits for an answer, sits in a highlighted card.
The message box keeps its place at the bottom (012 FR-008) and its behaviour. AI text that isn't a question (the recommendation text of older chats, the round's closing line) is not put in a bubble.
*Changes the look in 001 FR-024 (the AI's replies were unboxed).*
WHILE research runs THE SYSTEM SHALL show, in the new look, what it shows today: the stage, each search on its own line, and the sources each search found (title and link). A finished run looks the same when the student comes back. Nothing re-runs.
The research list shows no trust labels (D-009).
IF a model, research or button error happens THE SYSTEM SHALL show it in the soft coral palette, in the same place, with the same words ("Model error: …", "Research error: …", "Couldn't save: …") and the same Retry or Dismiss as today: the banner at the top of the main area as a calm card, the error under an option card as a calm line. Field errors on forms use the same coral.
The Opik tracing warning (002) and the in-app reminder alert (009) keep their words and buttons, shown as soft peach cards so they stay distinct from errors.
*Replaces "red" in 001 FR-025, 003 FR-016, 005 FR-008, 008 FR-024 and the error notes of 007 and 009.*
THE SYSTEM SHALL show each option card with what it shows today, in the new card look: its name, its level and level reason (if it has one), what it is, why it fits (or "Why it might look right" for Not fit), pros, cons, rough cost, sources with trust labels, the mark buttons and Remind. The badges New and Updated and the label "from earlier research" are small pills.
AI's suggestion stays a line above the cards, on a lavender tile, with its wording unchanged.
THE SYSTEM SHALL show:
One mark per option, and pressing the chosen one clears it, as today (007). Ruled-out cards stay in the collapsed "Ruled out (N)" group, as today.
THE SYSTEM SHALL keep the rule-out reason picker, the groups "From earlier research (N)" and "Ruled out (N)", Options at a glance, the level tabs and the options viewer (arrows, dots, "2 of 4") working exactly as today, in the new look (D-001).
THE SYSTEM SHALL show each source on an option card with its site as a link and a colour-coded trust label that writes out its tier:
| Label | Colour |
|---|---|
| Tier 1 official | green |
| Tier 2 news | blue |
| Tier 3 aggregator or coaching | amber |
| Tier 3 likely official, unverified | amber |
| Tier 4 forum or blog | grey |
| Tier 4 unknown or uncertain | grey |
A legend that explains the four colours is shown once in each Options section.
No source can be tier 1 until the known list of official sites exists (006), so green won't appear yet.
*Changes the wording in 007 FR-015 (the tier number is added).*
THE SYSTEM SHALL show Remind, the reminder picker, the "Reminder: …" line with Change and Cancel, and the Reminders due page with Open and Dismiss, in the shared button and card look. The reminders-due count in the sidebar and the strip is orange, with the number written as today.
WHEN the Reset box is shown THE SYSTEM SHALL show it as a centred white card over a dimmed page, with its title, its sentence with the counts, Cancel first (and focused), and Reset everything in coral as the dangerous choice (016 NFR-001, D-008). Its words stay as in 016.
THE SYSTEM SHALL show the match confirmation in the same card look, in its place inside the Research section (D-010).
THE SYSTEM SHALL show the other confirmations (delete a project, rename a chat, delete a chat, discard new research) as app dialogs in the same look as the Reset box, with today's words, today's choices and the safe choice first (D-015).
THE SYSTEM SHALL show the empty states (the start screen with no project open, "No chats yet.", "No reminders due.") with today's line and one small drawing (a sun, a sprout or hills), used sparingly. Loading lines ("Loading…", "Thinking…", "Researching…", "Saving recommendation…" and the others) keep their words, in the new type.
Partly superseded by 020 FR-012 (2026-10-06): the words on screen listed in 020 FR-012 changed too: project becomes goal, chat becomes journey, New chat becomes New journey and General becomes Your details; behaviour is still unchanged by this spec (020-my-goals-onboarding). The original text is kept below for history.
THE SYSTEM SHALL keep what every control does, what is saved, and what leaves the machine exactly as the earlier specs say. Words on screen stay as they are, except where FR-001, FR-002 and FR-026 change them (D-011).
conventions.md stays unchanged.Screens and their closest design (canvas screen numbers; "—" means the component sheet sets the look):
| Today's screen | Closest design | What changes (look only) |
|---|---|---|
| First-run details form | 1 About you | Two columns, logo lockup, illustration panel, rounded fields (FR-019). Fields stay as today (D-007) |
| General | 1 About you (form card only) | Card and field look (FR-019) |
| Start screen (no project open) | — | Logo as title, today's line and button, a drawing (FR-002, FR-029) |
| Sidebar with projects, chats, Reminders due | Left rail | White surface, soft blue open item, 72px collapsed strip with today's contents (FR-016) |
| Project page, chat list, New project | — | Card look, 880px width, empty-state drawing (FR-017, FR-029) |
| Chat: Questions and rounds | 3 Questions | Speech bubbles, highlighted current question (FR-020) |
| Chat: live and saved research | 5 Research | Stage, search lines, sources; no trust labels (FR-021) |
| Chat: AI's suggestion, Options at a glance, level tabs, cards, viewer | 6 Options | Card, badges, plain level labels, mark colours, lavender suggestion tile, trust legend (FR-023–FR-026) |
| Rule-out reason picker | 6 reason panel | Same inputs, new chips and buttons (FR-013, FR-025) |
| Message box, Research again, Go to options, Add more about me | 6 hint banner | Field and pill buttons (FR-011, FR-013) |
| Match confirmation | 4 Confirm dialog (card look only) | Card look, stays inline (FR-028, D-010) |
| Reset | 4 Confirm dialog | Dimmed page, counts kept, coral Reset everything (FR-028) |
| Delete project, rename chat, delete chat, discard research | 4 Confirm dialog | App dialogs instead of the browser's boxes (FR-028, D-015) |
| Remind, reminder picker, Reminders due | — | Shared buttons, chips and cards; orange count (FR-027) |
| Error banner, error under a card, field errors | 5 error states | Soft coral (FR-022) |
| Opik warning, in-app reminder alert | — | Soft peach card (FR-022) |
| Trust labels on option sources | Component sheet, tier legend | Six coloured labels with the tier written out, plus a legend (FR-026) |
Known differences from the designs, beyond Out of Scope: the chat column is 1,100px, not 880px (D-014); there is no top bar and no name on the right (D-013); level labels and tabs, which the designs don't have, are shown (D-002).
product.md (glossary entry for the name), tech-stack.md (styling: light only, fonts and icons shipped with the app), conventions.md (errors are soft coral, not red; confirmations are app dialogs).The PRD was written on a recommended default for each place where the designs and the app disagree. D-001–D-008 record those defaults (PRD decisions 1–8); D-009–D-011 come from checking the PRD against the specs and the code; D-012–D-015 are the owner's answers to Q-001–Q-004. Approving these requirements confirms D-001–D-011.
Decision: Options stay in 012's viewer; only the cards are restyled. Reason: A two-column grid changes how options are browsed and needs its own spec. Source: PRD decision 1 Impacts: FR-025, Out of Scope
Decision: Easy, Medium, Hard and Not fit, Options at a glance and the level tabs stay. Level labels use one neutral style; none is red (today Hard is red and Medium amber). Not fit is neutral grey. Reason: Colour on levels can read as good and bad, which FR-005 forbids. Removing levels would be a behaviour change. Source: PRD decision 2 Impacts: FR-005, FR-023, FR-025
Decision: The sidebar keeps its items and behaviour. Collapsed, it is 72px wide, matching the designs' rail, and holds only the expand button and the reminders-due count. Reason: A real rail (Home, My Journey, icons for projects and chats) needs a new way to reach projects and chats. Source: PRD decision 3; the strip's contents from 011 FR-013 Impacts: FR-016, Out of Scope
Decision: No "Added to shortlist" or similar messages. Reason: The card already shows the mark; a toast is new feedback. Source: PRD decision 4 Impacts: Out of Scope
Partly superseded by 025 FR-001 (2026-10-07): answer chips now exist (suggested answers under each question, 025-answer-suggestions); the question counter stays out. The original text is kept below for history.
Decision: Both stay out. Reason: Today's questions are free text and the AI asks a varying number (1–5), so neither exists to restyle. Source: PRD decision 5, checked against today's app Impacts: Out of Scope, FR-020
Decision: The two design fonts, the icons and the drawings are files inside the app, not loaded from the web. The design records this as a technical decision. Reason: Loading web fonts would send a request to an outside service, which the privacy rules don't allow. Source: PRD decision 6 Impacts: NFR-001, NFR-006, Constraints
Decision: The details form keeps name, location, age and educational background. *Superseded by 020 FR-018 (2026-10-06): the details are now first name, year of birth, where the student is, board and stream (or what they study), state and city.* Reason: The designs' date of birth, class, board and state would change what is collected and saved. Source: PRD decision 7 Impacts: FR-019, Out of Scope
Decision: Reset everything is coral. Reason: 016 NFR-001 already asks for it to look dangerous; coral is that style in the new palette. Not an addition. Source: PRD decision 8 Impacts: FR-028
Decision: The research list shows sources as today, without trust labels. Option cards show them. Reason: Adding them would reverse 007 D-008 and add information to a screen, which is a behaviour change. The PRD's FR-021 asked for them. Source: Check against 007 D-008 Impacts: FR-021, US-002, Out of Scope
Decision: It keeps its place at the end of the Research section, in the dialog card look, not as a pop-up over a dimmed page. Reason: 008 FR-020, 011 FR-005 and 012 keep it an inline list; a pop-up changes where it appears and how the page scrolls. Source: Check against 008, 011 and 012 Impacts: FR-028
Decision: Every text on screen stays word for word, except the name (FR-001), the logo line (FR-002) and the tier number in trust labels (FR-026). *Partly superseded by 020 FR-012 (2026-10-06): the texts in 020 FR-012 changed: project becomes goal, chat becomes journey, New chat becomes New journey and General becomes Your details.* Reason: Earlier specs fix many texts ("No chats yet.", "Thinking…", "Reset everything?", …). Rewording each would need its own list; the PRD names no new texts. Source: Check against 001–016 Impacts: FR-029, FR-030
Decision: The app has one light look, whatever the computer's light or dark setting. Reason: The designs define only a light look; a dark version would have nothing to be checked against. Source: Q-001 (owner, 2026-10-06) Impacts: NFR-008; supersedes the theme part of 001 FR-032
Decision: No top bar. The logo stays in the sidebar, Reset floats in the top right corner as today, and the student's name isn't shown. Reason: Keeps the owner's choice in 016 (design TD-005). Source: Q-002 (owner, 2026-10-06) Impacts: FR-015, UX Notes
Decision: The chat's column stays up to 1,100px (012 FR-006). The other pages use the designs' 880px. Reason: The wide chat was the owner's request in 012. Source: Q-003 (owner, 2026-10-06) Impacts: FR-017, UX Notes
Decision: Deleting a project, renaming a chat, deleting a chat and discarding new research use app dialogs in the Reset box's look, with today's words and choices. Reason: The browser's boxes can't be restyled; the app already has one such dialog. Source: Q-004 (owner, 2026-10-06) Impacts: FR-028, NFR-003, UX Notes; the look of 001 FR-007, FR-013 and FR-014
Status: answered Answer: Light only. Decision: D-012
Status: answered Answer: No top bar; Reset floats top right as today. Decision: D-013
Status: answered Answer: Keep 1,100px for the chat; other pages 880px. Decision: D-014
Status: answered Answer: App dialogs in the new look. Decision: D-015
Look and wording only; no behaviour is superseded.
| Metric | Target / Signal | Notes |
|---|---|---|
| Matches the designs | Every screen in the UX Notes table, opened at 1,440px and 1,280px, differs from its design only where this document says | Browser check next to the canvas. A difference not listed is reported, not fixed silently (P-002) |
| Controls | Every control tried with the mouse and the keyboard; hover and focus looks seen | Browser check |
| Nothing lost | A run from the first-run form through questions, research and options, to marks, a reminder, Research again with a match confirmation, a project and chat delete, and Reset, behaves as before | On a throwaway copy of the data |
| Long text | Text 30–40% longer on cards, buttons and dialogs holds | Browser check |
| No outside requests | The browser's network list shows no request to any new outside service | NFR-001 |
| Build | Build and lint pass |
| Risk | Impact | Mitigation |
|---|---|---|
| A look change quietly alters behaviour | High | FR-030 and the full-run check |
| Features the designs imply creep in | Medium | Out of Scope; the report-not-fix rule (P-002) |
| Amber and pastel colours are hard to read; amber means parked, tier 3 and a due reminder | Medium | NFR-002: a contrast check on every label, and every state written as a word |
| The designs are static, so states such as hover are drawn only on the component sheet | Low | The component sheet is the reference for those states |
| The canvas files, fonts or drawings aren't available, or can't be shipped | Medium | Constraints: exported and licence-checked before design |
PERPLEXITY_API_KEY is set (038 FR-010) — a research run saves its options with no sources. advisor.py:1225 empties the run's evidence, the branch never refills it, and structure() (:1349) keeps only URLs already in it; search._deep_research also throws away Perplexity's citations. Verified on a live turn: 6 options, 0 source links. Fix as F19 in PLAN.md; full evidence in 033-deep-research-toggle/review.md. The same review leaves two low items: the FR-002 hint wording and no aria-describedby on the two disabled dropdowns.Status: Draft (requirements)
Source: Owner's request, 2026-10-08: "I want to add a Deep Research toggle in Settings. If on it will use Perplexity Agent API to do both research and use it's own web search. When this setting is on the Research and Web Search dropdowns should be disabled."
Last Updated: 2026-10-08
Today research uses the chosen Research model plus Web Search service. This spec adds a Deep Research toggle on Settings. When on, research is handed to the Perplexity Agent API, which runs its own web searches and returns a reasoned answer with citations. The local Research model and Web Search choices are not used, so their dropdowns are disabled.
Deep Research is off by default.
As the owner I want a Deep Research toggle on Settings So that I can switch research to Perplexity
Acceptance Criteria:
PERPLEXITY_API_KEY is set.As the owner I want research to use Perplexity Agent API when Deep Research is on So that Perplexity handles reasoning and web search
Acceptance Criteria:
web_search tool.As the owner I want Research model and Web Search dropdowns disabled when Deep Research is on So that it's clear those choices don't apply
Acceptance Criteria:
Partly superseded by 038 FR-010 (2026-10-10) (038-new-logo-path-cards-panels): with no saved choice, and after a Reset, the toggle is on whenPERPLEXITY_API_KEYis set and off without it. Its place and saving are unchanged. The original text is kept below for history.
THE SYSTEM SHALL show a Deep Research toggle on the Settings page, below the Web Search choice and above Reflections.
THE SYSTEM SHALL set the toggle to off by default and after a Reset.
IF PERPLEXITY_API_KEY is not set in the settings file THEN the Deep Research toggle SHALL be disabled, with a hint saying "Add a Perplexity key and restart the backend to use Deep Research."
IF the owner tries to turn Deep Research on via the API while the key is missing THEN the system SHALL return 422.
WHEN Deep Research is on THE SYSTEM SHALL send the research task to the Perplexity Agent API (POST https://api.perplexity.ai/v1/responses) with model perplexity/sonar (or PERPLEXITY_MODEL) and tools: [{"type": "web_search"}].
THE SYSTEM SHALL include the same context the local Research model receives: student details, goal, discovery answers, and marks/reasons from Research again.
THE SYSTEM SHALL NOT call the local Research model or the web_search tool during the research step when Deep Research is on.
THE SYSTEM SHALL parse Perplexity's response into:
THE SYSTEM SHALL save the options, top pick and sources the same way as today's research output (spec 005).
WHEN Deep Research is on THE SYSTEM SHALL disable the Research model dropdown and the Web Search dropdown on the Settings page.
THE SYSTEM SHALL still return their current saved values in GET /api/settings so the page can display them.
WHEN the owner turns Deep Research off THE SYSTEM SHALL save it immediately and use the local Research model + Web Search choice for the next research turn.
Partly superseded by 038 FR-010 (2026-10-10) (038-new-logo-path-cards-panels): a Reset puts Deep Research back to its default, on when the key is set. A saved choice is still kept across restarts and releases.
THE SYSTEM SHALL keep the Deep Research setting across restarts and releases, and a Reset SHALL put it back to off.
Switching Deep Research on or off never loses saved journeys, answers, options, marks or reminders.
The settings template and README explain Deep Research, that it needs PERPLEXITY_API_KEY, and that it disables the Research model and Web Search choices.
PERPLEXITY_API_KEY.advisor.py, and possibly the option-saving code.Superseded by 038 D-008 (2026-10-10) (038-new-logo-path-cards-panels): on by default when the key is set, unless the owner saved "off".
Decision: The toggle starts off and Reset turns it off. Reason: Preserves today's behavior; opt-in feature. Impacts: FR-001, FR-006, FR-007.
Decision: When on, research is sent to https://api.perplexity.ai/v1/responses with the web_search tool. Reason: Perplexity can search and reason in one call. Impacts: FR-003, FR-004.
Decision: Research and Web Search dropdowns stay visible but disabled when Deep Research is on. Reason: The owner sees what values will apply when Deep Research is off. Impacts: FR-005, US-003.
Decision: If Perplexity fails, the run fails with the usual error card and Retry. Reason: Avoids silently switching research strategy. Impacts: Out of Scope, NFR-001.
Status: open Question: Should Deep Research also disable web_search during Discovery, or only the final research step? Leaning: Only the final research step.
Status: open Question: Perplexity returns text + citations. Should the prompt request JSON, or should a second model call extract options? Leaning: Request JSON from Perplexity; fall back to structured extraction if JSON fails.
| Metric | Target |
|---|---|
| Toggle | Deep Research toggle appears, saves, survives restart, Reset restores off |
| Disabled dropdowns | Research and Web Search dropdowns disabled when on, enabled when off |
| Deep research | With toggle on and Perplexity key set, a full research turn returns options with sources |
| Off mode | With toggle off, behavior identical to before this spec |
| Risk | Impact | Mitigation |
|---|---|---|
| Parsing Perplexity's answer into options is unreliable | High | Request JSON output; validate; fallback to extraction |
| Perplexity Deep Research is slower or more expensive | Medium | Opt-in toggle |
| Disabling dropdowns confuses users | Low | Show helper text under the toggle |
web_search tool.about.goal_name), but the API still saves a journey title of only spaces as blank (the UI blocks it, ConfirmDialog.tsx). Only the residual journey-title case is left
main.py, advisor.py); very long journeys can exceed the model's limit. Only the shared Compass conversation is capped (last 20 rows, 041 FR-013)
tech-stack.md says "Test — none yet"
main opsPERPLEXITY_API_KEY, so Deep Research stays off there (038)
main, and its data survives the releasePERPLEXITY_API_KEY is set (038 FR-010) — a run saves its options with no sources: the research branch empties the run's evidence and never refills it, while Perplexity's own citations are discarded. Deep Research itself is shipped; this is its fix, and it should land before the next hosted release
GoalView.tsx)