Website source and local backups: GitHub is the private source repository intended to feed the website. Dated local copies live in ignored .local-backups/ on this computer. The hourly sync preserves a local snapshot before pulling and pushes completed, checked work. See sync setup and local recovery. Website hosting connection and Supabase/cloud configuration remain deferred.
A private, persistent saved-contact recognition app. Find someone is the homepage. Contacts and Review details include imports, nested groups, safe duplicate review, durable controlled enrichment and source-linked memory cues. This is the locally validated core beta. External tester readiness remains conditional on the operational prerequisites in BETA_READINESS. The configurable remote adapter is disabled; no live model calls, paid resources, invitations or deployment were used.
Current scope: private My profile, invited-account setup and adaptive Find someone. Open http://127.0.0.1:3002, serving .next-owner-quiz. The account menu opens the private owner profile; the approved large blue quiz controls use common-first and balanced questions with replayable history. Contacts folders, Settings and expanded contact profiles remain in place. Apply additive migrations 018–019 to an existing local database; do not reset it. See profile/quiz behavior and migration notes and current verification results. Historical milestone results below remain historical evidence.
The supplied handoff is preserved in contact-recall-codex-handoff/; its planning documents were copied to the repository root as instructed by START_HERE.md. Milestone 1 started from that handoff; milestone 2 extends its existing application and persistence without replacing the stack.
Prerequisites: Node.js 22.17+ (tested with 22.17.0), npm 10+, Docker Desktop or a compatible running Docker engine. Initial npm, Supabase image, and Chromium downloads require internet access and disk space. No cloud account is needed.
npm ci
npm run db:start
npx supabase migration up --local
npx tsx scripts/local-env.ts
npm run seed:local
npm run dev
Open http://127.0.0.1:3000. Use that hostname consistently. local-env.ts reads the local CLI status into the ignored, mode-0600 .env.local without printing credentials. It refuses to overwrite an existing file. .env.example describes the required variables; .env.local is never committed. Local test scripts refuse hosted Supabase URLs. They default to port 54321; LOCAL_TEST_SUPABASE_PORT=55321 selects only the separate disposable validation stack. The existing .env.local is never overwritten.
Mutations check APP_ORIGIN (defaults to http://127.0.0.1:3000) exactly; set it explicitly if you deliberately use a different application origin. Untrusted forwarded headers do not configure this check.
The opt-in seed creates fictional local users with confirmed email without sending email:
| Local account | Password | Access |
|---|---|---|
alex@recall.test |
Local-Recall-Only-2026! |
Approved; eight fictional contacts |
blair@recall.test |
Local-Recall-Only-2026! |
Separate approved library |
uninvited@recall.test |
Local-Recall-Only-2026! |
Deliberately denied beta access |
These are public, local-only fixture credentials, never production credentials. Re-running the seed preserves nonempty libraries. Each seeded account has same-name contacts, overlapping affiliations, aliases, sparse data, former employers, shared emails, and an explicitly synthetic pending observation that the quiz ignores.
To try the workflow: add a contact in Contacts, save a note, close the drawer, open Review details to add a remembered trait, then use Find someone’s sentence box and Show people who might match. Open the recognition card and View your original notes. Reload to verify your records persist.
# Production server, still local only:
npm run build
npm run start
# Stop the backend while retaining its local volumes:
npm run db:stop
# Resume it:
npm run db:start
After adding migrations to an existing local database, run npx supabase migration up --local. npm run db:reset is provided for a disposable local test database only: it erases local records, reapplies migrations, and requires another npm run seed:local. Do not reset a library you want to keep.
npm test # Pure domain tests; no network, DB or paid services
npm run typecheck
npm run lint
npm run build
npm run test:integration # Real local Auth/Postgres RLS/Storage tests
npm run test:enrichment # Backend tests with isolated fake providers
npm run test:profile # Section edits, ownership, review states and preservation
npm run test:folders # Atomic memberships, hierarchy, ownership and capacity
npx playwright install chromium
npm run test:e2e # Uses the production build and real local backend
# With npm run start running in another terminal:
npm run test:pagination # Real API check with 1,005 temporary review decisions
All backend and browser suites create isolated temporary local accounts and clean up only their own records and private photos. The browser suite no longer uses or modifies the seeded Alex/Blair libraries; seed:local is optional for manual exploration and is not a test prerequisite. Its account worker runs in a separate Node/tsx process to avoid a Node 22/Playwright SDK-loading conflict, and refuses any backend except localhost port 54321. Normal failures and parent disconnects trigger cleanup; a forced machine/process termination can still leave temporary synthetic accounts. The pagination API check needs a running production app (port 3000 by default, or PLAYWRIGHT_BASE_URL for another local port). Screenshots and failure traces are in ignored test-results/. The E2E server starts automatically unless a server is already listening on the configured local port. Build first, and stop an outdated server before running E2E. Tests do not contact AI providers or send invitations.
Current exact verification results, limitations, and remaining scope are in docs/BUILD_STATUS.md.
Milestone-4 evidence adds source-deletion retention, negative/appearance search, independent clue recovery, unchanged-field keyboard navigation, interrupted-import retry, concurrent edits, bounded upload handling, clean setup and measured scale checks. Passed: 65 domain, 21 backend, 19 enrichment and one pagination test; 18/18 Chromium and 18/18 Firefox workflows; type checks, lint, formatting and production build. The 2,000-contact run and disposable clean setup passed. WebKit is blocked before page creation; npm audit returned a registry error. See BUILD_STATUS for exact commands and results. All fixtures are fictional; live-provider quality, actual billing and availability remain unverified.
lib/domain/ contains typed input validation, the deterministic sentence parser/ranker, session reducer, question utility, fixtures and Review details queue. Recognition remains independent of enrichment: no model, embedding, face-matching, scraping or remote-avatar requests run in ordinary search/quiz/profile reads. lib/enrichment/ implements the separate provider/worker boundary.app/api/ verifies Supabase users and active beta membership for every protected operation. Mutations also require the same origin. Session cookies are HTTP-only; personal API/media responses use private, no-store. Pending requests cannot restore a previous account’s UI after sign-out.supabase/migrations/ establishes explicit grants, RLS, same-owner/contact composite foreign keys, append-only notes/sources/encounters, confirmed/pending observations, groups, photos and transactional contact saves. Ordinary requests use the authenticated user’s client, never the service-role key. The service key is server-only, used by local setup/tests and the explicit enrichment worker. Worker RPCs are unavailable to ordinary users and recheck owner, active membership, source versions, consent and budget before accepting work.Keep Docker running, stop an older app process, and run:
npx supabase migration up --local
npm run build
npm run start
Migrations 202610220003_organization.sql and 202610220004_import_retries_and_priorities.sql are additive. They preserve current contacts, notes and photo paths. Do not use db:reset to upgrade. Those milestone-2 migrations require no new environment variables or paid services. Migration 202610220005_comparison_evidence.sql extends the private review-signature bound and rejects new merges exceeding the existing 30-affiliation editor limit. It retains all existing review decisions and contact data. Migrations 006_enrichment, 007_enrichment_recovery, 008_account_photo_reuse and 009_suggestion_contact_relation add jobs, budgets, note-version metadata, cues, source-linked reviews, safe recovery and private result reuse. Migration 010_enrichment_group_priority applies saved manual/nested smart group priorities to newly queued jobs. Migration 011_deleted_enrichment_sources removes unedited/unpinned summaries when their notes are deleted, and removes photo jobs/caches when their source photo is deleted. Those eleven migrations were applied locally during the original milestones. The current profile/Settings/folder build requires migrations through 017; all are applied in this local preview. Folder migrations 016–017 preserve IDs, records, parents and memberships while allowing same-named subgroups in different branches and adding an atomic membership operation. See folder upgrade notes. Older active merge fingerprints may require explicit reconciliation during Undo; originals and later edits stay preserved. No earlier migration was modified.
Name:, Email:, Phone:, Link:, Company:, School:, Role:, Met: and Note: lines, then select Fill in the fields from my description. Review the fields and save. Plain two-to-four-word name lines and obvious emails are recognized conservatively. Unparsed text stays intact in Original description or imported text. Fill in the details preserves the draft; no model is involved. Company/school timeframes default to unknown.In Review details, check AI progress and suggested details or approve help for selected contacts. Set account-wide automatic help and spending limits in Settings. Saved contact/group priorities, including nested smart-group rules, influence selective processing. Group priority is captured when a job is queued; changing priority alone never creates a model request. Fill in the details is still available in Add contact; existing contacts default to manual. Describe the person saves in assisted mode, but assistance is disabled at the account and server levels until explicitly enabled. Turning an existing contact’s assistance on is an explicit choice in its profile. Existing imports remain manual; a bulk approval can process selected saved photos or notes without changing those contacts’ automatic mode.
The save transaction persists its outbox rows with the contact/source. Workers can only see committed records; no model request runs in the save handler. Jobs show pending, processing, completed, failed, blocked, cancelled or stale states. Review details polls existing state while work is pending; Check progress also reloads stored results. Neither operation enqueues work or calls a model. Cancel stops future dispatch/acceptance; a request already sent cannot be unsent.
Photo suggestions appear next to their exact private source photo. Approve, correct or reject each field, or Skip for now. Only explicit approval copies the four existing appearance fields into confirmed quiz observations; stale browser approvals fail revision checks. Optional skin-tone suggestions are always uncertain, saved in photo-review history after approval, and are not an additional quiz field in this milestone. Unknown is never manufactured as No. Unclear, multiple-person and no-person results request a clear single-person photo/crop; no subject is guessed. Rejected/unchanged inputs do not automatically reappear.
Generated note cues appear immediately as Unreviewed summary, with links to the exact original note IDs/versions. They are display aids, never independent search/quiz facts. Profiles and Review details support cue edits, pins, review and dismissal; recognition shows the preferred cue and More things to remember. Manual mode uses original-note excerpts or user-written cues without remote processing. Correcting a source keeps its original body and creates a new current version. Deleting a note removes that entry and its text from stored job inputs. Affected cues become outdated and disappear from current recognition; edited/pinned text is retained under Things to remember that may be out of date, never silently overwritten. Deleting a source removes unedited/unpinned generated summaries that use it. Edited or pinned copies remain outdated and explicitly show when their source was deleted; there is no dead source link. A source-free manual cue remains the user’s own content. Independently stored original import text and user-edited cues are not implicitly deleted with a note entry.
Processing new sources on a currently merged profile is paused: undo the active merge first. Existing valid cues retain their original contact/source IDs through merge and undo. Derived edits now participate in undo reconciliation. Unreviewed photo output never overwrites approved facts, curated groups, relationships or affiliation history.
No prior provider had been selected. This implementation supplies a genuine OpenAI Responses adapter with configurable model, constrained JSON output, supplied image bytes, no tools and store: false. The request format follows the official structured-output documentation. Live behavior was not tested. No credentials were created or reused, no private content was transmitted, and the current .env.local remains unchanged. No local vision adapter is implemented and there is no paid fallback.
Before a separately authorized live test, an operator must securely configure the following server/worker variables in the ignored .env.local; see .env.example. Do not put a key in any NEXT_PUBLIC_* variable or source file.
| Variable | Requirement |
|---|---|
ENRICHMENT_REMOTE_ENABLED |
Explicitly true only after authorization; default false. |
OPENAI_API_KEY |
Authorized server-only credential. No key is needed for normal contact management or tests. |
OPENAI_ENRICHMENT_MODEL |
An explicitly chosen model supporting image input and strict JSON output. No model is hardcoded in business logic. |
ENRICHMENT_INPUT_USD_PER_MILLION / ENRICHMENT_OUTPUT_USD_PER_MILLION |
Verified conservative prices for the chosen model, including billable output/reasoning tokens. Positive finite values required. |
ENRICHMENT_PHOTO_TOKEN_BOUND |
Verified conservative bound for one low-detail image for that model. Unknown bounds keep processing unavailable. |
SUPABASE_SERVICE_ROLE_KEY |
Server-only worker access to the configured database. The local development value is already configured; never send it to the provider or browser. |
Then, using a fictional account and explicitly approved scope/budget in Review details, start the durable worker in a separate terminal:
npm run enrichment:worker
# One polling cycle, useful for an authorized operator check:
npm run enrichment:worker -- --once
With current disabled/missing configuration, the command exits 1 with a genuine unavailable message and makes no request. A worker is not started by opening the app. The production worker can instantiate only the real adapter; fake providers live under tests/helpers/, and synthetic browser job rows visibly say TEST ADAPTER.
Each attempt reserves a conservative micro-USD cap transactionally: (32,000 input bytes + 16,000 overhead tokens + configured image-token bound) × input rate + 1,200 output tokens × output rate. USD-per-million-token rates are numerically micro-USD per token. This intentionally overestimates small text jobs. A fresh account has no spending permission. Each explicit automatic or selected-scope bulk approval has a hard budget of at most $100. Replacing an automatic budget closes the previous approval; it does not erase previous charges. Concurrent reservations cannot exceed a budget. Known usage releases unused allowance; uncertain failures keep the full charge allowance. These amounts are not provider invoices. Their validity depends on correctly configured current model prices/token bounds, which remain unverified live.
Leases last two minutes; provider requests time out after 45 seconds. At most three attempts are permitted per unchanged job. Explicit provider rejection such as HTTP 429 may retry after 30 seconds. An expired undispatched lease recovers automatically. A lost response/timeout or expired dispatched lease stops for explicit retry, because it may already have incurred a charge; the UI reports unknown outcomes. Exactly-once external processing cannot be guaranteed after an unknown network outcome. Explicit retry may repeat the request and consumes another reservation. Changing a budget cannot reset the attempt limit.
Unchanged inputs deduplicate within their contact/account/schema. Completed identical-photo results can also be reused across contacts within the same account and provider/model, preserving the new contact’s source photo and returning pending suggestions. Different accounts never share results. Concurrent identical-photo jobs wait for existing work. There is no implicit regeneration when a model configuration changes, a profile opens, a cue is viewed or a clue is answered.
Inputs are bounded to 32,000 serialized bytes per job; oversized note collections fail visibly without truncating saved notes. Responses are stream-bounded to 100,000 bytes, validated against strict allowed fields/vocabulary and source IDs, and at most three 500-character cues are accepted. Notes and image text are untrusted data in an instruction-separated request; there are no model tools or actions. Syntax/source validation cannot prove semantic faithfulness, uncertainty preservation or visual accuracy; those remain part of the authorized live evaluation. All generated summaries stay labeled until reviewed.
The folder preview uses http://127.0.0.1:3002 and .next-folders against the preserved local database. Older previews on ports 3000/3001 were not restarted. If this preview stops, run:
APP_ORIGIN=http://127.0.0.1:3002 CONTACT_RECALL_DIST_DIR=.next-folders npm run build
APP_ORIGIN=http://127.0.0.1:3002 CONTACT_RECALL_DIST_DIR=.next-folders npm run start -- --port 3002
Do not launch a second process on an occupied port. To run browser regressions against this preview:
APP_ORIGIN=http://127.0.0.1:3002 CONTACT_RECALL_DIST_DIR=.next-folders PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 npm run test:e2e
PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 npm run test:pagination
Normal fresh setup still uses port 3000 and .next. Provider enablement is unnecessary for either preview. Existing import limits and unverified environment/browser/performance items remain below and in BUILD_STATUS.
npm run benchmark # Pure deterministic 8/2,000-contact and near-limit CSV timings
PLAYWRIGHT_BASE_URL=http://127.0.0.1:3001 npm run test:scale
# Opt-in 2,000-contact API/browser test; creates and cleans up its own fictional account.
npx playwright install firefox webkit
# Prepend these to the existing preview test command to select an engine:
PLAYWRIGHT_BROWSER=firefox APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone4 PLAYWRIGHT_BASE_URL=http://127.0.0.1:3001 npm run test:e2e
PLAYWRIGHT_BROWSER=webkit APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone4 PLAYWRIGHT_BASE_URL=http://127.0.0.1:3001 npm run test:e2e
Playwright warns that WebKit is frozen on macOS 14.4. The installed engine failed page creation with Unknown setting: PushAPIEnabled; WebKit and current Safari remain unverified. No Playwright/browser internals were patched to bypass this incompatibility. The clean-setup check used a new temporary directory, npm ci --offline, a distinct Supabase project and ports 55320–55329, all migrations, generated local configuration, fictional seeding, production build, real backend regressions and a Chromium sign-in. Its temporary app/containers were stopped; no existing database was reset. Exact commands/results and remaining installation limitations are in BUILD_STATUS.
Panel tabbing no longer creates an unsaved-change prompt for unchanged aliases. The desktop palette now uses darker muted text and the existing accent for visible keyboard focus. A temporary initial-load failure offers Retry opening library. These bounded keyboard, name and contrast checks are not a complete accessibility audit.
All imports are UTF-8 (optional BOM), at most 2 MiB, 500 records, and 60,000 characters per raw record. The multipart stream is bounded before parsing, including requests without Content-Length. NUL/UTF-16 and invalid UTF-8 are rejected. Field validation also applies: names/methods/organization/role up to 300 characters; notes up to 20,000; meeting context up to 3,000; at most 30 methods/affiliations. A name or user-supplied temporary label is required; missing names are not invented. Invalid records remain unselected with per-record errors; correct the source file and upload again.
| Format | Supported | Explicit limitations |
|---|---|---|
| CSV | Comma delimiters; header required; up to 50 columns with headers up to 100 characters; CRLF/LF records; quoted commas/newlines; doubled quotes; preview and field mapping. | No delimiter/encoding guessing or XLSX. Malformed quotes/column counts are invalid. Formula-looking text is inert text. |
| CSV fields | Name, first/last name, repeated email/phone/link columns, organization, role, status, kind, original note and original meeting. | Status is current, former or unknown; kind is employer, school, role or organization. Missing status/kind becomes unknown/organization. One affiliation per CSV row. Repeated scalar mappings use the first value with a warning; repeated notes are joined, contact methods retained. Unmapped columns remain in raw source. Dates, groups, photos and appearance fields are not imported as facts. |
| vCard | Complete BEGIN:VCARD/END:VCARD records, VERSION 3.0 or 4.0; FN (preferred) or N fallback; EMAIL, TEL, URL, ORG, TITLE, NOTE; CRLF/LF folding; escaped newlines, commas, semicolons and backslashes. |
One parsed ORG/TITLE per record; additional organization components stay in source. Repeated scalar properties use the first with a warning. Contact methods/notes may repeat. No v2.1, quoted-printable, legacy CHARSET/ENCODING, grouped property names, provider extensions, relationship conversion, or date/group/appearance inference. Unsupported properties are reported and retained in source. |
| Photos | Add photos separately to saved contacts through the existing validated private upload. | Imported PHOTO values, embedded/base64 images and remote image URLs are never decoded, uploaded or fetched. They remain raw source text with a warning, subject to the same size limits. Oversized records are invalid. This is deliberate subset support, not automatic photo importing. |
Each valid selected row saves in its own database transaction; one bad row does not roll back other contacts. Its original record text, filename, format, SHA-256 file hash, mapping/header information, warnings, source ID and capture timestamp persist. Invalid/unselected rows are not stored as contacts; their source file remains with the user. Retry within the same open import dialog reuses the exact accepted batch/item; changed input cannot reuse that receipt. Uploading the same file again explicitly creates separate contacts and duplicate suggestions, never automatic merging. Closing/reopening the importer starts a new batch; there is no durable resumable-upload dashboard or external address-book sync.
Sample fixtures: tests/fixtures/import.csv and tests/fixtures/import.vcf. Ordinary imports, search, group evaluation, duplicate review, priorities and quiz questions make zero paid API calls.
Search recognizes saved names, nicknames, organization phrases and group names before ignoring simple filler words. It also searches contact methods, original notes, original meeting context, explicitly recorded encounters, manual custom details, affiliation roles, raw manual quick-entry text and confirmed traits. Smart/manual group names use the same membership evaluator as explicit scopes. It does not turn note text into verified quiz facts.
| Input | Interpretation |
|---|---|
Lex, May Chen, bookshops |
Saved phrase or keyword |
Morgam |
At most one edit for a single token of five or more characters |
works at Cedar Studio |
Current affiliation evidence |
used to work at Goldman, formerly at Goldman |
Former affiliation evidence, labeled historical |
met at NYU |
Original meeting context or recorded encounter |
not finance |
Soft negative text evidence; negative-only library filtering keeps unknowns rather than requiring a positive score |
no glasses, without glasses, not wearing glasses |
Explicit recorded No; unknown and pending observations remain neutral |
brown hair, grey hair, short hair, bald, clean-shaven |
Confirmed appearance vocabulary; grey/gray and blonde/blond are explicit spelling variants |
not brown hair, does not work at Goldman |
Soft negative evidence in the indicated field |
no longer works at Goldman |
Former affiliation evidence |
the person I met at NYU who used to work at Goldman |
Two explicit clues in the same session |
The small explicit organization alias vocabulary is Goldman ↔ Goldman Sachs and NYU ↔ New York University. No inference equates an employer with an industry or attendance. Unsupported language is ordinary keyword text; this is not general natural-language understanding. Interpreted chips are removable and the exact original query remains editable.
Ranking boosts positive matches and demotes contradictions without excluding sparse people. Only explicit group scope and rejected visible batches filter candidates. Ties use display name then stable ID. Every owned contact is loaded in paginated batches; questions use the entire scoped pool, not only six visible cards. This intentionally favors a simple auditable local slice over a speculative indexing service. Milestone-4 measurements cover 2,000 fictional contacts: ordinary query processing is fast on the tested Apple M2, while full library loading took about 2.4 seconds. Larger libraries and heavier records remain unverified; no speculative index service was introduced.
Quiz fields are glasses, hair color, hair length, facial hair, current organization and original meeting context. Questions require at least two meaningful known partitions and adequate coverage. Utility combines weighted known coverage, partition entropy, fixed answerability and an initial appearance preference. Confirmed manual observations are equally eligible; no calibrated confidence or optimality is claimed. Scores are soft weights, not probabilities. “I’m not sure,” “Skip this question” and “No detail saved” add no identity evidence or profile edits. Unsure/skipped/suppressed chips offer Use [field] again without clearing other clues. Explicit typed appearance/current-organization/meeting clues suppress redundant questions. Scope widening, candidate cards and full-profile visits preserve the session; a full page reload intentionally starts a fresh ephemeral session.
Live-provider validation, deployment and external invitations await separate authorization and the prerequisites in BETA_READINESS. Larger-scale tuning, full assistive-technology validation, current Safari on a newer OS, long-idle expiry and exhaustive fault/stress testing remain unverified. Events, practice, follow-ups and external integrations remain later. No unfinished navigation tabs are shown.
Apply additive migration 202610220012_settings.sql with npx supabase migration up --local; do not reset existing data. Then rebuild/restart the app. Settings is the last primary navigation tab.
Preferences are saved per authenticated beta account. Existing enrichment_policies remain authoritative for automatic notes, automatic photos and paid processing; user_preferences stores appearance and deterministic-suggestion preferences under RLS. New defaults preserve Light, comfortable spacing, tips and deterministic suggestions. Paid processing defaults off. Auto notes/photos default on, subject to contact assistance mode, budgets and operator provider configuration. No provider configuration or credentials are changed by Settings.
Review details retains selective bulk approval, jobs, pending suggestions and manual duplicate comparison. Global policy switches and usage/budgets moved to Settings. Turning paid processing off cancels queued work and closes approved budgets; reenabling requires new explicit budget approval. Already-dispatched external requests cannot be recalled. Existing notes, photos, cues, confirmed attributes, groups and review decisions are preserved.
Changes are shown after server confirmation; failures retain the last confirmed values and display an error. Other devices/tabs read updated preferences on load or when the window regains focus (no realtime subscription). Optional tips currently control Review details’s explainer; essential review, uncertainty and security information remains visible. Account theme is loaded with the private library; the initial loading/sign-in screen remains Light.
Settings coverage: npm test, npm run test:enrichment, npm run test:integration, and npm run test:e2e. No paid provider calls are made by these tests. Notifications, event prompts, external connections/sync and data export remain deferred, with no placeholder switches.
The homepage is now Find someone, and Review details is where you check photo suggestions, compare contacts and add useful details. See the writing policy for the approved vocabulary. These are display changes; internal API routes, stored states and existing contact content are unchanged. No new migration, environment setting or credentials are needed. Rebuild and restart the app to load the wording update.
Apply migrations through 015 using npx supabase migration up --local; do not reset existing data. Rebuild with APP_ORIGIN=http://127.0.0.1:3002 CONTACT_RECALL_DIST_DIR=.next-profile npm run build, then serve with the same variables and npm run start -- --port 3002. Credentials and paid-provider configuration stay unchanged. No extra package, OAuth setup or external service is required. New fields default to empty/unknown, never inferred values.