Skip to content
bagideaPublic

About

πŸ•ŠοΈ Emmaus β€” Bible-counsel companion plugin for BagIdea Office: 3D Selah, voice, Scripture-grounded counsel

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

Β 

History

84 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ•ŠοΈ Emmaus

Version 0.2.0.

Bible-grounded counseling, right in the office. Tell Emmaus what you're going through β€” typed or spoken, Thai or English β€” and it listens, opens relevant Scripture with you, and walks you to a concrete next step. Every quoted verse is pulled from a local Bible corpus and checked against it before it's shown, so nothing is ever a hallucinated reference.

Named for Luke 24:13-35: two disciples walk a road, crushed and confused; a stranger joins them, listens to their story first, then opens the Scriptures β€” and their hearts burn within them. That's the shape of every answer here: listen β†’ open the Scriptures β†’ the heart warms β†’ a next step.

Built as a plugin for the BagIdea office β€” a 3D-scened panel with voice in and voice out, running entirely on your own API keys.

This plugin is free and will never be sold. No account, no subscription, no ads.


Screenshots

The companion answering Settings drawer FX layer
Selah the companion answering with a Scripture reference on screen The settings drawer open, showing Sound, Motion, Character, and Voice controls The FX layer's scripture-burst effect over the scene

Install

From the Plugins Hub (inside the office): β‹― β†’ 🧩 Plugins Hub β†’ Emmaus β†’ Install.

From a GitHub URL (before it's listed on the Hub, or to track a fork): 🧩 Plugins β†’ paste the GitHub URL β€” the office git clones the repo into plugins/emmaus/ and loads it. Reinstalling picks up whatever the author has pushed since.

Either way, Emmaus needs at least one API key set in the office's own key vault before it can answer anything β€” see below.


Required keys

Set these in the office's key vault (never in the plugin itself β€” a plugin reads keys from the office registry at runtime, it doesn't ship or store its own).

Key Required? Used for
OPENAI_API_KEY Required. The default first brain (counsel), the default voice engine (synthesize, tts.engine: "openai"), and speech-to-text (transcribe β€” gpt-4o-transcribe β†’ whisper-1 fallback, no Gemini path). Without this key, counsel can still work if you reconfigure brains to Gemini-only, but transcribe and the default voice will not.
GEMINI_API_KEY Optional. The second/fallback brain (gemini-3.1-pro-preview), and Google voice mode gemini-tts (config.tts.engine:"google", mode:"gemini-tts"). Also the fallback key for cloud-chirp3 if GOOGLE_TTS_API_KEY isn't set.
GOOGLE_TTS_API_KEY Optional. Google Cloud Chirp 3 HD voices (config.tts.mode:"cloud-chirp3") β€” a synchronous, non-LLM text-to-speech API, noticeably faster than gemini-tts. Preferred over GEMINI_API_KEY for this one mode; needs texttospeech.googleapis.com enabled and unblocked on the key's Google Cloud project (see Troubleshooting).

Nothing works with zero keys set. With just OPENAI_API_KEY, every command works using the defaults (openai brain and voice, OpenAI transcription).


The config command β€” brain order and voice engine

config with no args returns the current settings; a patch merges into what's saved (plugins/emmaus/data/config.json) and persists across restarts.

Read the current config:

POST /plugin/emmaus/cmd  { "cmd": "config", "args": {} }
β†’ { "ok": true, "config": { "brains": [...], "tts": {...} } }

Set a custom brain order (tried in order; the next one is used only if the previous one errors or still returns unusable JSON after one repair round):

POST /plugin/emmaus/cmd  { "cmd": "config", "args": { "brains": [
  { "provider": "openai", "model": "gpt-5.5", "effort": "none", "verbosity": "low" },
  { "provider": "gemini", "model": "gemini-3.1-pro-preview", "effort": "low" },
  { "provider": "openai", "model": "gpt-5.4-mini", "effort": "low" }
] } }

Reset the brain order to the shipped default:

POST /plugin/emmaus/cmd  { "cmd": "config", "args": { "brains": "default" } }

Switch the voice engine (tts.engine: openai default, or google; tts.mode: gemini-tts or cloud-chirp3, only used when engine is google):

POST /plugin/emmaus/cmd  { "cmd": "config", "args": { "tts": { "engine": "google", "mode": "cloud-chirp3", "voice": "Kore" } } }
POST /plugin/emmaus/cmd  { "cmd": "config", "args": { "tts": { "engine": "openai" } } }   # back to the default

A partial tts object merges into the saved one, so {"tts":{"engine":"google"}} alone is enough to switch engines and keep the rest. Bad values (an engine that isn't openai/google, a mode that isn't gemini-tts/cloud-chirp3, an empty model/voice) are rejected and nothing is written.


Every command

All commands go through POST /plugin/emmaus/cmd with {"cmd": "<name>", "args": {...}}. Args also accept a bare string for the primary field (e.g. "args": "PHP 4:6-7" for verse).

counsel

The core command. Send a situation, get a full pastoral reply.

POST /plugin/emmaus/cmd  { "cmd": "counsel", "args": { "situation": "I've been really anxious about work lately, my boss pressures me every day, I'm scared of getting laid off, and I can't sleep at night.", "lang": "en" } }
{
  "ok": true,
  "summary": "It sounds like you're carrying a heavy burden of anxiety about work...",
  "scriptures": [
    { "ref": "Philippians 4:6-7", "ref_id": "PHP 4:6-7", "text": "In nothing be anxious...", "why": "This passage speaks directly to anxiety...", "verified": true }
  ],
  "guidance": ["..."],
  "practical_steps": ["Before the presentation, set aside a few moments to quietly pray...", "..."],
  "prayer": "Dear God, I come to You feeling so anxious...",
  "follow_up": "What is one small thing you can do today to help prepare your heart and mind?",
  "safety": { "crisis": false, "abuse": false, "message": "" },
  "topics": ["anxiety"]
}

A QUESTION (a direct doctrinal/factual question, not a life situation) returns a short answer instead, with summary: null. Every scriptures[] entry is checked against the local Bible corpus before being returned (verified: true) β€” nothing is quoted without being found in the text.

verse

Look up the text of a reference from the local corpus.

POST /plugin/emmaus/cmd  { "cmd": "verse", "args": { "ref": "PHP 4:6-7", "lang": "en" } }
β†’ { "ok": true, "ref": "Philippians 4:6-7", "ref_id": "PHP 4:6-7", "text": "...", "translation": "en-web", "found": true }

topics

List counseling topics (with their key verses) and the loaded Bible translations.

POST /plugin/emmaus/cmd  { "cmd": "topics", "args": { "lang": "en" } }
β†’ { "ok": true, "topics": [{ "id": "anxiety", "label": "Anxiety", "refs": ["PHP 4:6-7", "1PE 5:7", "ISA 41:10"] }, ...], "translations": [...] }

speak

Broadcast a line of text over the panel's WebSocket β€” any already-open Emmaus panel says it through its registered speaker. Text only; no audio is generated by this command (see synthesize for that).

POST /plugin/emmaus/cmd  { "cmd": "speak", "args": { "text": "Thank you so much for sharing that with me.", "lang": "en" } }
β†’ { "ok": true }

synthesize

Turn text into real audio: one mp3 per chunk (a short first chunk so playback starts fast, then whole sentences), plus a manifest β€” cached by content hash, so replaying the same text costs nothing extra. Engine is whatever config.tts currently points at.

POST /plugin/emmaus/cmd  { "cmd": "synthesize", "args": { "text": "The LORD is my shepherd; I shall not want.", "lang": "en", "voice": "warm", "chunk": 0 } }
β†’ { "ok": true, "count": 4, "chunks": [{ "index": 0, "text": "...", "url": "/plugin/emmaus/static/audio/....mp3", "cached": false, "ms": 884 }], "manifestUrl": "..." }

transcribe

Speech-to-text: OpenAI gpt-4o-transcribe, falling back to whisper-1 if that call fails. Thai and English both work; pin the language with lang or let it auto-detect.

POST /plugin/emmaus/cmd  { "cmd": "transcribe", "args": { "audio": "data:audio/webm;base64,GkXfo...", "mime": "audio/webm", "lang": "th" } }
β†’ { "ok": true, "text": "I've been feeling so tired and anxious about work lately.", "lang": "en", "model": "gpt-4o-transcribe", "ms": 1617 }

For a real recorded file, skip the base64 and POST the raw audio (or multipart) straight to /plugin/emmaus/transcribe?lang=th:

curl -X POST http://127.0.0.1:8787/plugin/emmaus/transcribe -F "file=@clip.wav;type=audio/wav" -F lang=th

scene

Read or set the counselor's 3D scene state β€” the panel drives this itself as you talk, but it can also be read or forced from outside.

POST /plugin/emmaus/cmd  { "cmd": "scene" }
β†’ { "ok": true, "state": "idle" }

POST /plugin/emmaus/cmd  { "cmd": "scene", "args": { "state": "answering" } }
β†’ { "ok": true, "state": "answering" }

States: idle | listening | thinking | answering.

config

See The config command above.


Panel walkthrough

  1. Type or speak β€” write a situation in the text box, or hold the mic (πŸŽ™) and talk; the mic records, sends the clip for transcription, and fills the box for you before asking.
  2. Emmaus answers in beats, in order, every time: acknowledge how you're feeling β†’ relevant Scripture with context β†’ what it means for your situation β†’ concrete practical steps β†’ a short prayer written for you β†’ one gentle follow-up question that keeps the conversation going.
  3. Every verse shown is a real citation checked against the local Bible corpus β€” book, chapter, and verse, never a paraphrase presented as a quote.
  4. The answer is read aloud automatically through whichever voice engine config.tts points at, chunked so the first words start playing in a couple of seconds rather than waiting for the whole reply.
  5. The scene behind the panel moves with the conversation: idle β†’ listening β†’ thinking β†’ answering β†’ idle.
  6. Language: leave the selector on AUTO to answer in whatever language you wrote/spoke in, or pin Thai / English.

Optional modules

panel.html loads a core scene (scene.js + world.js) plus four optional lanes β€” app.js mounts whichever of these have registered, so a fork can drop any of them without breaking the core panel:

  • character.js β€” the counselor companion (Selah the pilgrim tortoise) standing beside the road, with idle/listen/speak states instead of the scene speaking with no visible speaker.
  • fx.js β€” sprite-based visual effects (the scripture-burst shown above), manifest-driven and prefers-reduced-motion safe.
  • sfx.js β€” ambient and interaction sound cues (footstep, page-turn, chime) that accompany scene transitions.
  • settings.js β€” the settings drawer (βš™ in the top-right) to control Sound, Motion, Character, and Voice, without going through the config command by hand. Settings persist to localStorage and broadcast an emmaus:settings event other modules listen for.

Troubleshooting

"no key" / a brain or voice call fails immediately. Emmaus reads keys from the office's own key vault (ctx.reg.apiKeys), not from your shell's environment variables β€” setting OPENAI_API_KEY in a terminal has no effect on the running office. Set it in the office's key manager instead. At minimum OPENAI_API_KEY must be set for the default brain order, the default voice, and transcription to work at all.

403 on Google Cloud Chirp 3 HD (config.tts.mode: "cloud-chirp3"). Two separate blockers can each produce a 403, and Google's error alternates which one it reports:

  • SERVICE_DISABLED β€” the Cloud Text-to-Speech API isn't enabled on the key's Google Cloud project yet. Enable texttospeech.googleapis.com for that project in the Google Cloud console.
  • API_KEY_SERVICE_BLOCKED β€” the key itself is restricted to other APIs (e.g. a Gemini-only key). Either lift the restriction, or use a separate key scoped to Cloud Text-to-Speech via GOOGLE_TTS_API_KEY (recommended β€” keeps your Gemini key untouched).

gemini-tts mode (config.tts.mode: "gemini-tts") doesn't need either of the above β€” it only needs GEMINI_API_KEY β€” but it is noticeably slower to first sound than OpenAI or Chirp 3 HD, so expect a longer pause before the answer starts speaking.

Mic permission. The first time you use the mic, your browser/webview will prompt for microphone access; the choice is remembered per origin after that. If you denied it earlier, the mic button reports a denied state β€” re-enable microphone access for the office in your OS/browser privacy settings and reload the panel. If your device has no working microphone, typing still works exactly the same β€” the mic is optional, not required.


Privacy

Emmaus keeps no log of what you ask it. Your situation text is sent, per request, to the brain provider you've configured (OpenAI and/or Gemini) to generate the answer, and β€” only if you use voice β€” to the transcription and text-to-speech providers, the same as any API call the office makes on your behalf; nothing is separately written to a question log or history file by this plugin. The only files Emmaus writes to disk are generated answer audio clips, cached by a hash of the text/voice/engine so the same line is never re-synthesized (and never re-billed) β€” these are audio of the answer, not a record of your question.


Bible text licenses

Emmaus ships two Bible translations locally (data/bible/) so every verse can be verified against real text before it's shown:

  • en-web β€” the World English Bible, public domain. No attribution required, no restrictions.
  • th-kjv β€” a Thai translation licensed CC BY-NC-ND 4.0 (Attribution, NonCommercial, NoDerivatives). Verbatim verse excerpts, cited, are explicitly permitted by the source's own terms ("You may share and redistribute this Bible translation or extracts from it..."); the license forbids changing the wording and forbids selling the work. Since Emmaus is free and is never sold, this sits well inside the license's non-commercial terms. Attribution: Thai KJV Bible, Β© the copyright holder, used under CC BY-NC-ND 4.0 β€” see docs/research/2026-09-25-thai-bible-license.md for the full license research, including the path being pursued for a direct license to the Thai Standard Version (THSV11).

If you fork Emmaus and swap in a different translation, check that translation's own license before shipping it β€” the rules above apply to the corpus bundled with this repo, not to substitutes.


Safety note

Emmaus is a companion that surfaces Scripture and walks alongside you β€” it is not a pastor, a licensed counselor, a doctor, or a lawyer, and it never claims to be. For anything medical, legal, or involving immediate danger to yourself or someone else, please talk to a real professional or call for help. In Thailand:

  • Mental Health Hotline 1323 β€” mental health / crisis hotline, 24 hours.
  • Social Assistance Center 1300 β€” abuse/domestic violence assistance, Ministry of Social Development and Human Security, 24 hours.
  • 1669 β€” emergency medical services.

If you're outside Thailand, please reach your local emergency number or crisis line β€” don't wait. Emmaus will always still offer Scripture and prayer alongside pointing you to real help; it is never meant to be the only place you turn.


Credits

Emmaus is built by the BagIdea office team:

  • Monanisa β€” counselor character design (Selah, Lumi, Tobi candidates)
  • Pixel β€” UI/UX direction
  • Poppy β€” voice engineering (TTS engines, listening matrix, chunked playback)
  • Kevin β€” release engineering and deploys
  • Yamamoto β€” sound design (SFX set, ambient loop)
  • Shiba β€” settings drawer (sound, motion, character, voice display)
  • Sun β€” counsel-quality evaluation
  • Sahara β€” Bible-translation license research

About

πŸ•ŠοΈ Emmaus β€” Bible-counsel companion plugin for BagIdea Office: 3D Selah, voice, Scripture-grounded counsel

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages