A Telegram bot that lets you manage Jira tickets and run AI-assisted dev workflows from your phone — create, move, comment, solve issues, ask Claude questions about your code, and run CLI commands, all without opening a browser or laptop.
curl -fsSL https://raw.githubusercontent.com/sayjeyhi/DevM8/main/install.sh | bashPrefer to review the script before running:
curl -fsSL https://raw.githubusercontent.com/sayjeyhi/DevM8/main/install.sh -o install.sh
less install.sh
bash install.shPin to a specific release:
DEVM8_VERSION=v1.0.0 curl -fsSL https://raw.githubusercontent.com/sayjeyhi/DevM8/main/install.sh | bashThe installer:
- Detects your platform and downloads the correct binary
- Verifies the SHA-256 checksum against
checksums.txt - Installs to
/usr/local/bin(or~/.local/binif not writable) - Registers a system service (launchd on macOS, systemd on Linux)
- On Linux: installs
bubblewrapfor Claude process sandboxing (see Security) - Runs the configuration wizard on first install (skipped in non-interactive environments)
$ devm8
DevM8 — Jira + Claude + Telegram assistant
Usage: devm8 <COMMAND>
Commands:
daemon Run the daemon process (internal — invoked by launchd)
start Start the daemon (macOS: launchd, Linux: systemd)
stop Stop the daemon
status Show daemon status
logs Show or follow daemon logs
config Run the configuration wizard
update Check for and apply binary updates
slackmap Configure Slack integration
migrate-users Map channel identities (Telegram/Slack/Teams IDs) to emails, and
optionally issue a devm8-client pairing code
clone Clone a repository via SSH
add-project Add a local git repository as a project
version Print version
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version| Platform | Support |
|---|---|
| macOS 12+ arm64 (M-series) | Supported |
| macOS 12+ x64 (Intel) | Supported |
| Linux x64 glibc | Supported |
| Linux ARM64 | Not supported |
| Alpine / musl Linux | Not supported |
| Windows | Not supported |
No runtime required — the binary is self-contained.
Prerequisites:
- A Telegram bot token (@BotFather)
- A Jira Cloud API token (
https://id.atlassian.com/manage-profile/security/api-tokens) - Claude Code CLI installed and authenticated (
claude login)
| Command | Description |
|---|---|
/create |
Create a new Jira issue |
/move |
Move an issue to a different status |
/comment |
Add a comment to an issue |
/my_tickets |
Browse your assigned tickets with pagination |
/jira |
Interactive Jira panel (create, move, comment, solve from one menu) |
| Command | Description |
|---|---|
/ask |
Ask Claude a question about a repo, or run a CLI command inside the sandbox |
/solve |
Analyze a Jira ticket with Claude and get implementation steps |
/history |
Browse your past /ask and /solve conversations, grouped by project (also reachable via the "History" button on /status) |
| Command | Description |
|---|---|
/permissions |
Manage which users can access which projects |
/admin |
Admin panel (clone repos, add projects) |
/clone |
Clone a git repository |
/logs |
View recent bot logs |
/status |
Show bot status and config summary |
/help |
List available commands |
devm8-client is a terminal counterpart to the Telegram bot — ask Claude questions, run /solve against a Jira ticket, and browse chat history, all from the command line. It talks to your devm8 server over the network (typically your Tailscale tailnet), so it can run on a completely different machine than the one hosting the bot — your laptop, for instance, while devm8 itself runs on a home server or VPS.
Add an [api] block to ~/.config/devm8/config.toml on the machine running devm8 (see Config File below for the full schema), then restart:
[api]
port = 7887By default this listens on all interfaces; a bearer token is required for every request, and reachability is expected to come from your Tailscale ACLs rather than a public bind address. Plain HTTP is fine over a tailnet (already WireGuard-encrypted) — set tls_cert_path/tls_key_path (e.g. from tailscale cert <magicdns-name>) only if you need real HTTPS.
devm8 migrate-usersThis walks you through attaching a real email to any Telegram/Slack/Teams user IDs devm8 has only ever seen as raw platform IDs, then offers to issue a short-lived pairing code for a chosen email:
Issue a devm8-client pairing code now? Yes
Email to pair: you@example.com
Pairing code for you@example.com: ABCDE-12345
Valid for 10 minutes.
curl -fsSL https://raw.githubusercontent.com/sayjeyhi/DevM8/main/install.sh | bash -s -- --client
devm8-client login --server https://myserver.tailnet-name.ts.net:7887 --code ABCDE-12345--client installs only the devm8-client binary — no launchd/systemd service is registered, since it's an interactive CLI, not a daemon. The issued token is stored in ~/.config/devm8-client/credentials.toml (mode 0600).
devm8-client login --server <url> --code <pairing-code> # pair this machine
devm8-client logout # forget stored credentials
devm8-client whoami # show the logged-in identity
devm8-client projects # list accessible projects
devm8-client ask [QUESTION...] [--project KEY] # ask Claude (interactive REPL if no question given)
devm8-client solve <ISSUE-KEY> # run the /solve analysis flow
devm8-client pr-review <PR-URL> # review a GitHub pull request with Claude
devm8-client jira # open the Jira menu (tickets, create, move, comment, account setup)
devm8-client history [--limit N] [--project KEY] # pick a project, then list its past sessions
devm8-client history show <SESSION_ID> # show a session's full transcript
devm8-client update # check for and apply devm8-client binary updates
devm8-client opencode [--account NAME] # attach an opencode session to your active /ask worktree (Tailscale SSH)Interactive ask sessions (no question given) and jira open a full-screen terminal UI in the style of opencode's TUI: a rounded header box with the client version, project, your identity, and the server host; a scrolling transcript where markdown answers are rendered with bold headers, accented inline code and code blocks, and your sent messages are echoed as ❯ your question; a live spinner line while Claude works; the follow-up choices as a selectable actions list above a bordered message input box; and a dim footer of key hints. Keys: type to compose, ↵ sends (or picks the highlighted action when the input is empty), ↑/↓ moves through the actions list or your sent-message history, esc hides the actions list for free text, PgUp/PgDn (or the mouse wheel) scroll the transcript past a scrollbar on its right edge — scrolling up pins the view so streaming answers don't push the text around, and scrolling back to the bottom re-attaches to the live reply, and Ctrl-C/Ctrl-D exit. A submit typed while Claude is still working is queued and sent when the current answer finishes.
The terminal channel also cleans up what the chat flows format for Telegram: color emoji are demoted to text glyphs (✅→✓, ❌→✗, ⭐→★, ⬜→[ ]) or stripped entirely, so menus read Pull latest (0 behind) instead of ⬇️ Pull latest (0 behind) — Telegram, Slack, and Teams are unaffected.
Responses are rendered as terminal markdown — headers, styled code blocks, inline code — and while Claude works you get a live spinner showing the current progress line instead of a log of repeated updates. In the linear UI, follow-up choices come up as an arrow-key menu: Enter picks one, Esc drops you back to a free-text prompt, Ctrl-C exits. devm8-client jira drives the same choice menus to show the same options Telegram's /jira command offers: My Tickets, Create Ticket, Move Ticket, Add Comment, Solve Ticket, and account settings (connect/reconnect/disconnect a personal Jira account, manage its accessible projects, and pick favorite statuses).
Both ask and history (the listing form) prompt you to pick a project from your accessible projects first — skipped automatically when you have exactly one project or pass --project KEY. In an interactive terminal, ask's picker is the full-screen TUI's opening screen: the same header box and footer hints as the session, an arrow-key projects list (↵ selects, esc quits). history and linear-mode runs prompt inline, and history also offers an arrow-key picker to open any listed transcript. Everything degrades gracefully: pass --plain to ask/jira to force the linear UI, and piped/redirected output or NO_COLOR always gives plain, script-friendly text with the classic > prompt and numbered choices.
- v1 scope covers
ask,solve,jira, andhistory. - A CLI-only user (paired via email but never set up in Telegram/Slack/Teams) can connect their own Jira account directly from
devm8-client jira→ Settings, or reuse one already configured through a chat channel — either way, the same personal Jira credentials work across all channels. - Chat history is shared across all channels — a
/solverun from Telegram shows up indevm8-client historytoo, and vice versa.
Location: ~/.config/devm8/config.toml
Run devm8 config to launch the interactive wizard at any time.
[telegram]
bot_token = "YOUR_TELEGRAM_BOT_TOKEN"
# Users allowed to use the bot. If empty, all users are allowed.
allowed_user_ids = [123456789]
# Only this user can run admin commands (/permissions, /admin, /logs, /clone).
admin_user_id = 123456789
# Per-project access control: project key -> list of allowed user IDs.
# Users listed here but NOT in allowed_user_ids are restricted to only their granted projects.
# If a project key is absent, all allowed_user_ids can access it.
[telegram.project_access]
PROJ = [111111111, 222222222]
BZ = [111111111]
[jira]
base_url = "https://yourcompany.atlassian.net"
email = "you@example.com"
api_token = "YOUR_JIRA_API_TOKEN"
project_keys = ["PROJ", "BZ"]
# Per-project ticket description templates for /jira -> Create Ticket.
# Value is a path to a Markdown file with the instructions Claude follows
# when drafting a description (e.g. a bug-report skeleton with "Steps to
# Reproduce" / "Expected vs Actual" sections). Relative paths resolve
# against ~/.config/devm8. Projects with no entry, or an unreadable file,
# fall back to the built-in default instructions.
[project_ticket_templates]
PROJ = "templates/proj-bug.md"
BZ = "/absolute/path/to/bz-template.md"
[claude]
binary_path = "/usr/local/bin/claude"
# api_key = "sk-ant-..." # optional if already authenticated via `claude login`
# sandbox = true # default: true on Linux, false on macOS (see Security)
# timeout_ms = 300000
# Per-project repo paths for /ask and /solve.
[repos]
PROJ = ["/home/you/code/myrepo"]
BZ = ["/home/you/code/blaze", "/home/you/code/blaze-infra"]
# Optional Slack integration
[slack]
user_token = "xoxp-..."
poll_interval_ms = 30000
# Optional local API server for devm8-client (see "devm8-client (Terminal Client)" above).
# Unset entirely = disabled.
[api]
port = 7887
# bind_addr = "0.0.0.0" # default; the real access boundary is the bearer token + Tailscale ACLs
# tls_cert_path = "/path/to/tailscale-cert.pem" # optional, e.g. from `tailscale cert`
# tls_key_path = "/path/to/tailscale-key.pem"
[app]
log_level = "info" # info | debug | errorThe /permissions command opens an interactive menu for the admin to control project-level access:
- Add a user by Telegram user ID
- Toggle project access per user — Jira projects and git repos shown separately
- Revoke all access for a user in one tap
- Changes persist to the config file immediately
Access rules:
- Users in
allowed_user_idshave unrestricted access to all projects. - Users added only via
/permissions(inproject_access) are restricted to exactly the projects granted to them — they cannot access other projects via any command. - The admin (
admin_user_id) always has full access regardless ofproject_access.
On Linux, every Claude subprocess and CLI command run via /ask is isolated with bubblewrap (bwrap), a lightweight Linux namespace sandbox. The install script installs it automatically.
Each Claude or shell invocation runs in a fresh namespace:
| Resource | Inside sandbox |
|---|---|
| Project directory | Mounted read-write at /tmp/workspace |
~/.claude (auth token) |
Mounted read-only |
| All other home dirs | Replaced with empty tmpfs — SSH keys, credentials, other projects invisible |
/root |
Replaced with empty tmpfs |
| System binaries / libs | Mounted read-only (needed for Claude to run) |
| Environment variables | Cleared — only HOME, PATH, TMPDIR, ANTHROPIC_API_KEY re-injected |
| Network | Unrestricted — Claude must reach the Anthropic API |
| PID / UTS / IPC namespaces | Isolated |
A user with access to project A cannot use /ask or a CLI command to read project B, ~/.ssh, .env files, database credentials, or any path outside their granted project directory.
Set claude.sandbox = false in the config to disable sandboxing (useful for debugging). On macOS, sandboxing is always off.
curl -fsSL https://raw.githubusercontent.com/sayjeyhi/DevM8/main/install.sh | bash -s -- --uninstall- Stops and removes the service
- Removes the binary from
/usr/local/binor~/.local/bin - Config files at
~/.config/devm8/are left in place — remove manually if desired
To uninstall devm8-client instead:
curl -fsSL https://raw.githubusercontent.com/sayjeyhi/DevM8/main/install.sh | bash -s -- --client --uninstallCredentials at ~/.config/devm8-client/ are left in place.
Not needed when using the install script — it strips the quarantine attribute automatically.
If you download a binary manually from the Releases page:
xattr -d com.apple.quarantine /usr/local/bin/devm8By default, systemd user services only run while an active session exists. To start at system boot without a login:
loginctl enable-linger $USERThis may require sudo on some systems. The install script prints an advisory but does not run this automatically.
Requires the Rust toolchain.
git clone https://github.com/sayjeyhi/DevM8.git
cd DevM8
cargo build --release
# Binaries at: target/release/devm8, target/release/devm8-clientThe install script downloads checksums.txt from the same GitHub Release and verifies the SHA-256 hash before installing. This guards against download corruption. Both files are served from the same release, so this is a corruption guard rather than a tamper-proof guarantee. Users requiring stronger verification should build from source.
MIT