Devbot is a private, local-first Discord workspace for building software with Codex. It connects a Discord room to the repositories on your own machine, automatically chooses Luna, Terra, or Sol for each request, and can invite approved people and peer Devbots into the same workspace.
The everyday model is intentionally small:
- Ask: mention
@devbotfor an answer, or let an action-shaped mention open a proposal first. - Do: approve a proposal, use the private task workroom, or use
/dofor an intentional project change. - Check: use
/statusto see what is happening.
Devbot uses your signed-in local Codex CLI or app session and does not need a separate OpenAI API key or hosted Devbot backend. Selected project context is handled through that session; Discord messages still travel through Discord.
Devbot is the Discord front-end for whichever coding agent you already run locally. The executor is pluggable, so the same Ask / Do / Check workflow drives any of these command-line agents:
- Codex CLI (
codex) — the default and reference backend, and the only one Devbot ever selects automatically; behavior is unchanged from earlier releases. This is currently the only backend that runs/doactions, because its sandbox confines writes to the task workspace. - Claude Code (
claude) — answers only, after an explicit opt-in (/setup backend id:claudeorDEVBOT_AGENT_BACKEND=claude). Read-only answers run with--safe-mode(the CLI's documented switch that disables CLAUDE.md, hooks, plugins, skills, MCP servers, and other user customization),planpermission mode, a read-only tool allow list plus a write/network tool denylist,--strict-mcp-config,--no-session-persistence, and an isolated emptyHOME(credentials still resolve through the realCLAUDE_CONFIG_DIR). The Claude CLI has no supported flag that confines filesystem writes to a single directory (--add-dironly grants extra access), so/doactions fail closed on this backend. Detection probesclaude --helpfor every safety flag above and refuses to run an older CLI that would silently ignore them. - Gemini CLI (
gemini) and opencode (opencode) — experimental and detection-only. Devbot reports them in backend diagnostics but does not offer them as active setup choices; neither has passed real-CLI verification of read-only answers or workspace-confined actions, so no process is ever spawned for them.
Every executable backend runs under the same hardening Devbot applies to Codex: a minimal child environment (never process.env, so DISCORD_TOKEN and other Devbot secrets can never reach a third-party CLI — only exact, individually named auth variables are forwarded, with no prefix-based admission), and the prompt delivered over stdin so it never appears in process listings. Both modes are fail-closed capabilities: a backend that cannot guarantee a read-only run refuses answer mode, and a backend that cannot confine writes to the task workspace refuses action mode.
The browser setup flow bootstraps the reference Codex backend and therefore requires a signed-in Codex CLI. After setup, an owner can explicitly select compatible Claude for answer-only use; /setup doctor reports ask readiness separately from change capability.
Devbot picks a backend in this order: the DEVBOT_AGENT_BACKEND environment variable, then the /setup backend choice. Nothing else is automatic — if neither is set, Devbot uses Codex, so an incidentally installed CLI can never become the executor by mere presence. The Luna / Terra / Sol tiers map to a backend's own fast / balanced / deep model whenever you configure one (for example DEVBOT_CLAUDE_DEEP_MODEL). Run /setup backend to see detected agents and versions, or /setup doctor for the full readiness view, which gates on answer and action readiness for the active backend.
Prerequisites: Node.js 22 or newer, a signed-in Codex CLI or app, and a Discord account that can add apps to the target server.
-
Install dependencies and launch the local setup tool:
npm install npm run browsers:install npm run setup
On Linux, use
npx playwright install --with-deps chromiuminstead when Chromium system dependencies are not already installed. -
The setup page opens in your browser. Discord requires one manual platform step: create an application in the Developer Portal, open Bot, reset the token, and paste that token into the local setup page. Devbot then:
- validates the bot directly with Discord
- opens the correct server-install prompt with the required scopes and permissions
- discovers the server after installation
- requires an explicit confirmation before using the Discord server owner as the initial Devbot owner
- registers the local repository with a native folder picker
- records whether that repository's screenshots are allowed, approval-gated, or blocked
- creates a deny-by-default
devbot-privateroom - deploys slash commands and posts a reusable Discord workspace launcher
- optionally enables the Discord-native Studio board without opening any additional Studio or runtime listener
- writes the ignored local
.envand protected runtime setup state with owner-only file permissions - requests a Devbot start in the same terminal, or reports that an existing process must be restarted
The setup page binds only to 127.0.0.1, validates its loopback host, protects its API with a per-run 30-minute browser claim, clears the pasted token field after validation, and never returns the token in an API response. Completion stays locked until Node.js 22+ and a signed-in Codex CLI pass the system check. The result reports launcher/start warnings and does not claim Devbot is ready before the terminal confirms its Discord login.
The Discord application itself cannot be created by Devbot: Discord's application API exposes read and edit operations for the current app, while creation and bot-token retrieval remain in the Developer Portal. Everything after that token is automated.
For advanced or headless environments, copy .env.example to .env, fill in DISCORD_TOKEN, DISCORD_CLIENT_ID, DISCORD_GUILD_ID, and DEVBOT_OWNER_USER_ID, then run npm run dev. Devbot synchronizes guild commands automatically. In Discord, /setup wizard creates or repairs the room, repositories, and approved access.
Then use it:
@devbot explain how authentication works in this repo
/do task:fix the failing authentication test
/status
The launcher opens a personal, ephemeral workspace with project selection and native Ask, Make change, Status, Recent, Open Studio, and Refresh controls. Tasks update one shared message through routing, context preparation, work, completion, failure, or cancellation. Safe public controls open role-aware private actions for follow-up, review, validation, retry, adjustment, and cancellation. Internal task and model IDs remain in task details instead of normal conversation.
For production, run:
npm run build
npm start- Workspace: open the shared Devbot launcher or run
/dashboard; choose a project and use its native controls. - Studio: optionally enable it during setup, then run
/studioor choose Open Studio for a Components V2 board covering tasks, agents, branches, approvals, and proof. - Ask:
@devbot <question>or/ask question:<text>keeps the request read-only. - Do:
/do task:<text>is the intentional write-capable path for the owner and controllers. - Check:
/statusreports current work, blockers, repository evidence, and the next action. - Snap-to-fix: mention
@devbotwith a screenshot of a stack trace, console error, or broken UI attached; Devbot transcribes the visible error, locates the likely spot in the project, and offers a one-tap Fix it button that starts a/dotask pre-filled with the finding. - Set up:
/setup wizardis owner-only and resumable;/setup doctordiagnoses the full path.
The workspace remembers each approved user's intentional project choice locally. Explicit slash-command project options, project:<name> mentions, natural status scopes such as status on devbot?, and concrete Workspace/Studio project selections update it; merely falling back to a default does not. Mentions, /ask, /do, /status, and /dashboard use that choice when no project is supplied, then fall back to the setup default. Changing the setup default clears the setup actor's personal override. /projects labels the global default and your current selection separately. Every interaction rechecks current project access, controller authority, safe mode, and task state.
Ideas 1-8 are implemented as the ambient workroom flow:
- Natural intent preview:
@devbot fix the failing auth testis classified as a proposed action and shown as a confirmation card.@devbot why is auth failing?remains an immediate read-only answer. The proposal offers Approve and start, Edit, Answer only, and Decline. Editing opens a modal; answer-only runs without write access. - Private task threads: an approved-room mention creates a private task thread and posts the proposal there. Unrestricted projects inherit the configured Devbot audience; scoped projects admit the requester and explicit project audience IDs. Eligible peers and the bot are added when project policy permits.
- Isolated work: an approved write action runs from a separate
devbot/task/<task-name>branch and worktree under~/.devbot/worktreesby default. The source checkout is left untouched. Changed-file and bounded diff-status evidence are saved for human review. A controller can commit the reviewed paths with/task commit, validate that exact worktree with task-scoped/review validateor/review gates, and rebase it with/task sync; Devbot still does not push or merge automatically. - Needs Me:
/inboxand the dashboard Needs Me control surface proposals and other decisions waiting for the current user. Open an item to see its private task detail, workroom, approval state, branch, changed files, and verification evidence. - Proof-first completion: completion cards show recorded proof before the result, including isolation evidence, changed files, and the route used. Open proof reveals the saved task detail; Mark reviewed clears the item from Needs Me for the requester and controllers.
- Project rooms: the owner can bind a private channel or private thread to one project with
/setup project-room action:bind project:webapp channel:#webapp-room. Mentions in that room are restricted to the bound project; remove the binding withaction:remove. - Workroom roles: proposals default to Builder, Reviewer, and Verifier. The selector can change the team before approval: Builder proposes the smallest implementation, Reviewer checks scope and regressions, and Verifier defines completion evidence. These seats produce a read-only preflight brief before an approved action runs.
- Components V2: proposal, ordinary task progress/completion, task detail, review packet/validation/gates, proof, and Needs Me surfaces use bounded Discord Components V2 containers with stable, allow-listed custom IDs and disabled controls when state changes. Content is sanitized and mentions are not expanded by these cards.
Example:
@devbot update the billing retry copy in webapp
Review the private proposal, choose the roles, then select Approve and start. During execution, the workroom reports progress. On completion, inspect proof and the isolated branch before taking any repository action. For a read-only path, choose Answer only or write /ask question:... project:webapp.
Studio is an optional Discord-native Components V2 workroom. It shows task lanes, Needs Me decisions, agent roles, branch state, changed files, verification, and the selected task's result or blocker in one private interactive card. Project and task selectors update the same message; Open full task hands off to the existing revision-checked task controls.
Choose Enable Studio in npm run setup, toggle Enable Studio in /setup wizard, or set DEVBOT_STUDIO_ENABLED=true in the ignored local .env and restart Devbot. Then run /studio in the configured private room. Only the owner and approved controllers can open it. The feature creates no Activity, public URL, tunnel, web server, OAuth client secret, redirect, or loopback listener; all data travels through the bot's existing Discord connection and is filtered by current project and task access policy.
Safety and fallback behavior are intentional. Only the requester or an approved controller can edit or decline a proposal; only the owner or an approved controller can approve write work or cancel it. DEVBOT_SAFE_MODE=true blocks approval and write execution. A project with a scoped audience declines channel-mention results and directs the user to the private workspace or /ask. If Discord cannot create a private task thread, an unrestricted proposal may remain in the configured private room; a scoped proposal is closed without publishing. If the target is not a Git repository, the worktree path is unsafe, or Git isolation is unavailable, the action stops before Codex receives write access and records the blocker in task evidence.
/setup show: Show owner-managed viewers, controllers, peer bots, private room, and project roots. Every/setupcommand is restricted toDEVBOT_OWNER_USER_ID./setup user action:<add|remove> user:<user> permission:<view|control>: Manage private-room viewers. Controllers can also invoke write-capable commands; granting control automatically grants view access./setup devbot action:<add|remove> bot:<bot>: Manage peer Devbots and their private-room access./setup repo action:<add|remove|default> name:<name> path:<required for add>: Register a local project root or select the default used when a command omitsproject./setup project-room action:<bind|remove> project:<name> channel:<optional>: Bind or remove a private ambient room for one project. The selected channel must be private, and every visible member or elevated role must satisfy both the Devbot and project allowlists; Administrator and private-thread manager bypasses fail closed unless explicitly allowed./setup room name:<optional>: Create or resync the private Devbot room. It uses a deny-by-default text channel when Devbot can manage channels, otherwise it adopts or creates an invite-only private thread./projects: List configured projects./status project:<optional> question:<optional> image:<optional>: Show a decision-ready brief with confirmed Devbot tasks, task phase, external Codex runs, activity-unknown app sessions, repository evidence, visible blockers or risks, and the best next step. Add a question for a deeper read-only inspection.image:trueattaches a live UI only when policy already allows capture; approval-gated projects point to/snipfor controller consent./snip project:<optional> target:<text>: Attach a live project UI screenshot by opening the running app and navigating visible UI controls from the target text. Explicit paths and local URLs are also supported. Approval-gated projects show Approve once, Always allow, and Cancel controls to an owner/controller before capture./task recent project:<optional> status:<optional> limit:<optional>: List recent saved devbot tasks from local task history./task show id:<task-id>: Show one saved task with request, status, and result or error preview./task status id:<task-id>: Alias for showing one saved task./task logs id:<task-id>: Show the saved request, result preview, and error text./task cancel id:<task-id>: Mark a running saved task as canceled in local history./task retry id:<task-id>: Retry a failed, canceled, or interrupted saved task with the same project, mode, text, and include patterns./task freshness project:<name> limit:<optional>: Show merged state and behind/ahead counts for saved task branches against the project's local default branch. Branches that are fully merged are marked durably on the task record and flagged as prune-eligible worktrees./task commit task:<task-id> message:<optional>: Stage only the task worktree's reported changed paths and create a reviewable commit. Owner/controller-only and blocked by safe mode./task sync task:<task-id>: Rebase one task branch onto the current local default branch inside its isolated worktree. Owner/controller-only; blocked by safe mode and while the task is still open. The pre-sync tip is preserved underrefs/devbot/backup/<task-id>first, conflicts abort with the branch restored and the conflicted files reported, and configured validation runs afterwards with results reported as-is./task preview task:<task-id> action:<start|stop|status>: Start, stop, or inspect a managed dev server for the task's isolated worktree. The server runs only the project's configureddev/preview/serve/startpreset or an allow-listed package.json script, binds to a loopback origin (http://127.0.0.1:<ephemeral port>) on the machine running Devbot, and stops automatically after its TTL. It is not a public tunnel and is reachable only from that machine. Only the owner or an approved controller can start one; the task requester may inspect or stop it. Safe mode blocks starting one but never stopping it. Missing dependencies fail closed; Devbot does not install them./task stale minutes:<optional> project:<optional>: List running tasks older than a selected threshold./dashboard project:<optional>: Open the personal interactive workspace with project selection, current status, recent work, and native Ask / Change controls./studio: Open the optional Discord-native Components V2 Studio in the configured private room. Owner/controller-only; no web listener or Activity configuration is required./inbox project:<optional> limit:<optional>: Open the paginated ephemeral Needs Me inbox for up to 25 pending proposals and decisions, with review and refresh controls./run command:<name> project:<optional> confirm:<optional>: Run every command configured under that preset from<project>/.devbot/project.json. Commands not classified as read-only require an explicitconfirm:truererun./review packet project:<name> task:<optional>: Create a provider-neutral review handoff packet from git status, diff stat, last commit, and optional task context./review validate project:<name> task:<optional> commands:<optional> confirm:<optional>: Run configured validation commands in the task's verified isolated worktree when supplied, and report the exact branch tested./review gates project:<name> task:<optional> commands:<optional> confirm:<optional>: Check merge gates without merging in the exact selected checkout: clean working tree plus validation pass./devbot capabilities: Show this bot's owner, safe mode, projects, and command capabilities./devbot announce: Post a structured capability announcement for peer devbots./devbot peers: List peer devbots that have announced themselves./peer status bot:<id-or-mention> project:<optional>: Ask an allow-listed peer bot for read-only status./peer snip bot:<id-or-mention> target:<text> project:<optional>: Ask an allow-listed peer bot for a live UI screenshot./lab council prompt:<text> project:<optional> seats:<optional 2-4>: Open a persistent workroom on the selected default or explicit project with three independent local agent seats by default, plus invited peer bots, before the human reveals, challenges, synthesizes, approves, denies, or closes the room./lab roundtable project:<name> prompt:<text>: Start a private devbot strategy room with role-based product, frontend, backend, testing, and risk angles./lab see target:<text> project:<optional>: Collect a local screenshot plus peer screenshot requests for the same target when local policy permits capture; use/snipfirst when controller approval is required./lab handoff project:<name> target:<human-or-bot> task:<optional>: Create a baton-pass review handoff card and send a peer review-packet request when the target is an allow-listed bot./lab bossfight project:<name> task:<optional> commands:<optional>: Build a merge-readiness boss bar from review packets, local gates, peer observers, and approval state./lab jam project:<name> theme:<text>: Brainstorm playful options and convert the best one into a concrete task./lab argue project:<name> proposal:<text>: Run a contrarian council against a proposal from speed, safety, UX, and maintenance angles./lab fix-from-snip project:<name> target:<text> complaint:<text>: Use policy-allowed visual context and produce an approval-ready fix plan; approval-gated screenshots must be captured separately through/snip./lab campfire minutes:<optional> project:<optional>: Surface stale running tasks with recovery options./lab roster: Show peer capability cards./lab ritual project:<name> task:<optional>: Build a merge ritual card with review packet, recent tasks, and safety state./lab recent: List recent collaboration lab sessions./lab events id:<collab-id>: Show recent events for a lab session./lab approve id:<collab-id> decision:<approve|deny|read-only> action:<record|validate|gates> project:<optional> commands:<optional> note:<optional>: Record a human approval, denial, or read-only decision, optionally running validation or gates after approval./lab safety project:<optional>: Show active collaboration safety rules and approval boundaries./refresh project:<name>: Rebuild the in-memory file index for a project./ask question:<text> project:<optional> include:<optional patterns>: Ask the model a question with local project context./do task:<text> project:<optional> include:<optional patterns>: Ask local Codex to perform a focused project task. Requires owner or controller access./ship task:<task-id>: Compose a 1200x675 shareable card for a completed/dotask with the project name and task summary./shipnever starts or silently attaches to a task preview, so isolated-task cards remain text-only with an explicit "visual proof unavailable" note; use/task previewseparately to inspect that branch's running UI on the Devbot machine. A live screenshot is attempted automatically only for non-isolated tasks. Requires owner or controller access; also available as a "Ship it" button on completed action tasks./remember text:<text> project:<optional> kind:<decision|note>: Record a project decision or note for Devbot to recall later. Requires owner or controller access./memory list project:<optional> kind:<optional> limit:<optional>: List recent memory entries you have access to for a project (workroom-private outcomes are hidden unless you were the requester or are a controller)./memory search query:<text> project:<optional>: Search memory entries by relevance to a query./memory promote id:<memory-id> project:<optional>: Owner/controller-only; approve an automatically captured outcome so it becomes eligible for automatic recall./memory forget id:<memory-id> project:<optional>: Owner-only; permanently delete a memory entry. This removes it from Devbot's memory only, not from git, Discord, task, or backup history./memory purge confirm:<project-name> project:<optional>: Owner-only; permanently delete every memory entry for a project. Requires retyping the project name to confirm, and likewise leaves git, Discord, task, and backup history untouched.
You can also mention the bot in a channel:
@devbot explain why the failing test is failing
@devbot project:api include:src/* where are failed webhooks handled?
@devbot what's currently in progress
@devbot what's the status on the web build, send me a snip of the browse page
Read-only mentions use the invoking user's workspace project, then the setup-selected default as a fallback. An action-shaped mention opens a proposal instead of changing files; write-capable work starts only after an explicit approval. Use project:<name> to override the selection for one mention. Inside a project room, the room binding wins and a mention for another project is declined.
Status-style mentions such as @devbot wip, @devbot current dev work, or @devbot give me a breakdown of what you are working on return the decision-ready brief without invoking Codex. Devbot distinguishes confirmed work from an open Codex app session, because an open session can be working, waiting, or idle. It never exposes process IDs or private external prompts. Generic requests for blockers and next steps stay deterministic; diagnostic questions about failures, diffs, remaining work, or merge readiness trigger the deeper read-only Codex inspection. If the message asks for a snip, screenshot, image, or picture, the bot tries to attach a live project UI screenshot. Page hints such as browse page or watchlist are handled by opening the running app and navigating through visible UI controls instead of reading framework routes from disk. Explicit paths like /cards/op01-016 are still supported when you want an exact target.
The optional include field accepts comma-separated path patterns. * is supported as a wildcard, so examples like src/*, README.md, or *.json work.
Task history, in-flight executions, managed previews, preferences, peers, collaboration workrooms, setup, screenshots, and project memory default to owner-only files under ~/.devbot/state. Set DEVBOT_STATE_DIR to move that protected root, or use DEVBOT_TASK_STORE, DEVBOT_EXECUTION_STORE, DEVBOT_PREVIEW_STORE, DEVBOT_PREFERENCES_STORE, DEVBOT_PEER_STORE, DEVBOT_COLLAB_STORE, DEVBOT_SETUP_STORE, DEVBOT_SNAPFIX_STORE, or DEVBOT_MEMORY_STORE for an individual override; relative override paths resolve from the Devbot process working directory. On first use, Devbot migrates recognized legacy runtime files from this repository's .devbot/ directory without moving project metadata such as .devbot/project.json.
For a consistent offline backup, stop Devbot and run npm run state:backup -- /absolute/path/to/new-backup. The command loads .env, honors DEVBOT_STATE_DIR and DEVBOT_RUNTIME_LOCK, and fails closed if any individual DEVBOT_*_STORE override is configured because one directory would not be a complete snapshot. Consolidate those stores under DEVBOT_STATE_DIR or back them up separately. The destination must not already exist and cannot contain, or be contained by, the live state root. Devbot refuses symlinks and special files, writes owner-only copies plus a SHA-256 manifest, and can recheck the snapshot with npm run state:verify -- /absolute/path/to/backup. Restore remains an explicit operator action: verify the backup first, keep the bot stopped, preserve the current state root, and copy the verified data files—not manifest.json—into the configured state root.
While a task runs, Devbot keeps a durable execution record with the task identity, phase, isolated workspace, Discord message references, and the worker process id plus its spawn identity. On startup, Devbot reconciles those records instead of silently closing interrupted work as canceled:
- Each task the previous runtime left running is marked
interrupted, a distinct honest state rather thancanceled, with an account of what is known. - If the recorded worker process is still running and its spawn identity (pid, kernel start time, and command) still matches, it is stopped with an observed exit (SIGTERM, then SIGKILL) so no unsupervised writer stays alive. A pid alone is never trusted; a pid whose identity no longer matches is never signaled.
- The original task message is edited in place, in the task's original audience only, to say the bot restarted mid-task, with Retry and Dismiss controls. Retry goes back through the normal authorization, safe-mode, and isolation checks, and reuses the preserved isolated worktree when its branch identity still verifies; otherwise a fresh worktree is created. Only the requester or an approved controller can retry or dismiss interrupted work, and safe mode blocks retrying write-capable tasks.
- The isolated worktree and branch from the interrupted run are preserved as evidence, subject to the normal worktree retention cap.
Model work is not resumed or re-attached: an interrupted Codex run is never continued, only the workspace, branch, and task history survive the restart. Corrupt or malformed execution records are quarantined beside the store file and never crash startup.
DEVBOT_OWNER_USER_ID is the immutable bootstrap authority for /setup; it cannot be changed from Discord. Once /setup room creates the private room, normal slash commands and mentions are accepted only there. A managed text channel denies ViewChannel to @everyone; the no-Manage Channels fallback uses private-thread membership. Both grant access to effective ID-based viewers, controllers, the owner, the bot itself, and allow-listed peer bots. This is the layer that controls who can actually see Devbot messages. Ordinary messages previously posted in other Discord channels cannot be retroactively hidden.
Environment allowlists and static project maps remain bootstrap inputs. Discord setup augments them and never edits .env. Removing a user or repo from setup does not remove an equivalent entry still present in .env, PROJECTS_JSON, or config/projects.json.
Each target project can define optional metadata at <project>/.devbot/project.json.
{
"canonicalName": "webapp",
"frontendUrl": "http://127.0.0.1:3000",
"defaultBranch": "main",
"aliases": ["web", "frontend"],
"commands": {
"test": ["npm test"],
"build": ["npm run build"],
"verify": ["npm run build && npm test"],
"presets": {
"quick-check": "npm run build"
}
},
"policy": {
"visibility": "team",
"allowedUsers": [],
"allowedUsernames": [],
"allowedRoles": [],
"allowedPeers": [],
"screenshotPolicy": "approval",
"readOnlyCommands": ["test"],
"approvalRequiredCommands": ["verify"]
}
}Devbot only runs commands declared in that metadata file. A dev, preview, serve, or start preset also serves as the dev command for /task preview; without one, Devbot falls back to a package.json script with one of those exact names. DEVBOT_SAFE_MODE=true disables write-capable work: /do, action-task retries, /run, /task sync, /review validate, /review gates, and starting /task preview servers (stopping them still works).
Global access can be limited with ALLOWED_USER_IDS, ALLOWED_USERNAMES, and ALLOWED_ROLE_IDS. User IDs are the most stable option. Account usernames are matched case-insensitively; mutable global display names and guild nicknames are intentionally ignored.
Project policy lets each repo narrow collaboration behavior. allowedUsers, allowedUsernames, and allowedRoles scope project-specific slash command access, allowedPeers limits peer bot access per project, and screenshotPolicy can be allow, approval, or deny. Omitted screenshot policy defaults to approval. Commands must be named in readOnlyCommands to avoid an approval gate; unclassified commands fail closed.
When a project has any user or role allowlist, Devbot keeps workspace, /ask, /do, /status, /snip, /task, /run, /review, continuation, and retry results ephemeral so other members of the shared room cannot read them. Because channel mentions cannot be selectively hidden, Devbot declines mention-based results for those projects and points the user to the private workspace or /ask.
For multi-dev servers, each developer can run a separate bot application and add the other bot accounts with /setup devbot. PEER_BOT_IDS remains available as a bootstrap configuration.
Use /devbot announce to publish capabilities. Basic peer requests are sent as structured Discord messages for capabilities, status, and screenshots. The /lab workflows add versioned collaboration envelopes for planning, review packets, screenshot requests, approval cards, and event recording.
/lab council is the first persistent multiplayer workflow. It runs independent Product Steward, Systems Builder, and Evidence Verifier seats in parallel by default; seats:4 adds an Operations Guardian. It opens a private Discord thread when the channel and bot permissions support one, stores stable participant IDs and correlated peer invitations, hides proposals from normal workroom views during collection, and exposes native decision buttons. Peer fan-out requires a dedicated private text channel or private thread in COORDINATION_CHANNEL_ID; without both a private workroom and coordination room the council runs local-only in an ephemeral response. Devbot automatically unarchives a configured coordination thread and adds allow-listed peer bots before sending. Sealing prevents agents from anchoring on earlier responses; it is an application-level visibility rule, not encryption of the Discord transport or local state file. See Collaboration Protocol.
The safety boundary is deliberate: peer bots can ask, observe, plan, review, and hand off inside allow-listed projects. Peer-triggered edits, command execution, validation with side effects, pushes, merges, deploys, dependency installs, and secret/config changes require explicit human approval.
- Discord-launched agent processes — Codex and every alternative backend — receive a minimal environment without the bot token or application credentials; only exact, individually named auth/config variables are forwarded (prefix-based admission is not supported), and
DISCORD_*/DEVBOT_*variables are dropped unconditionally. Prompts are sent over standard input instead of command-line arguments so they never surface in process listings. For Codex, user config and rules are ignored, optional tools are disabled, anddanger-full-accessis rejected. Claude answers run under--safe-mode,planpermissions, a read-only tool allow list,--strict-mcp-config, and an isolatedHOME. Any backend that cannot guarantee a read-only run refuses answer mode, any backend that cannot confine writes to the task workspace refuses action mode, and unverified adapters (currently Gemini CLI and opencode) are never executed at all. - Git inspection and isolated-worktree operations run without inherited credentials, hooks, signing, filesystem monitors, pagers, or external diff helpers. Repositories with locally configured checkout filters are refused before a worktree is created.
- Retained isolated worktrees are capped at 100 by default so abandoned task branches cannot grow without bound; remove reviewed worktrees before starting more.
/task freshnessand/task showdetect task branches that are fully merged into the local default branch and mark their worktrees as eligible for that cleanup. /task syncrewrites only the isolated task branch, never the source checkout. The pre-sync tip is preserved under an exact-formatrefs/devbot/backup/<task-id>ref before the rebase, conflicts are never auto-resolved, and a conflicted or failed sync restores the branch and reports honestly.- Screenshots are limited to configured or detected loopback origins. Redirects and browser subresources are restricted to those approved origins; arbitrary localhost ports, remote hosts, credentials in URLs, and link-local metadata addresses are rejected.
- Task previews run only a configured project preset or an allow-listed package.json script from the verified isolated worktree, never free-text commands. Only controllers can start them. The child gets a minimal credential-free environment and empty temporary home; its command remains behind a private stdin gate until a stable pid, process-group id, kernel start time, command identity, and temporary-home path are durably recorded. Readiness requires an HTTP listener owned by that exact process group and bound specifically to loopback; a foreign or non-loopback listener is stopped without being accepted, and active previews keep checking the whole group for later non-loopback listeners. TTL, manual stop, shutdown, and restart recovery use SIGTERM then SIGKILL and clear state only after the whole group, listener, temporary home, and owner-only ledger are confirmed clean. A bare or recycled pid is never signaled, and previews are never exposed beyond the local machine.
- Local task, setup, preference, peer, capture, and collaboration state defaults to owner-only files under
~/.devbot/state(orDEVBOT_STATE_DIR), outside managed checkouts; legacy checkout-local state migrates on first use. Responses, stored results, errors, command output, and indexed context pass through credential redaction. - These controls reduce exposure but do not make untrusted repositories harmless. Keep credentials out of project roots, review isolated changes before applying them, use ID-based Discord allowlists, and leave screenshot policy at
approvalunless a project UI is safe to post.
Before a project request runs, Devbot can use a separate read-only routing model to choose both model capacity and prepacked context:
- Luna / direct: greetings, pings, and generic questions without repository context.
- Terra / focused: targeted questions and ordinary scoped work with ranked project snippets.
- Sol / deep context: architecture, security, migrations, broad diagnosis, and consequential changes.
The friendly route is shown while Devbot works; concrete model IDs and routing diagnostics are kept in task details. The routing model cannot change answer/action mode, grant controller access, or loosen the Codex sandbox. Deterministic validation prevents an action from being routed below Terra with focused context, and a local fallback policy takes over if the router times out or returns malformed output.
Configure the family with CODEX_ROUTER_MODEL, CODEX_FAST_MODEL, CODEX_STANDARD_MODEL, and CODEX_DEEP_MODEL. Reasoning effort and the focused context budget have separate environment controls; see .env.example.
The scanner ranks files by path and content matches against your question or task, then passes a bounded set of relevant snippets to local Codex as delimiter-safe JSON Lines records. Repository text remains data even when it contains prompt-like tags.
By default:
/askusesCODEX_SANDBOX=read-only./dousesCODEX_ACTION_SANDBOX=workspace-write.- Discord-triggered agent runs (any backend) receive a minimal credential-free child environment and take prompts over stdin rather than process arguments; Codex additionally rejects
danger-full-access, non-Codex backends refuse any mode they cannot enforce (read-only for answers, workspace confinement for actions), and unverified backends never execute. - Local task, setup, peer, collaboration, preference, and runtime state use owner-only files; active task and collaboration directories are hardened to owner-only access on supported systems.
Defaults are conservative:
- Maximum indexed file size:
80 KB - Maximum index size:
2,000 filesand8 MBof file contents - Maximum context per file:
12 KB - Maximum packed project context:
120,000 characters - Cached indexes refresh automatically after
5 seconds;/refreshstill forces an immediate rebuild - Default ignored paths include
.git,node_modules,dist,build,coverage,.env, private keys, logs, and common binary media files - Private
.devbotand.codexdirectories are always excluded, including when anincludepattern explicitly requests them
Tune these with the bounded DEVBOT_CONTEXT_* settings documented in .env.example. Invalid or excessive values fail startup rather than silently removing a limit.
MIT. See LICENSE.
In the Discord Developer Portal, create an application, add a bot, enable the bot token, and invite it to your server with these scopes:
botapplications.commands
The bot needs permission to read and send messages in the channels where you use it. /setup room prefers Manage Channels, but can adopt or create a private thread when it has Create Private Threads. Directly mentioned messages are one of Discord's documented Message Content intent exceptions, so Devbot does not request that privileged intent.