Session log — Zoom Companion, Medilearn fork built and verified live

← Overview

Session log — Zoom Companion · Session, 18 May 2026, Medilearn fork built and verified live

18 May 2026 · Hasmukh with Claude · auto-published from the local journal entry.

Summary

Picked up cleanly from the previous session's plan: build a parallel "Camera Monitor (Medilearn)" packaged app for the medilearn.africa Zoom tenant, distinct from the Mobilearn build that was shipped yesterday. Did the Marketplace provisioning, hit two real blockers (one iCloud-rsync-related, one Marketplace-toggle-related), worked through them, and verified a live join end-to-end. Both apps are now distribution-ready and can coexist on the same Mac.

Also published the two queued session logs from the prior two sessions to documentation.mobilearn.africa under a new "Zoom Companion session log" section on /overview/, satisfying the SessionStart publish queue hook.

Decisions

  • Separate packaged app per Zoom tenant. Hasmukh's preference, architecturally correct given the SDK key is account-bound. Two distributables (Mobilearn and Medilearn), no shared multi-tenant runtime code, identical feature set at v0.11.0.
  • Project folder named Zoom Companion Medilearn (no parens, sibling to Zoom Companion). Clean for shell, easy to discover in Finder, mirrors the Mobilearn project's folder shape.
  • appId africa.medilearn.cameramonitor and productName Camera Monitor (Medilearn) for the new build, so userData directories are separate from the Mobilearn build and OAuth tokens don't clash if both apps installed on the same Mac.
  • Version stays at 0.11.0 for the Medilearn fork. Feature parity with Mobilearn at fork point; version reflects feature set, not project age. When they later diverge, the version numbers will too.
  • Kept the full DEVLOG history from the Mobilearn fork in the Medilearn project, with a fresh fork-point entry at the top noting the lineage. Provides traceability for the shared code.
  • Did NOT include session logs in the fork. Those belong to the Mobilearn project's history. The Medilearn project starts with an empty sessions-log/.

Changes made

Documentation publishing

  • Wrote a one-off Python script at /tmp/publish-zoom-companion.py that imports the rendering helpers from s2l-assistant/.claude/scripts/nightly-publish.py and publishes Zoom-Companion-specific session logs with the right slug prefix and a dedicated <h2>Zoom Companion session log</h2> section on /overview/.
  • Published 2026-05-16-session-devlog-catchup.md as /session-log-2026-05-16-zoom-companion-devlog-catchup/.
  • Published 2026-05-17-session-v0.10.0-dual-tenant.md as /session-log-2026-05-17-zoom-companion-v0.10.0-and-v0.11.0/.
  • Updated /overview/ to insert the new "Zoom Companion session log" section between the existing "Zoom Apps session log" and "Related plans" sections, with both new entries as bullets.
  • Touched .published markers locally for both files.

Medilearn fork build

  • rsync -aE from Zoom Companion/ to Zoom Companion Medilearn/, excluding dist/, the already-published session log markdowns and markers, and Mobilearn-specific transient files. Source code identical to Mobilearn v0.11.0 at fork point.
  • [package.json](../Zoom Companion Medilearn/package.json): rewritten with new name, author, appId, productName, retained version 0.11.0.
  • [.env](../Zoom Companion Medilearn/.env): fresh file with the Medilearn S2S credentials (copied from the *_MEDILEARN-suffixed vars in the Mobilearn project's .env, the suffix dropped since this app is single-tenant). BOT_EMAIL=cameramonitor@medilearn.africa, BOT_DISPLAY_NAME=Camera Monitor (Medilearn). SDK_KEY/SDK_SECRET filled with the credentials from the new General App that Hasmukh provisioned during this session.
  • [CLAUDE.md](../Zoom Companion Medilearn/CLAUDE.md): front matter retargeted to describe the Medilearn fork, Marketplace apps section listed for medilearn.africa.
  • [DEVLOG.md](../Zoom Companion Medilearn/DEVLOG.md): new top entry documenting the fork point and the build journey including blockers and resolutions. Mobilearn historical entries kept below.
  • [OPERATOR-GUIDE.md](../Zoom Companion Medilearn/OPERATOR-GUIDE.md) and .html: bulk Mobilearn → Medilearn swap via sed.
  • .claude/settings.json: hook paths re-pointed at the Medilearn project's own .claude/scripts/ (rsync had carried over Mobilearn project paths).
  • Cosmetic fixes after first build (three values that I missed in the initial fork): main.js BrowserWindow.title, renderer/index.html <title> and <h1>, renderer/renderer.js OAuth banner text. Required two extra rebuilds (first one missed the HTML <title>, which overrides BrowserWindow's title once the renderer loads — lesson 22).

Marketplace provisioning (Hasmukh)

  • Created the Camera Status Companion Medilearn General App on the medilearn.africa Marketplace.
  • Hit "Include invalid characters" on the original Camera Status Companion (Medilearn) name because Zoom rejects parens; renamed to no-parens.
  • Configured OAuth Redirect URL, Allow List, both Strict Mode and Subdomain Check unchecked. Added user:read:token scope. Activated.
  • On the Embed tab, toggled Meeting SDK ON and "Are you developing a programmatic join use case?" ON. This was the missing step that produced the "Signature is invalid" error on the first join attempt; once both toggles were enabled and saved, the Client ID/Secret signed valid JWTs (lesson 21).

Verification (live)

  • First join attempt: blocked by node_modules corruption from the rsync (one file missing in http-proxy-agent). Fixed by rm -rf node_modules && npm install (447 packages, ~3 seconds with npm 11 / node 24).
  • Second join attempt: "Signature is invalid". Fixed by enabling Meeting SDK + programmatic join sub-toggle on the Marketplace.
  • Third join attempt: succeeded. Bot joined the medilearn.africa-hosted meeting (host: admin@medilearn.africa) cleanly via the Medilearn ZAK path. Roster populated correctly. Participant-stats line rendered. Version footer showed v0.11.0.

Memory + lessons

  • Updated project memory at ~/.claude/projects/-Users-...-Zoom-Apps/memory/project_camera_status_app.md:
  • Frontmatter rewritten for the dual-app state.
  • Version history updated with the Medilearn fork entry.
  • How to resume rewritten to reflect the dual-app shippable state and to provide a recipe for any future third-tenant fork.
  • Added lesson 21 (Meeting SDK toggle gotcha on new General Apps) and lesson 22 (HTML <title> overrides BrowserWindow title) for next time someone treads this path.

Final state at session close

  • Zoom Companion/dist/Camera Monitor-0.11.0-arm64.dmg — Mobilearn shippable, unchanged from yesterday.
  • Zoom Companion Medilearn/dist/Camera Monitor (Medilearn)-0.11.0-arm64.dmg — Medilearn shippable, built at 19:36 this evening with all cosmetic fixes applied.

Closing exchange — port-conflict decision

Hasmukh noticed late in the session that both Mobilearn and Medilearn builds listen on the same local TCP ports (8765 for OAuth callback, 8766 for the broadcast overlay) because the fork shares the source code. Running both apps simultaneously on the same Mac would cause the second to fail to bind 8766 and clash on 8765 during OAuth.

Offered three options: move the overlay to 8767 only (one-line change), move both ports (requires Marketplace Redirect URL update too), or leave as-is. Hasmukh chose leave as-is — operators run one app at a time, picking whichever build matches the meeting they're monitoring. The constraint is logged as lesson 23 in the shared project memory so future-me doesn't re-discover it. If two concurrent productions on different tenants ever need to share a Mac, the fix is documented for one-line implementation.

Follow-ups

  • Live-verify the Medilearn OBF flow (operator authorises OAuth via the Medilearn app, joins an auth-off non-medilearn meeting, bot joins on their behalf). Only the ZAK path was tested today.
  • Operator guide for Medilearn: the bulk Mobilearn → Medilearn swap is in; a careful read-through against the Medilearn workflow before distribution is worth doing.
  • Release email for the Medilearn distribution, analogous to Zoom Companion/RELEASE-EMAIL-v0.10.0.md. Not drafted yet.
  • Lessons captured in project memory for any future third-tenant fork: enable Meeting SDK + programmatic join on the Embed tab (lesson 21); nuke and reinstall node_modules after rsync (iCloud strips files); remember to update both BrowserWindow.title and HTML <title> (lesson 22); port conflict between sibling builds is unsupported by design (lesson 23).