feat!: run Rumi without a Meta account, and set it up in two commands (v2.0.0) - #82
Open
Jazy1 wants to merge 1 commit into
Open
feat!: run Rumi without a Meta account, and set it up in two commands (v2.0.0)#82Jazy1 wants to merge 1 commit into
Jazy1 wants to merge 1 commit into
Conversation
Rumi's messaging channel is now pluggable. The default links your own WhatsApp by QR the way WhatsApp Web does, so a clone goes from `git clone` to a working conversation in about fifteen minutes with no Business account, no app review and no waiting. `rumi graduate` moves you to an official number when you're ready, and every teacher, conversation and past assessment carries over — Rumi identifies people by phone number, not by channel. The key insight for Meta-only features: a WhatsApp Flow is only a *renderer*. The endpoint holds all the logic in a uniform shape, so the sandbox needed a second renderer, not a second implementation. The new text-flow engine drives those same endpoints over chat, which is why /settings, /video, reading assessment and class setup work on a channel that has no Flows. Setup stopped being an eleven-step document and became `./install.sh` then `rumi setup` — a five-step wizard that asks in plain language rather than by variable name, checks every value against the real service as you type it, writes each answer to .env immediately, and skips whatever already works on a re-run. Plus `rumi start|status|doctor|pair|graduate`. Most of the fixes here were pre-existing and affected Meta deployments too; each failed inside a try/catch that made it look transient. `redisService.setNX`/`setexWithCeiling` never existed, so no quiz could ever be delivered and every image failed. `quiz_class_*` replies had no handler. Five services bypassed llm-client. `quiz_sessions` was missing six columns on any pre-existing database. `doctor` showed a green tick for an OpenRouter key with no credit. Four paths resolved against the working directory rather than the repo, which is how `cd bot && npm start` loaded zero env vars and how a bot started from bot/ registered a second WhatsApp device and re-synced until WhatsApp invalidated the first. 170 suites / 1997 tests, verified both locally and under CI's own condition (root suite before `cd bot && npm ci`). BREAKING CHANGE: `npm run setup` now launches the interactive wizard; use `npm run doctor` for the preflight it used to run. `.env` is read from the repo root rather than the process working directory — move a `bot/.env` up one level (Railway is unaffected). `REQUIRED_VARS` is core-only, with the channel's own variables in `CHANNEL_REQUIRED_VARS[CHANNEL_DRIVER]`; existing Meta deployments need no change, since the driver is inferred as `meta` when the four Meta variables are present. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rumi no longer needs a Meta account to run
The messaging channel is now pluggable. The default links your own WhatsApp by QR the way WhatsApp Web does, so a clone goes from
git cloneto a working conversation in about fifteen minutes — no Business account, no app review, no waiting.rumi graduatemoves you to an official number when you're ready, and every teacher, conversation and past assessment carries over, because Rumi identifies people by phone number rather than by channel.Setup stopped being an eleven-step document and became two commands.
Release:
2.0.0. Three breaking changes, all small, all listed below with the one-line migration.The idea that made the Meta-only features work
A WhatsApp Flow is only a renderer. The logic lives in the endpoint (
bot/shared/routes/*-endpoint.js) in a uniform shape:So the sandbox needed a second renderer, not a second implementation. The new text-flow engine drives those same endpoint functions over an ordinary chat conversation — which is why
/settings,/video, reading assessment and class setup all work on a channel that has no Flows at all. Navigate-style Flows (no endpoint) synthesize thenfm_replywebhook, sowhatsapp-bot.js's dispatch andflow-response.handler.jsrun untouched.The field names are a contract, so they're pinned by tests against their real consumers rather than assumed.
npm run setuplaunches the wizard (wasdoctor.js)npm run doctorfor the preflight — identical output.envis read from the repo root, not the working directorycd bot && npm startloaded zero variables and aborted with "Missing REQUIRED env var(s)" on a fully configured deploymentbot/.envup one level. Railway is unaffected — its Procfile already runs from rootREQUIRED_VARSis core-only; the channel's vars come fromCHANNEL_REQUIRED_VARS[CHANNEL_DRIVER]metawhen the four Meta vars are presentCHANNEL_STATE_DIRalso resolves against the repo now. That only affects the new sandbox driver, but it's the reason a bot started frombot/registered a second WhatsApp device and re-synced endlessly until WhatsApp invalidated the first.What's new
A two-layer CLI.
install.shdoes the mechanical bootstrap and offers to run the wizard;rumidoes the rest.rumi setup--reconfigurere-asks everythingrumi startrumi statusrumi doctorrumi pairrumi graduateThe wizard is built around four commitments, and they explain most of its code:
SUPABASE_URL.rumi doctorruns, so "configured" and "working" can't drift apart..envbyte-identical.Field-shape validation with the specific correction. The expensive setup failures aren't typos — they're pasting a value that's perfectly well-formed for something else:
service_role— both areeyJ…JWTs on the same page, and the anon key can't see past RLS, so the bot starts cleanly and behaves as though the database were empty. The validator decodes the token'sroleclaim and tells you to click Reveal.PHONE_NUMBER_ID. Graph answers "Object with ID does not exist", naming neither the field nor the mistake.sk-…inOPENROUTER_API_KEY— it names which vendor's key it recognised.https://endpoint asREDIS_URL.The one step that can't be automated is named rather than glossed over. Supabase exposes no API for arbitrary SQL, so the
exec_sqlhelper the schema applies through must be pasted in once. The wizard distinguishes the three states a project can be in — already set up / helper missing / ready for schema — because "no tables yet" and "no way to create them" look identical from outside and need opposite instructions. When the helper is missing it prints the two lines and links straight to that project's SQL editor.Also: the Baileys sandbox driver (QR pairing; text, reactions, typing, images, audio, documents, video, stickers; an inbound adapter that normalizes a socket event into the shape Meta's webhook produces);
rumi graduatevalidating credentials before touching.envand retiring rather than deleting the old session;rumi status.Fixes
Most of these were pre-existing and affected Meta deployments too. Each failed inside a
try/catchthat made it look transient.redisService.setNX/setexWithCeilingnever existedquiz_class_*replies had no handler/quizdid nothingllm-client.jsforOPENAI_API_KEYquiz_sessionsmissing six columnsCREATE TABLE IF NOT EXISTSis a no-op on an existing table, so the columns only ever reached fresh installsdoctorgreen-ticked an OpenRouter key with no credit.oggof a child's voice and a report PDF on disk, foreverFour of these now have conformance guards so they can't return silently.
Test plan
cd bot && npm ci. Three suites would have failed on first push (fluent-ffmpegreached transitively; two tests readbot/node_modules); fixed with mapped mocks and install-independent assertions.envdeleted, session retired,./install.sh→rumi setup→ QR → conversation. 6 min 13 s, against a 30-minute target.envbyte-identical by checksum--version,--help, unknown command,status,doctor,pair(correctly refuses while the bot holds the session),setup,graduate(rejects bad credentials and changes nothing), and all of them from insidebot/to prove the cwd fixHi,/menu,/status,/settings→1(drives the real Flow endpoint through two screens as chat),/video,cancelNot verified: the 12-hour quiz report (a timer), pronunciation scoring (
AZURE_SPEECH_KEY), video generation (KIE_API_KEY), lesson plans (GAMMA_API_KEY).Docs
README.mdandSETUP.mdlead with the two-command path; the manual walkthrough stays as the production reference. Both now say plainly that you need a second phone number to test from — Rumi answers as your number, so messaging it from the same account looks exactly like a broken bot.The
/setupskill documents both front doors: the human wizard, and the agent-driven "set me up" flow. The agent path calls the wizard's own modules (validators, the.envpatcher, doctor's probes, the schema bootstrap) so the two can't drift, and the skill is explicit thatrumi setup,rumi pairandrumi graduateare interactive TTY programs an agent must not launch — it would hang at the first prompt.CLAUDE.mdgains the architecture fact an agent was missing: the channel is pluggable, and you require the index, never a driver.🤖 Generated with Claude Code