Copilot CLI push delivery
In GitHub Copilot CLI, telex delivers messages to the agent as turns. The agent does not run or re-arm a waiter. The full, version-matched Copilot workflow is printed by the installed binary:
telex copilot skill
That command is the source of truth for the Copilot path. This guide is the operator’s overview.
Install the plugin
copilot plugin marketplace add lossyrob/telex
copilot plugin install telex@telex
The plugin contributes session lifecycle hooks and provisions the push bridge. It
maps $COPILOT_AGENT_SESSION_ID to the generic telex session id. In bridge mode,
the extension heartbeat, not $COPILOT_LOADER_PID, is the push liveness signal.
Bind and provision the bridge
First enable Copilot Extensions under /experimental. Copilot exposes the
extensions_reload tool only when this experimental feature is enabled.
telex --address <addr> copilot attach --copilot-bridge --description "<work>"
Then run the extensions_reload tool once (the agent does this; telex cannot
trigger a reload). After that, delivered telex messages arrive as new turns
labelled [telex] from <addr> (<attention>).
If extensions_reload is unavailable, enable Copilot Extensions under
/experimental, re-provision with
telex --address <addr> copilot resume --description "<work>", and then run
extensions_reload. If Copilot Extensions cannot be enabled, use the supported
pull fallback or detach with
telex --address <addr> copilot detach.
Receive and disposition
A pushed turn includes the ack and handle commands with the address, id, and
session filled in. The generic verbs do not read Copilot env vars, so they need
--session "$COPILOT_AGENT_SESSION_ID":
telex ack --address <addr> --id <message-id> --session "$COPILOT_AGENT_SESSION_ID"
telex handle --address <addr> --id <message-id> --session "$COPILOT_AGENT_SESSION_ID" --note "completed"
Sending is not push: telex send and telex reply also need --session.
CC observers
A session that should receive CC (observer) copies as turns opts in at bind time
with --wake-on-cc:
telex --address <addr> copilot attach --copilot-bridge --wake-on-cc --description "<work>"
Then run extensions_reload as usual. Without --wake-on-cc, CC copies are still
buffered and visible in telex inbox --all, but are not delivered as turns.
(telex wait --wake-on-cc is the separate pull-mode equivalent for non-Copilot
harnesses.)
Tear down
telex --address <addr> copilot detach
This detaches the address and, when it was the last binding, removes the bridge files so nothing reloads on a later resume. Session end also removes them.
Inspect stale bridge files left by other sessions with telex copilot gc --dry-run.
Fallback
If the bridge cannot load because Copilot Extensions cannot be enabled, push is unavailable. Surface that plainly and prepare one Telex-owned pull fallback run:
telex --address <addr> copilot fallback prepare --description "<work>"
The JSON result contains a unique run_dir plus launcher.program,
launcher.args, and a ready-to-run launcher.command. Run that launcher as one
fully detached Copilot task. Unix uses the current telex binary directly; Windows
uses a generated PowerShell file for the detached-task compatibility path. Telex
does not detach the task itself and does not run an internal delivery loop.
Preparation is idempotent until the run writes exit.code, and it leaves push
unchanged if the launcher never starts. The running launcher atomically clears
push before entering exactly one pull-mode wait. On completion,
read exit.code first, then the exact run’s delivery.json/message.json; ack
and dedupe primary deliveries by message id before preparing the next run.
telex --address <addr> status reports delivery_mode separately from
station_health: push is bridge delivery, pull is the Copilot fallback, and
conflict is a version-skew/race tripwire. The daemon rejects simultaneous push
and pull coverage.
To return to push, stop the waiter before binding the bridge:
telex --address <addr> station stop --session "$COPILOT_AGENT_SESSION_ID"
telex --address <addr> copilot attach --copilot-bridge --description "<work>"
Then run extensions_reload. The version-matched telex copilot skill contains
the full artifact, timeout, recovery, and re-arm procedure.
Compatibility
telex copilot skill prints the installed version and source build identifier, the
bridge protocol version, and the minimum compatible plugin version, and warns if the
plugin is older than the binary supports. telex --version includes the same build
identifier, while telex --json version exposes it as version.build_id. Published
release binaries are gated to report the release commit; source builds without Git
metadata may report unknown. Git fallback is accepted only for a standalone Telex
checkout, not an unrelated ancestor repository, and the value is diagnostic rather
than an attestation.
If the drain hook reports skew, inspect version.current_exe plus Get-Command telex
or command -v telex, reinstall the plugin and binary from the same release, and make
the versioned launcher precede stale shims on PATH before restarting Copilot. A binary
rollback must be paired with the plugin from the same release.
Release install scripts pin the plugin and binary to the same tag. The plugin shape is validated against a specific Copilot CLI version; see the acceptance matrix.