Channel migration — Telegram to pendant
One crane, one CHANNEL. This page is how to move Kit from Telegram
(or Discord / Slack) onto the pendant without building a second agent.
The yard has no “switch mouth” button. You change CHANNEL, mint a
bearer from Kit’s Pendant fold, then recreate. Same folder, same
data/gantry.db, same persona. Telegram on that process goes quiet.
Who may talk, Google sub, yank: access.md. First-time
Worker + Settings: operators.md ·
access.md. New cranes (not a migrate):
install.md.
Same crane vs two mouths
| Want | Do |
|---|---|
| Kit herself on the phone, keep her memory | This walk. Change Kit’s CHANNEL. |
| Kit still on Telegram and a phone mouth | Two processes. Clone Kit, migrate the copy. Memories fork from that stamp. |
| A brand-new pendant crane | Build, channel pendant. Not this page. |
The bot token (Telegram / Discord / Slack) is dropped from .env when
you save CHANNEL=pendant. Paste it back if you ever switch the mouth
the other way. Pendant mailbox keys stay.
Before you start
- gantry-pendant code is on Workers (that repo’s CI). Secrets are not pasted in the Cloudflare dashboard.
- Yard Settings → Pendant is filled and saved: Cloudflare token,
account, Worker name, origin, Google Web client. Save and push
must have landed
GOOGLE_*andSESSION_SECRET. The fold shows ready. Pointer: access.md · Google OAuth. - GCP client is a Web application. Origin =
https://<pendant-origin>. Redirect =https://<pendant-origin>/api/auth/callback/google. - Ada (the human who will talk) has email on her Profile. Leave
Google blank; the yard learns
subafter she talks.
If Settings is not ready, Kit’s Pendant fold will refuse the mint with a pointer back to that page. Do not paste a bearer by hand.
Walk
Examples use Kit (crane) and Ada (operator / chatter). Same motion for Discord or Slack: only the old token name differs.
1. Email on the person
Ada → header name → Profile → email → save. That is what Pendant
matches until Google sub is learned. Not a reset path, not a mailbox.
2. Point the mouth
Kit → Secrets → set CHANNEL to pendant → save.
Do not recreate yet. Empty PENDANT_ALLOWED_USERS fails boot.
The Pendant fold appears once CHANNEL is pendant (or a mailbox /
bearer is already in .env). Changing Secrets does not mint a
bearer by itself.
3. Who may talk
Kit → Pendant. Tick Ada (or paste ada@example.com). Confirm-scary
Save allowlist.
Someone who is not an operator can still be a chatter: paste their email. They never need a yard login.
4. Mint the mailbox
Confirm-scary Rotate bearer. First time is a mint, not a rotation:
the yard writes PENDANT_MAILBOX_URL (wss://…/ws/kit) and
PENDANT_BEARER, merges kit:<token> into Worker CRANE_BEARERS.
No wrangler. Do not also secret put that map from the pendant CLI —
a bulk put can drop yard-minted slugs.
5. Recreate Kit
Recreate, not restart. Boot reads .env, dials the mailbox,
publishes allow. Restart keeps a ghost allowlist.
6. Phone
Open the pendant origin from Settings. Sign in with Google. Ada should see Kit and talk.
After a few turns, spend may show a raw 1182… and offer to store it
on Ada’s profile. Accept; the next allowlist push becomes sub:email.
Keep Telegram too
Clone Kit with settings + persona + database. The copy is a new
slug. If the source was already pendant, clone mints a new bearer
(never copies PENDANT_BEARER). If the source is still Telegram,
migrate the clone with the walk above; leave Kit on Telegram.
Two processes, two memories after that stamp. One Completer does not speak two mouths.
Back to Telegram
Kit → Secrets → CHANNEL=telegram. Confirm TELEGRAM_BOT_TOKEN and
TELEGRAM_ALLOWED_USERS (numeric ids, not @username). Recreate.
Pendant keys can stay unused. The Worker still has kit:<token> until
you rotate on a pendant crane or destroy Kit (destroy drops the slug
from CRANE_BEARERS).
Stuck
| Symptom | What to do |
|---|---|
| Pendant fold missing | CHANNEL is not pendant yet, or Secrets save did not write the file. |
| Crane dies on boot / empty list | Save the allowlist (email is enough), then recreate. |
| Google works, crane list empty | Allowlist not saved, or recreate never ran. Until /me lists a crane the phone used to fetch Kit’s avatar (401 on /api/avatar?slug=kit). Type the real slug on that screen, or wait for pendant allow sent and refresh. |
| Phone 401 / stuck on Kit | Google is fine. The picker is not yard “assigned cranes” — it is Google email/sub → rooms that published allow. |
Worker 503 config |
Settings → Pendant did not land Google / SESSION_SECRET. Save and push again. |
| Rotate says not pendant | Secrets still has the old CHANNEL. Save pendant first. |
| Rotate / Build points at Settings | Cloudflare token, account, Worker name, or origin missing. |
| Sign-in redirect error | GCP client must be Web, redirect exactly /api/auth/callback/google on the pendant origin. |
| Telegram still answers | Recreate did not run, or CHANNEL never saved. One process, one mouth. |
The yard cookie never goes to the Worker. Ada’s Google login is not a yard session.