A fast and efficient AI agent that accepts tasks via Telegram or Discord, writes the code, opens a pull request, and reports back - so you can review and merge at your own pace. This is great for someone who wants to build their weekend project while working full-time.
Inspired by OpenClaw and OpenCode.
Send a task description to your Telegram bot. DevBot picks it up, asks the AI to write the implementation on a new feature branch, and opens a pull request on your GitHub repository. It then messages you with a plain-English summary and the PR link. You review on your own schedule and merge when satisfied - nothing ever lands on main automatically.
- Telegram or Discord - choose your messaging platform; all commands work on both
- Multi-repository - configure any number of repos; tasks are routed to the right one by name alias
- Automatic branch naming - prefix (
feat/,fix/,chore/) inferred from the task description - PR review helpers - ask the AI to explain a diff, list changed tests, or retry with a fresh branch
- SQLite by default, Postgres via
DATABASE_URLfor multi-user VPS deployments - Auto-scheduler - processes TODO tasks automatically during configurable work hours; weekday-only by default, with an opt-in weekend mode for always-on setups
- No auto-merge - every merge is a deliberate human action on GitHub
- No open ports - outbound Telegram polling only; zero inbound attack surface
- Allowlist authentication - commands from unknown Telegram user IDs are silently dropped
macOS, Linux, or WSL:
curl -fsSL https://raw.githubusercontent.com/harrison542002/dev-bot/main/scripts/install.sh | bashWindows PowerShell:
irm https://raw.githubusercontent.com/harrison542002/dev-bot/main/scripts/install.ps1 | iexThese installers download the latest release and install devbot.
The Windows installer also adds DevBot to your PATH.
Option A: Telegram (default)
- Open Telegram and message @BotFather
- Send
/newbotand follow the prompts - Copy the HTTP API token (looks like
123456789:ABCdef...) - Find your own Telegram user ID: message @userinfobot
Choose Telegram during the first-run setup wizard (or leave it as the default).
Option B: Discord
- Go to the Discord Developer Portal and click New Application
- Go to Bot → click Add Bot
- Under Token, click Reset Token and copy it
- Under Privileged Gateway Intents, enable Message Content Intent (required to read command text)
- Under OAuth2 → URL Generator, select scopes:
bot; permissions:Send Messages,Read Message History - Open the generated URL in your browser to invite the bot to your server (or use it in DMs)
- Find your own Discord user ID: in Discord, go to Settings → Advanced → enable Developer Mode, then right-click your username → Copy User ID
Choose Discord during the first-run setup wizard.
- Go to GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens
- Select your target repository
- Grant Contents: Read & Write and Pull requests: Read & Write
- Copy the token (starts with
ghp_orgithub_pat_)
DevBot supports several LLM backends - pick one and get a key for it:
| Provider | Where to get a key |
|---|---|
| Claude | console.anthropic.com |
| OpenAI | platform.openai.com/api-keys |
| Gemini | aistudio.google.com |
| Local (Ollama, LM Studio...) | No key needed |
| Codex (ChatGPT subscription) | Run codex login - see Using Codex |
devbotOn Windows PowerShell:
devbotDevBot will open the first-run setup wizard and write config.yaml for you. See Configuration Reference below if you want to review the available options afterward.
- Telegram: Send
/helpto your bot. You should receive the full command reference within a few seconds. - Discord: Type
!helpin any channel the bot can see, or in a DM to the bot.
Browse the full command guide in COMMAND_REFERENCE.md.
These values can be set in config.yaml.
| Field | Required | Default | Description |
|---|---|---|---|
bot.platform |
No | telegram |
Messaging backend - telegram or discord |
telegram.token |
If platform=telegram | - | Bot token from @BotFather |
telegram.allowed_user_ids |
If platform=telegram | - | List of Telegram user IDs permitted to send commands |
discord.token |
If platform=discord | - | Discord bot token from the Developer Portal |
discord.allowed_user_ids |
If platform=discord | - | List of Discord user snowflake IDs (as quoted strings) |
discord.command_prefix |
No | ! |
Prefix for bot commands in Discord (e.g. !task list) |
git.name |
No | DevBot |
Author name used in git commits made by the agent |
git.email |
No | devbot@users.noreply.github.com |
Author email used in commits - set to your GitHub-verified email so commits show as Verified |
github.token |
Yes | - | GitHub PAT with Contents + Pull requests Read & Write scope |
github.owner |
If not using github.repos |
- | GitHub username or org (single-repo shorthand) |
github.repo |
If not using github.repos |
- | Repository name without owner prefix (single-repo shorthand) |
github.base_branch |
No | main |
Default base branch for PRs (single-repo mode only) |
github.repos[].owner |
Yes (per repo) | - | Owner of this repository |
github.repos[].repo |
Yes (per repo) | - | Repository name |
github.repos[].name |
No | - | Short alias shown in the /task create repo selection prompt |
github.repos[].base_branch |
Yes in multi-repo | - | Base branch for PRs in this repo; required when two or more repos are configured |
github.repos[].token |
No | inherits github.token |
Per-repo token override |
ai.provider |
No | claude |
AI backend - claude, openai, gemini, local, or codex |
claude.api_key |
If provider=claude | - | Anthropic API key (console.anthropic.com) |
claude.model |
No | claude-sonnet-4-6 |
Claude model - e.g. claude-opus-4-6 for harder tasks |
openai.api_key |
If provider=openai | - | OpenAI API key (platform.openai.com) |
openai.model |
No | gpt-4o |
OpenAI model - e.g. o3, gpt-4-turbo |
openai.base_url |
No | https://api.openai.com/v1 |
Override for OpenAI-compatible endpoints |
gemini.api_key |
If provider=gemini | - | Google Gemini API key (aistudio.google.com) |
gemini.model |
No | gemini-1.5-pro |
Gemini model - e.g. gemini-2.0-flash, gemini-1.5-flash |
local.base_url |
No | http://localhost:11434 |
Base URL of the Ollama server - uses the native /api/chat endpoint; omit the /v1 suffix |
local.model |
If provider=local | - | Model name as loaded in the local server (e.g. gemma4, llama3.2, mistral) |
local.api_key |
No | `` | Usually blank; set to "ollama" if your server requires a non-empty value |
codex.model |
No | codex-mini-latest |
Codex model - e.g. o4-mini, gpt-4o |
codex.token_file |
No | ~/.codex/auth.json |
Path to credential file written by codex login |
codex.access_token |
No | - | Paste directly instead of using token_file |
codex.refresh_token |
No | - | Enables automatic token renewal without re-running codex login |
budget.monthly_limit_usd |
No | 0 |
Monthly spend cap in USD. When exceeded, DevBot switches to the local model. 0 = unlimited (still tracks spend) |
database.path |
No | ./devbot.db |
SQLite file path; ignored when DATABASE_URL env var is set |
schedule.enabled |
No | false |
Set to true to enable the auto-scheduler |
schedule.timezone |
No | UTC |
IANA timezone name (e.g. Asia/Bangkok, America/New_York) |
schedule.work_start |
No | 09:00 |
Local time to start processing tasks (Mon-Fri only, 24h format) |
schedule.work_end |
No | 17:00 |
Local time to stop starting new tasks |
schedule.check_interval |
No | "10m" |
How often to poll for TODO tasks. Uses duration format like "10s", "30s", or "5m" |
Single-repo example (Telegram):
bot:
platform: "telegram" # default; can be omitted
telegram:
token: "7123456789:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw"
allowed_user_ids:
- 123456789
# Set to your GitHub-verified email so commits show as Verified
git:
name: "Alice"
email: "alice@example.com"
github:
token: "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
owner: "alice"
repo: "my-project"
base_branch: "main"
ai:
provider: "claude"
claude:
api_key: "sk-ant-..."Single-repo example (Discord):
bot:
platform: "discord"
discord:
token: "YOUR_DISCORD_BOT_TOKEN"
allowed_user_ids:
- "123456789012345678" # your Discord user ID (quoted string)
command_prefix: "!" # use !task, !pr, !status, etc.
git:
name: "Alice"
email: "alice@example.com"
github:
token: "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
owner: "alice"
repo: "my-project"
base_branch: "main"
ai:
provider: "claude"
claude:
api_key: "sk-ant-..."Multi-repo example:
bot:
platform: "telegram"
telegram:
token: "7123456789:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw"
allowed_user_ids:
- 123456789
git:
name: "Alice"
email: "alice@example.com"
github:
token: "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # shared default token
repos:
- owner: "alice"
repo: "backend"
name: "backend" # alias shown in /task create repo selection
base_branch: "main" # required per repo in multi-repo mode
- owner: "alice"
repo: "frontend"
name: "frontend"
base_branch: "develop"
- owner: "alice"
repo: "infra"
name: "infra"
base_branch: "main"
token: "ghp_separate_infra_token" # optional per-repo token override
ai:
provider: "claude"
claude:
api_key: "sk-ant-..."DevBot can manage tasks across multiple GitHub repositories from the same bot instance. Each task is permanently linked to the repo it was created for - the agent clones, branches, and opens PRs in the correct repo automatically.
Replace the single github.owner / github.repo fields with a github.repos list. Each entry must declare its own base_branch (the global fallback is intentionally disabled in multi-repo mode to prevent branches from accidentally targeting the wrong base):
github:
token: "ghp_shared_token"
repos:
- owner: "my-org"
repo: "backend"
name: "backend" # short alias used in commands
base_branch: "main"
- owner: "my-org"
repo: "frontend"
name: "frontend"
base_branch: "develop"Use /task create and the wizard will list all configured repos and ask you to choose:
/task create
→ What's the title for your task?
→ Add a description (or /skip):
→ Which repository?
• backend (alice/backend)
• frontend (alice/frontend)
→ Reply with the alias (e.g. backend) or owner/repo.
→ Any tech stack or constraints? (or /skip):
If you skip the repo step, the task goes to the first repo in the list (the default).
/task list shows the repo label for every task when multiple repos are configured:
Tasks:
[1] [my-org/backend] Add rate limiting - IN_REVIEW
PR: https://github.com/my-org/backend/pull/42
[2] [my-org/frontend] Update login page - TODO
[3] [my-org/backend] Fix auth token expiry - DONE
The label [owner/repo] is shown only in multi-repo mode and disappears in single-repo setups to keep the output uncluttered.
Set git.name and git.email to your GitHub-verified email so all agent commits show the green Verified badge:
git:
name: "Your Name"
email: "you@example.com" # must be verified in GitHub → Settings → Emailsflowchart TD
A["`/task create
Title: Add pagination to the /users endpoint
Description: /skip
Constraints: Go, cursor-based
Result: Task 1 created`"]
B["`/task do 1
Agent generates code, pushes branch, opens PR`"]
C["`PR opened
github.com/alice/my-project/pull/42
Added cursor-based pagination with next_cursor`"]
D["Review PR on GitHub"]
E["Merge on GitHub"]
F["`/task done 1
Task 1 marked as DONE`"]
G["`/pr retry 1
Branch deleted, task reset to TODO,
agent restarting`"]
A --> B --> C --> D --> E --> F
C -. "If something goes wrong" .-> G
G -. "Retry flow" .-> B
If something goes wrong, use /pr retry <id> to reset the task and restart the implementation flow.
The auto-scheduler lets you batch up tasks on the weekend and have DevBot work through them automatically during weekday business hours - no /task do needed.
schedule:
enabled: true
timezone: "America/New_York" # your local IANA timezone
work_start: "09:00" # start picking up tasks (24h)
work_end: "17:00" # stop picking up new tasks
check_interval: "10s" # poll interval
enable_weekend: false # set true to also run Sat/SunRestart DevBot after editing the config.
Use /task create to add tasks one by one (guided wizard):
/task create → follow the prompts for each task
After adding a few tasks, /task list shows the queue:
Tasks:
[1] Refactor authentication middleware to use JWT - TODO
[2] Add pagination to the /products endpoint - TODO
[3] Write unit tests for the order service - TODO
Every check_interval, DevBot checks whether it's within the work window (work_start–work_end in your timezone, Mon–Fri by default or Mon–Sun when enable_weekend: true). If a TODO task is queued and the agent is idle, it picks up the next task automatically.
At the start of each work day you'll receive a morning briefing:
Good morning! Work day started. 3 task(s) in the queue.
As each task completes you receive the usual PR notification:
PR opened: https://github.com/alice/my-project/pull/12
Added JWT-based authentication middleware replacing the session-based approach
All PRs land in GitHub for your review. Nothing merges automatically. Use the PR review commands to inspect the work:
/pr explain 1 → plain-English summary of what changed
/pr diff 1 → abbreviated diff in chat
/pr tests 1 → list of tests added or modified
/pr retry 1 → discard and regenerate if the output isn't right
/schedule → status: work window, timezone, weekend mode, queue size, whether agent is running
/schedule off → pause (tasks accumulate but nothing auto-starts)
/schedule on → resume
/schedule next → peek at the next task that will be picked up
/schedule setup → reconfigure timezone, work hours, and weekend mode (changes are live immediately)
If you have a ChatGPT Plus, Pro, or Team subscription you can use OpenAI models without paying per-token API fees - the same way the official OpenAI Codex CLI works.
npm install -g @openai/codex # install the official CLI once
codex login # opens browser, saves tokens to ~/.codex/auth.jsonDevBot reads ~/.codex/auth.json automatically. No further configuration is needed for the tokens.
ai:
provider: "codex"
codex:
model: "codex-mini-latest" # or o4-mini, gpt-4o, etc.That's it. DevBot will use your subscription credentials and automatically refresh the access token when it expires.
DevBot tracks token usage for every AI API call and can automatically switch to a local model when your monthly spending limit is reached -> so you never get a surprise bill.
ai:
provider: "openai" # your primary commercial provider
openai:
api_key: "sk-..."
model: "gpt-4o"
# Local model acts as the free fallback when budget is exceeded
local:
base_url: "http://localhost:11434" # Ollama (default if omitted)
model: "llama3.2"
budget:
monthly_limit_usd: 100 # switch to local when $100 is reached for the month| Situation | Provider used |
|---|---|
| Monthly spend < limit | Commercial (OpenAI / Claude / Gemini) |
| Monthly spend ≥ limit | Local model - automatically and silently |
| New calendar month | Resets to commercial |
/budget pause |
Always commercial, ignores limit |
/budget resume |
Back to automatic switching |
When the threshold is first crossed, DevBot broadcasts a Telegram message:
Budget limit of $100.00 reached (spent $101.23 this month).
Switching to Local (llama3.2) for the rest of the month.
Use /budget pause to override, or /budget resume to re-enable automatic switching.
/budget
Example output:
Budget - 2026-04
Spent: $42.1800 / $100.00 (42.2%)
Remaining: $57.8200
Enforcement: active - using OpenAI
Breakdown:
OpenAI $41.3500 (12k in / 95k out)
Claude $0.8300 (1k in / 3k out)
If you need the commercial model even after the budget is exceeded:
/budget pause → use commercial provider regardless of spend
/task do 5 → runs on commercial
/budget resume → automatic switching back on
budget.monthly_limit_usd: 0disables the limit but still records usage - useful for monitoring without enforcement.- No local model configured? DevBot continues using the commercial provider with a warning when the limit is exceeded.
- Token prices are approximate. Use
/budgetto track actual spend and adjust the limit as needed. - The budget counter resets at midnight UTC on the 1st of each month.
| Attack surface | DevBot | Why |
|---|---|---|
| Web UI / browser surface | None | No HTTP server at any port |
| Open inbound ports | None | Outbound polling to Telegram API only |
| Authentication | Telegram user ID allowlist | Commands from unknown IDs are silently dropped |
| Credentials stored | config.yaml only |
Two tokens total; chmod 600 on the file |
| GitHub token scope | repo only |
Cannot delete repos, manage org, etc. |
| Auto-merge | Not possible | Token lacks merge permissions by design |
| Plugin system | None | No dynamic code loading, no community registry |
| Filesystem access | Per-task temp dir | Cloned to os.MkdirTemp, deleted with defer os.RemoveAll |
| Prompt injection | JSON schema + system prompt | AI output must match a strict schema; rogue instructions in repo content are rejected by the output parser |
