@futurelab-studio/telepi
v0.4.2
Published
Telegram bridge for the Pi coding agent
Maintainers
Readme
TelePi
TelePi is a Telegram bridge for the Pi coding agent SDK. It lets you continue Pi sessions from Telegram — hand off from the CLI, keep working on your phone, and hand back when you're at your desk. Send a voice message and TelePi will transcribe it and feed it straight into Pi.
Features
- Bi-directional hand-off: Move sessions CLI → Telegram (
/handoff) and back (/handback) - Per-chat/topic sessions: Every Telegram chat or forum topic gets its own Pi session, picker state, and retry history
- Voice and image messages: Send voice/audio for transcription, or photos/image documents as Pi image inputs
- Local or cloud transcription: Parakeet CoreML on Apple Silicon, Sherpa-ONNX Parakeet for Intel Macs (and as a CPU fallback), or OpenAI Whisper in the cloud
- Session tree navigation: Browse, branch, and label your Pi session history with
/tree,/branch,/label - Cross-workspace sessions: Browse and switch between sessions from any project
- Model switching: Change AI models on the fly via
/model - Workspace-aware
/new: Create sessions in any known project workspace - Pi slash-command bridge: Run discovered Pi prompt templates, skills, and extension commands from Telegram, browse them with the paginated
/commandspicker, and surface Telegram-compatible ones in the native slash-command menu - Helpful recovery commands:
/helpfor quick usage guidance and/retryto resend the last prompt in the current chat/topic - Extension dialog support: Pi extension commands can now ask for Telegram-native selects, confirms, and text input mid-command
- Native Telegram UX: Topic-safe inline keyboards, typing indicators, HTML-formatted responses, friendly user-facing errors, auto-retry on rate limits
- Security: Telegram user allowlist, workspace-scoped tools, Docker support
Prerequisites
- Node.js 20+
- A Telegram bot token from @BotFather
- Pi installed locally with working credentials in
~/.pi/agent/auth.json
Quickstart (npm global install)
This is the main install path for TelePi on macOS (launchd) and Linux (systemd --user).
Install TelePi globally:
npm install -g @futurelab-studio/telepiRun the installer using either flow:
telepi setupWhen run in a terminal,
telepi setupprompts for the three setup values TelePi currently cares about:TELEGRAM_BOT_TOKENTELEGRAM_ALLOWED_USER_IDSTELEPI_WORKSPACE
On a fresh config copied from
.env.example, the example values are treated as placeholders, not saved defaults — pressing Enter still requires you to enter your real bot token, allowed user ID list, and workspace.Or use the fast positional form:
telepi setup <bot_token> <userids> <workspace>where
<userids>uses the same comma-separated format as the config file, for example123456789,987654321.telepi setupwill:- create or update
~/.config/telepi/config.env - preserve any existing optional config values already present in that file
- on macOS, install/update
~/Library/LaunchAgents/com.telepi.plist - on Linux, install/update
~/.config/systemd/user/telepi.serviceand runsystemctl --user daemon-reload && systemctl --user enable --now telepi.service - install the Pi
/handoffextension at~/.pi/agent/extensions/telepi-handoff.ts
If you run setup non-interactively, you must either pass all three positional values or already have them configured; TelePi now fails clearly instead of writing placeholder values.
Verify the installed config at
~/.config/telepi/config.envwith your real values:TELEGRAM_BOT_TOKEN=123456789:AAFf_real_token_from_botfather TELEGRAM_ALLOWED_USER_IDS=111111111,222222222 TELEPI_WORKSPACE=/Users/you/your-main-projectNotes:
TELEPI_WORKSPACEis strongly recommended in installed mode so fresh Telegram sessions start in the right projectPI_SESSION_PATHis usually injected automatically by/handoffOPENAI_API_KEY,SHERPA_ONNX_MODEL_DIR,PI_MODEL, andTOOL_VERBOSITYare optional
Verify the install:
telepi statusOpen Telegram and send
/startto your bot.
Rerunning telepi setup after upgrades is safe; it refreshes the service unit and extension while preserving your config. After setup, /handoff automatically reuses the installed launchd service on macOS or systemd --user service on Linux by default.
Development from Source
Use a source checkout when you want to hack on TelePi or run the latest unreleased code.
- Install dependencies:
npm install - Copy the example environment file and fill it in:
Replace the example values fromcp .env.example .env.env.examplewith your real settings. At minimum set:TELEGRAM_BOT_TOKENTELEGRAM_ALLOWED_USER_IDSTELEPI_WORKSPACEif you want fresh Telegram sessions rooted somewhere other than the repo directory
- Start the bot in development mode:
npm run dev - To test the installed-mode flow from a checkout, build first and use the built CLI entrypoint:
npm run build node dist/cli.js setup # or: node dist/cli.js setup <bot_token> <userids> <workspace> node dist/cli.js status
If you are working from a built checkout or GitHub Release artifact instead of a global npm install, install runtime dependencies first — the dist/ files are not self-contained:
npm install --omit=dev
# or: npm ci --omit=dev
node dist/cli.js setup
node dist/cli.js startTelegram Commands
| Command | Description |
|---------|-------------|
| /start | Welcome message, session info, and voice backend status |
| /help | Quick command reference and usage tips |
| /commands | Open a paginated picker for TelePi commands plus discovered Pi prompt templates, skills, and extension commands |
| /new | Create a fresh session (shows workspace picker if multiple known) |
| /retry | Re-send the last prompt in the current chat/topic |
| /handback | Hand session back to Pi CLI (copies resume command to clipboard) |
| /abort | Cancel the current Pi operation |
| /session | Show current session details (ID, file, workspace, model) |
| /sessions | List all sessions across all workspaces with tap-to-switch buttons |
| /sessions <path\|id> | Switch directly to a specific session file or session ID/prefix |
| /model | Pick a different AI model from an inline keyboard |
| /tree | View the session entry tree; navigate with inline buttons |
| /branch <id> | Navigate to a specific entry ID (with confirmation) |
| /label [args] | Add or clear labels on entries for easy reference |
Sessions, inline keyboards, and /retry state are isolated per Telegram chat/topic, so forum topics can be used independently without colliding with each other.
/commands now opens a mobile-friendly inline picker with pagination plus All, TelePi, and Pi filters. Tapping a TelePi entry runs the built-in command immediately, and tapping a Pi entry forwards the slash command into the active Pi session. Telegram-compatible discovered Pi commands (for example /review or /compact) are also synced into Telegram's native slash-command interface for the current chat. Commands that Telegram cannot represent, such as /skill:browser-tools, stay available through the picker and by manual typing.
Any non-TelePi slash command that matches the active Pi session's discovered commands is forwarded into Pi unchanged. That means Telegram can now trigger file-based prompt templates (for example /review), skills (/skill:browser-tools), and compatible extension commands. Interactive extension commands can also open Telegram-native select/confirm/input dialogs while the command is running.
External Prompt Inbox
For cron jobs, mail filters, webhooks, or log watchers, keep the external trigger outside TelePi and write a .txt file into a prompt inbox instead:
TELEPI_PROMPT_INBOX_DIR=/absolute/path/to/prompt-inbox
TELEPI_PROMPT_INBOX_INTERVAL_MS=60000 # optional; default 60s, minimum 1sWhen enabled, TelePi polls the directory, processes one .txt file at a time, sends its trimmed contents to the root chat for the first TELEGRAM_ALLOWED_USER_IDS entry, and deletes the file after accepting it. If that chat is already busy, files stay queued for the next poll. Empty .txt files are deleted to avoid loops; subdirectories and non-.txt files are ignored.
Voice and Image Messages
Send any Telegram voice message or audio file and TelePi will transcribe it and feed the transcript straight into Pi as a text prompt.
[you send a voice message]
🎤 "How does the session hand-off work?" (via parakeet)
[Pi responds normally]TelePi supports three transcription backends and picks the best one automatically:
| Backend | How to enable | Cost | Privacy |
|---------|---------------|------|---------|
| Parakeet CoreML (local) | npm install parakeet-coreml + brew install ffmpeg | Free | On-device |
| Sherpa-ONNX Parakeet (local, Intel Mac path) | npm install sherpa-onnx-node + download model + set SHERPA_ONNX_MODEL_DIR | Free | On-device |
| OpenAI Whisper (cloud) | OPENAI_API_KEY=sk-... in your TelePi config file | ~$0.006/min | Cloud |
TelePi tries backends in this order:
- Parakeet CoreML — best local path on Apple Silicon
- Sherpa-ONNX Parakeet — the local/offline path for Intel Macs, where
parakeet-coremldoes not run (and a CPU fallback on Apple Silicon) - OpenAI Whisper — cloud fallback
The /start command shows which backends are currently active.
Send a Telegram photo or image document to pass it to Pi as image input. Captions become the prompt; without a caption TelePi asks Pi to analyze the image.
Installing Parakeet CoreML (local transcription on Apple Silicon)
Parakeet CoreML is an optional dependency (~1.5 GB download, macOS only with Apple Silicon):
npm install parakeet-coreml
brew install ffmpeg # required for audio decodingOn first use the CoreML model is downloaded automatically. Subsequent calls use the cached model.
Installing Sherpa-ONNX Parakeet (local transcription for Intel Macs)
This is the recommended local transcription path on Intel Macs, since parakeet-coreml is Apple-Silicon-only. It can also be used on Apple Silicon, but TelePi will still prefer Parakeet CoreML there when available.
Install the optional Node binding:
npm install sherpa-onnx-node
brew install ffmpeg # required for audio decodingDownload and extract the Parakeet model layout TelePi expects (encoder.int8.onnx, decoder.int8.onnx, joiner.int8.onnx, tokens.txt). The v3 multilingual model below is the intended Intel Mac setup:
curl -LO https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8.tar.bz2
tar xvf sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8.tar.bz2Point TelePi at the extracted directory:
export SHERPA_ONNX_MODEL_DIR="$(pwd)/sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8"If SHERPA_ONNX_MODEL_DIR is set, TelePi treats missing model files or a missing sherpa-onnx-node package as configuration errors and will not silently fall through to OpenAI.
If the native module cannot find its shared libraries on macOS, start TelePi with:
export DYLD_LIBRARY_PATH="$(pwd)/node_modules/sherpa-onnx-darwin-$(uname -m | sed 's/x86_64/x64/;s/arm64/arm64/'):${DYLD_LIBRARY_PATH}"For the exact family of Sherpa Parakeet models TelePi currently supports, plus platform notes, see:
- https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-transducer/nemo-transducer-models.html
Using OpenAI Whisper (cloud transcription)
Add your key to your TelePi config file (~/.config/telepi/config.env in installed mode, or .env in a source checkout):
OPENAI_API_KEY=sk-...No additional packages are required. Supports the same audio formats Telegram delivers (Ogg Opus, MP3, M4A, WAV, etc.).
Session Tree Navigation
Every prompt and response in Pi is stored as a tree of entries. TelePi exposes this tree so you can review history and jump back to any point to create a new branch.
/tree
Shows the session entry tree as a preformatted diagram with inline navigation buttons.
/tree — default view (last 10 entries, branch points highlighted)
/tree all — full tree with navigation buttons on every entry
/tree user — user messages onlyInline buttons let you switch between filter modes without retyping the command.
/branch <id>
Navigate to any entry by its short 4-character ID (shown in /tree). TelePi asks for confirmation and offers two options:
- Navigate here — moves the session leaf to the selected entry; your next message creates a new branch from that point
- Navigate + Summarize — same, but first generates a concise summary of the branch you are leaving
/label [args]
Attach human-readable labels to entries so you can find them easily in /tree.
/label fix-auth — label the current leaf "fix-auth"
/label <id> fix-auth — label a specific entry
/label clear <id> — remove a label
/label — list all labels in the sessionLabeled entries are highlighted in /tree output and shown in /branch confirmations.
Session Hand-off
TelePi supports seamless bi-directional session hand-off between Pi CLI and Telegram. Both directions preserve the full conversation context — the JSONL session file is the single source of truth, and whichever side opens it gets the complete history, including any messages added by the other side.
CLI → Telegram (/handoff)
You're working in Pi CLI on your laptop and want to continue from your phone:
- In Pi CLI, type
/handoff - The extension hands off your current session to TelePi — in direct mode it starts TelePi immediately, and in
launchdmode it restarts the installed LaunchAgent with the handed-off session. The defaultautobehavior pickslaunchdaftertelepi setup, otherwise direct mode — then shuts down Pi CLI - Open Telegram — TelePi is already running with your full conversation context. Just keep typing (or speak).
Extension installation
- If you used
telepi setup, the extension is already installed at~/.pi/agent/extensions/telepi-handoff.ts - If you are developing from a source checkout without
telepi setup, symlink it manually:
cd /path/to/TelePi
ln -s "$(pwd)/extensions/telepi-handoff.ts" ~/.pi/agent/extensions/telepi-handoff.tsPi auto-discovers it after symlinking (or run /reload in Pi).
The extension supports three hand-off mode settings, controlled via shell environment variables:
TELEPI_HANDOFF_MODE=auto(default) — iftelepi setupassets are present, reuselaunchdon macOS orsystemd --useron Linux; otherwise use direct modeTELEPI_HANDOFF_MODE=direct— always start a fresh direct TelePi process; best for source-checkout development or when the installed service is unloadedTELEPI_HANDOFF_MODE=launchd— force macOSlaunchdhand-off by settingPI_SESSION_PATHin thelaunchduser environment and restarting the configured LaunchAgentTELEPI_HANDOFF_MODE=systemd— force Linuxsystemd --userhand-off by settingPI_SESSION_PATHin the user service manager and restartingtelepi.serviceTELEPI_LAUNCHD_LABEL(optional, default:com.telepi) — LaunchAgent label/plist name to restart inlaunchdmode or auto-detect
Direct mode
Direct mode starts a separate TelePi process. That is the natural default for source-checkout development, where you typically export:
export TELEPI_DIR="/path/to/TelePi"If a global telepi command is available and ~/.config/telepi/config.env exists, direct mode can also launch the installed CLI explicitly. If the installed config is missing, /handoff now falls back to TELEPI_DIR when that source checkout path is available.
launchd mode (default after telepi setup on macOS)
If you installed TelePi with telepi setup, no extra shell exports are required: /handoff auto-detects the installed config + LaunchAgent plist and reuses the resident launchd-managed bot instead of starting a second direct polling process.
If you are testing the installed flow from a source checkout, run the installer from the built checkout first:
npm run build
node dist/cli.js setupYou can still force launchd mode explicitly (or point at a non-default label) with:
export TELEPI_HANDOFF_MODE=launchd
export TELEPI_LAUNCHD_LABEL=com.telepiIn launchd mode, /handoff only does two things: set PI_SESSION_PATH in launchd, then restart the configured LaunchAgent. That keeps TelePi to a single bot process and avoids Telegram token conflicts.
Note:
launchctl setenvdoes not persist across reboots. After a machine restart,PI_SESSION_PATHwill be cleared and TelePi will start a fresh session until the next/handoff.
Note:
telepi setupinstalls the plist withKeepAlive, so launchd will restart TelePi if it exits. To fully stop TelePi, unload the agent:launchctl bootout gui/$UID/com.telepi.
systemd mode (default after telepi setup on Linux)
On Linux, telepi setup installs a user service at ~/.config/systemd/user/telepi.service, reloads the user daemon, enables the service, and starts/restarts it. /handoff auto-detects that service and runs:
systemctl --user set-environment PI_SESSION_PATH=/path/to/session.jsonl
systemctl --user restart telepi.serviceIf systemctl --user is unavailable, make sure your distro has user systemd sessions enabled. On headless servers you may need lingering:
loginctl enable-linger "$USER"Useful commands:
systemctl --user status telepi.service
journalctl --user -u telepi.service -f
systemctl --user stop telepi.serviceTelegram → CLI (/handback)
You're on your phone and want to get back to your terminal:
- In Telegram, type
/handback - TelePi disposes the session and sends you the exact command to resume, e.g.:
cd '/Users/you/myproject' && pi --session '/Users/you/.pi/agent/sessions/.../session.jsonl' - On macOS and Linux desktops with
wl-copy,xclip, orxsel, the command is copied to your clipboard automatically - In your terminal, paste and run — Pi CLI opens with the full conversation, including everything from Telegram
- TelePi stays alive — send any message in Telegram to start a fresh session
You can also resume with the shorthand:
# Continue the most recent session in the project
cd /path/to/project && pi -cManual hand-off
Without the extension, you can hand off manually:
- Note the session file path from Pi CLI (shown on startup)
- Start TelePi with that session explicitly:
TELEPI_CONFIG="$HOME/.config/telepi/config.env" PI_SESSION_PATH="/path/to/session.jsonl" telepi startFrom a source checkout, use the development entrypoint instead:
cd /path/to/TelePi
PI_SESSION_PATH="/path/to/session.jsonl" npm run devHow it works
Both Pi CLI and TelePi use the same SessionManager from the Pi SDK to read/write session JSONL files stored under ~/.pi/agent/sessions/. When either side opens a session file:
SessionManager.open(path)loads all entries from the JSONL filebuildSessionContext()walks the entry tree from the current leaf to the root- The full message history (including compaction summaries and branch context) is sent to the LLM
This means hand-off is lossless — no context is dropped regardless of how many times you switch between CLI and Telegram.
Cross-Workspace Sessions
TelePi discovers sessions from all project workspaces stored under ~/.pi/agent/sessions/. This means:
/sessionsshows sessions from every project (OpenClawd, homepage, TelePi, etc.), grouped by workspace/newshows a workspace picker when multiple workspaces are known, so you can start a new session in any project- Switching sessions automatically updates the workspace — coding tools are re-scoped to the correct project directory
Sessions are stored under ~/.pi/agent/sessions/--<encoded-workspace-path>--/.
For a fuller module walkthrough after the bot/install refactors, see docs/architecture.md.
File Layout
Installed mode (telepi setup) creates or manages these user-level files:
~/.config/telepi/
└── config.env ← generated from .env.example and updated by telepi setup
~/Library/LaunchAgents/ (macOS)
└── com.telepi.plist ← launchd service generated by telepi setup
~/.config/systemd/user/ (Linux)
└── telepi.service ← systemd user service generated by telepi setup
~/Library/Logs/TelePi/ (macOS)
├── telepi.out.log
└── telepi.err.log
~/.local/state/telepi/logs/ (Linux)
├── telepi.out.log
└── telepi.err.log
~/.pi/agent/extensions/
└── telepi-handoff.ts ← installed Pi CLI extensionSource checkout layout:
TelePi/
├── dist/
│ ├── cli.js ← built CLI entrypoint (`node dist/cli.js ...`)
│ └── index.js ← built bot entrypoint
├── docs/
│ ├── architecture.md ← module layout and runtime overview
│ └── npm-trusted-publishing.md ← npm release automation playbook
├── extensions/
│ └── telepi-handoff.ts ← Pi CLI extension source
├── launchd/
│ └── com.telepi.plist ← launchd template used by telepi setup
├── systemd/
│ └── telepi.service ← systemd user-service template used by telepi setup
├── scripts/
│ └── package-release.mjs ← builds release tarballs + sha256 checksums
├── src/
│ ├── cli.ts ← CLI commands (`start`, `setup`, `status`)
│ ├── index.ts ← entry point
│ ├── bot.ts ← Grammy wiring, callbacks, and shared picker state
│ ├── bot/
│ │ ├── commands/ ← grouped bot command handlers (`basic`, `sessions`, `model`, `tree`)
│ │ ├── chat-state.ts ← per-chat/topic transient state and `/retry` memory
│ │ ├── extension-dialogs.ts ← Telegram-backed extension select/confirm/input dialogs
│ │ ├── keyboard.ts ← inline keyboard pagination helpers
│ │ ├── message-rendering.ts ← Telegram HTML/plain rendering and chunking helpers
│ │ ├── prompt-handler.ts ← prompt execution, streaming, and tool updates
│ │ ├── slash-command.ts ← slash-command normalization and command catalog helpers
│ │ └── telegram-transport.ts ← safe reply/edit/send helpers and Telegram file downloads
│ ├── config.ts ← environment config
│ ├── errors.ts ← user-facing error helpers
│ ├── format.ts ← markdown → Telegram HTML
│ ├── install.ts ← public installed-mode setup/status facade used by the CLI
│ ├── install/
│ │ ├── config.ts ← config-file setup/update helpers
│ │ ├── extension.ts ← extension install/status helpers
│ │ ├── launchd.ts ← LaunchAgent plist and launchctl helpers
│ │ ├── platform.ts ← platform detection and install context resolution
│ │ ├── service-manager.ts ← shared launchd/systemd service manager interface
│ │ ├── systemd.ts ← systemd unit and systemctl helpers
│ │ └── shared.ts ← shared install types/constants
│ ├── model-scope.ts ← model filtering and grouping
│ ├── pi-session.ts ← Pi SDK session wrapper
│ ├── telegram-ui-context.ts ← Pi extension UI adapter backed by Telegram dialogs
│ ├── tree.ts ← session tree rendering & navigation
│ └── voice.ts ← audio transcription (Parakeet CoreML / Sherpa-ONNX / OpenAI)
├── test/
│ ├── bot.test.ts ← high-level bot integration tests
│ ├── bot/
│ │ ├── chat-state.test.ts
│ │ ├── extension-dialogs.test.ts
│ │ ├── keyboard.test.ts
│ │ ├── message-rendering.test.ts
│ │ ├── slash-command.test.ts
│ │ └── telegram-transport.test.ts
│ ├── config.test.ts ← config/env loading tests
│ ├── errors.test.ts ← error helper unit tests
│ ├── format.test.ts ← formatter unit tests
│ ├── install.test.ts ← install/setup integration tests
│ ├── pi-session.test.ts ← session service integration tests
│ ├── telegram-ui-context.test.ts ← extension UI adapter unit tests
│ ├── tree.test.ts ← tree rendering unit tests
│ ├── voice.decode.test.ts ← ffmpeg audio decode tests
│ └── voice.test.ts ← voice transcription unit tests
├── vitest.config.ts
├── .env.example
├── Dockerfile
└── docker-compose.ymlDocker
For production use with Docker:
docker compose up --buildThe compose file:
- Mounts
~/.pi/agentread-only (for auth and settings) - Mounts
~/.pi/agent/sessionsread-write (for session persistence) - Mounts your workspace directory read-write
- Runs as non-root, drops capabilities, enables
no-new-privileges
Security Notes
- Only Telegram user IDs in
TELEGRAM_ALLOWED_USER_IDScan interact with the bot - Pi tools are scoped to the workspace via
createCodingTools(workspace)and re-scoped on session switch - The
/handoffextension only shuts down Pi CLI if TelePi launches or restarts successfully - URL sanitization blocks
javascript:and other unsafe protocols in formatted output - Shell commands in
/handbackusespawnSync(no shell interpretation) for clipboard copy - Voice files are downloaded to a temporary directory and deleted immediately after transcription
Architecture
Telegram
↓
Grammy bot (`src/bot.ts`)
├── transport helpers → `src/bot/telegram-transport.ts`
├── rendering helpers → `src/bot/message-rendering.ts`
├── prompt lifecycle → `src/bot/prompt-handler.ts`
├── chat-local busy/retry → `src/bot/chat-state.ts`
├── extension dialogs → `src/bot/extension-dialogs.ts`
├── grouped command handlers → `src/bot/commands/*`
└── voice route → `src/voice.ts`
└── ffmpeg decode + local/cloud transcription backends
↓
PiSessionRegistry / PiSessionService (`src/pi-session.ts`)
├── AgentSession / SessionManager → `~/.pi/agent/sessions/`
├── workspace + saved-session switching
├── model scope / registry integration
├── tree navigation + labels
└── handback/session lifecycle
↓
Pi SDK + workspace-scoped coding toolsThe detailed module map, testing layout, and remaining large hotspots are documented in docs/architecture.md.
Development
npm install
npm run dev # Run with tsx (auto-loads .env)
npm run build # TypeScript compilation
npm run build:clean # Clean dist/ and rebuild
npm test # Run tests
npm run test:coverage # Run tests with coverage report
npm run package:release # Create artifacts/telepi-vX.Y.Z.tar.gz + checksum
npm run ci:release # Test + clean build + package release artifactRelease Automation
GitHub Actions publishes npm and creates the GitHub Release automatically on tag pushes matching v*.*.*.
Maintainer flow:
npm version patch # or minor / major
git push origin main --follow-tagsThe release workflow then:
- verifies the pushed tag matches
package.json - installs dependencies and runs release CI via
npx --yes [email protected] - publishes
@futurelab-studio/telepito npm - creates a GitHub Release with the packaged tarball and checksum
Notes:
- prerelease tags like
v0.2.0-beta.1are published to npm with thenextdist-tag and marked as GitHub prereleases - npm publishing uses Trusted Publishing from GitHub Actions; no
NPM_TOKENsecret is required - the trusted publisher must be configured on npm for repo
benedict2310/TelePiand workflow.github/workflows/release.yml - npm Trusted Publishing currently requires npm CLI
11.5.1+and Node22.14.0+; TelePi keeps the runner's bundled npm unchanged and usesnpx --yes [email protected]for release steps because older npm versions can fail with misleadingE404 Not Foundpublish errors even when OIDC is configured correctly - the workflow has been verified end-to-end with release
v0.2.2 - reusable setup details for this pattern live in
docs/npm-trusted-publishing.md
