Telegram bridge for controlling codex on a remote machine.
Each declawed process keeps:
- one allowed Telegram chat
- one active Codex job at a time
- one continuing Codex thread for that session
Release binaries are the primary distribution path. The release workflow, installer,
Homebrew formula template, and cargo-binstall metadata are wired for
https://github.com/bitboom/declawed. Publish the repo there, or update the URLs
in Cargo.toml, install.sh, and packaging/homebrew/declawed.rb first.
One-line install from a GitHub Release:
curl -fsSL https://raw.githubusercontent.com/bitboom/declawed/main/install.sh | bashManual binary install:
- Download the archive for your platform from GitHub Releases.
- Verify the matching
.sha256file. - Extract
declawedand place it on yourPATH.
Homebrew tap skeleton:
- Formula template:
packaging/homebrew/declawed.rb - Copy it into a tap repo such as
homebrew-tap/Formula/declawed.rb - Replace the placeholder
sha256values with the hashes from the release assets
Cargo channels after publish:
cargo install declawed
cargo binstall declawedexport DECLAWED_TELEGRAM_BOT_TOKEN=...
export DECLAWED_TELEGRAM_ALLOWED_CHAT_ID=123456789
export DECLAWED_CODEX_WORKDIR=/path/to/repo # optional, defaults to current directory
declawedDuring development:
cargo run- Open your bot in Telegram and send any message.
- Read the recent update with your bot token:
curl -fsSL "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates"- Use
message.chat.idasDECLAWED_TELEGRAM_ALLOWED_CHAT_ID.
On startup declawed prints:
- the Telegram bot username
- a direct bot link you can open in Telegram
- a QR code that opens the bot
- a one-word fruit session name for display only
flowchart TD
A[Start declawed] --> B[Load DECLAWED_* env]
B --> C[Create TelegramBridge]
C --> D[Fetch bot username with getMe]
D --> E[Print bot link and QR for this session]
E --> F[Long-poll Telegram getUpdates]
F --> G{Message from allowed chat id?}
G -- No --> H[Ignore]
G -- Yes --> I[Handle Telegram command]
I --> S["/status"]
I --> X["/cancel"]
I --> U["/mode auto or /mode danger"]
I --> P[Plain text prompt]
P --> J{Saved Codex thread?}
J -- No --> K[codex exec --json --full-auto -C workdir prompt]
J -- Yes --> L[codex exec resume --json --full-auto thread_id prompt]
K --> M[Parse thread.started and final agent_message]
L --> M
M --> N[Save thread_id and last result]
N --> O[Send summary back with sendMessage]
S --> ST[Return active or last job state]
X --> Q[Kill active Codex process]
Q --> R[Mark job canceled and reply]
U --> V[Switch future job execution mode]
Runtime notes:
DECLAWED_TELEGRAM_ALLOWED_CHAT_IDis required. Other chats are ignored.- Plain text continues the same Codex thread when a previous
thread_idexists. - New jobs use
codex --full-autoby default. /mode dangerswitches future jobs to--dangerously-bypass-approvals-and-sandbox./mode autoswitches future jobs back to--full-auto.- The fruit session name is only a display label. It is not used for authentication.
- Telegram receives short status and completion summaries, not raw terminal streaming.
- plain text: run or continue the current Codex thread
/status: show the active or last job/mode: show the current execution mode/mode auto: usecodex --full-autofor future jobs/mode danger: use--dangerously-bypass-approvals-and-sandboxfor future jobs/cancel: stop the active job/help: show the command summary
Each server run keeps one allowed Telegram chat and one continuing Codex thread.
Tagging vX.Y.Z on GitHub triggers the release workflow in
.github/workflows/release.yml. It builds:
x86_64-unknown-linux-muslx86_64-apple-darwinaarch64-apple-darwin
Each release uploads:
declawed-<target>.tar.gzdeclawed-<target>.tar.gz.sha256
Typical release flow:
cargo test
cargo clippy --all-targets --all-features -- -D warnings
git tag v0.1.1
git push origin main --tags