A code companion that lives in Slack.
Coding agents help us write code faster, but most engineering work isn't writing code. It's understanding how things work, reviewing PRs, figuring out what broke and why, triaging the backlog, and deciding what's safe to change. That work happens in Slack and GitHub, not in an editor.
Coda fills that gap. It answers architecture questions like "how does auth work" or "where is the model API call". It reviews PRs and open branches, diffs them against your conventions, and leaves comments. It reads open issues and flags the urgent ones worth tackling next.
Most importantly, Coda lives in Slack and works alongside your team.
Coda also learns and improves with use. It picks up your coding standards, conventions, and patterns. Over time it stops waiting to be asked — it reviews open issues on a schedule, flags low-hanging fruit, and proposes changes. It shows up in your Slack channel with a summary: here's what's worth tackling, here's why, here's how the code already handles similar cases.
Coda can write code too — in isolated worktrees that never touch main — but that's not its main job. Coda is the teammate who knows what's going on in the codebase, and is always available to talk about it.
- Create your Coda repo from this template.
- Configure GitHub and model connections.
- Tell Coda which repos to learn.
- Run locally.
- Connect to the Web UI.
- Connect to Slack.
- Deploy to your cloud provider.
- Secure your deployment.
Click Use this template to create your own repo, then clone it:
git clone https://github.com/your-org/coda.git && cd codaOr clone directly:
git clone https://github.com/agno-agi/coda.git && cd codaCopy the example environment file:
cp example.env .envCreate an OpenAI API key and add it to .env:
OPENAI_API_KEY="sk-svcacct-***"Create a GitHub Personal Access Token following docs/GITHUB_ACCESS.md and add it to .env:
GITHUB_ACCESS_TOKEN="github_pat_***"Edit repos.yaml and add your repositories:
repos:
- url: https://github.com/your-org/your-repo
branch: mainAuthor's note: I recommend just using the agno repo as a starting point, so you have some test questions you can play around with.
Make sure Docker Desktop is installed and running.
docker compose up -d --buildConfirm Coda is running at http://localhost:8000/docs.
Coda runs on Agno AgentOS, which gives you a web UI to chat with Coda directly — plus monitoring and debugging tools like sessions, traces, metrics, memory, and evaluations.
- Open os.agno.com and log in
- Add OS → Local →
http://localhost:8000 - Click "Connect"
For production deployments, replace
localhost:8000with your deployed URL.
With Coda running, follow docs/SLACK_CONNECT.md to create your Slack app and connect it. Once connected, add the credentials to .env:
SLACK_TOKEN="xoxb-***"
SLACK_SIGNING_SECRET="***"Then restart to pick up the Slack credentials:
docker compose up -dThere are two ways to talk to Coda:
Direct message — find Coda under Apps in the Slack sidebar and message it directly:
what repos are available?
walk me through the auth flow
In a channel — invite Coda first, then mention it in any message:
/invite @Coda
@Coda what are the open PRs?
Each thread is its own conversation — follow-up messages in the same thread don't need to @mention Coda again.
Coda comes with a script to deploy to Railway. Install the Railway CLI, then:
railway login
# First-time setup (creates project, database)
./scripts/railway_up.sh
# Sync env vars after changing .env (handles multiline keys like PEM)
./scripts/railway_env.sh
# Redeploy the app after code changes
./scripts/railway_redeploy.shOnce deployed, update your Slack app to point at the new URL:
- Copy your production URL from the Railway dashboard
- Go to your Slack App settings → Event Subscriptions
- Update the Request URL to:
https://your-production-url/slack/events - Wait for Slack to verify the endpoint
If you were using ngrok for local development, you can stop it now — Slack will route all messages to your deployed instance.
See
railway.jsonto adjust CPU, memory, and replica settings.
Production requires RBAC authentication via AgentOS. See Security below for setup — you'll need to connect your OS at os.agno.com and add a JWT_VERIFICATION_KEY to your environment.
Ask a question in Slack and get an answer grounded in the actual code — with file paths and line numbers. Coda reads files, greps through them, and follows call chains to trace how things connect.
@Coda where is the webhook handler for Stripe events?
@Coda walk me through the signup flow
@Coda find all API endpoints that accept file uploads
@Coda what breaks if I change get_customer()?
Coda pulls PR details, reads the changed files, diffs them against your conventions, and leaves inline comments — all from Slack.
@Coda review PR #42
@Coda what changed on the feature/payments branch?
@Coda compare this branch against main
Coda doesn't just read issues — it acts on them. It categorizes, labels, comments with code-backed analysis, flags duplicates, and closes junk. Ask it to review a batch and it'll triage the whole backlog.
@Coda review the last 10 issues on agno, let's wrap em up
@Coda triage the open issues and label them
@Coda clean up the stale issues
@Coda what are the open bugs? label them and flag the critical ones
Coda doesn't just respond — it shows up on its own. Scheduled tasks run in the background and post to your Slack channels automatically.
Daily Digest — every morning, Coda posts a summary of your repositories: what merged yesterday, what PRs are waiting for review, what issues were opened, and what's gone stale. Like a standup that writes itself.
Issue Triage — on a schedule, Coda's Triager agent reviews your open issues against the actual codebase, categorizes them, labels them on GitHub, and posts a summary to Slack. The same agent that handles interactive triage requests runs the daily scan — so you know it works.
Repo Sync — Coda pulls the latest changes from all configured repositories every 5 minutes, so it's always working with current code.
Schedules are registered automatically on app startup — no manual setup needed. They're idempotent, so restarting the app just updates existing schedules. To trigger a triage manually: POST /triage-issues.
For issue triage to post to Slack, set TRIAGE_CHANNEL in your env to the target channel ID (right-click channel in Slack → View details → copy ID).
You can also build your own scheduled tasks — automatic PR review when new PRs are opened, stale branch alerts, or convention drift detection. See tasks/ for examples.
Drop a feature request in Slack and Coda breaks it down into ordered, well-scoped GitHub issues — each with descriptions, code pointers, labels, and dependencies.
@Coda plan out adding webhook support to the payments service
@Coda break down the auth rewrite into implementable issues
@Coda create issues for adding rate limiting across all API endpoints
When a question goes beyond the codebase — framework docs, library APIs, error messages, security advisories — Coda searches the web and brings back answers with sources.
@Coda what changed in FastAPI 0.135?
@Coda what's the recommended way to handle rate limiting in Redis?
@Coda are there known vulnerabilities in pyjwt 2.12?
@Coda how does OpenAI's function calling work?
When you're ready, Coda writes code in isolated git worktrees and opens PRs. Your main branch is never touched.
@Coda add rate limiting to /api/v1/users using the same pattern as /orders
@Coda fix the NoResultFound bug in payment_service
@Coda write integration tests for the export endpoint
Coda gets sharper the more you use it.
Week 1: @Coda add a new endpoint for exporting invoices
→ Writes working code using generic patterns
Week 4: @Coda add a new endpoint for exporting invoices
→ Follows your service layer conventions, uses your team's
error handling pattern, matches your naming style, adds
the same logging your other export endpoints use
Coda's learning is powered by Agno's Learning Machines.
- Auto-merge. Coda opens PRs. A human merges them.
- Touch your main branch. All code work happens in isolated worktrees.
- Send code outside your environment. Coda runs in your infrastructure. Your code stays on your machines. The only external calls are to your configured LLM provider.
Slack → Coda (Team Leader, Coordinate)
├─ Coder Agent
│ ├─ CodingTools (read/write/edit/shell/grep/find)
│ ├─ GitTools (log/diff/blame/worktree)
│ ├─ GithubTools (PR read/create, issues)
│ └─ ReasoningTools (think/analyze)
├─ Explorer Agent
│ ├─ CodingTools (read-only: read/grep/find/ls)
│ ├─ GitTools (log/diff/blame/show)
│ ├─ GithubTools (PR read/review, code search)
│ └─ ReasoningTools (think/analyze)
├─ Planner Agent
│ ├─ CodingTools (read-only: read/grep/find/ls)
│ ├─ GitTools (log/diff/blame/show)
│ ├─ GithubTools (issues: create/label/search)
│ └─ ReasoningTools (think/analyze)
├─ Researcher Agent
│ ├─ ParallelTools (web search/extract)
│ └─ ReasoningTools (think/analyze)
├─ Triager Agent
│ ├─ CodingTools (read-only: read/grep/find/ls)
│ ├─ GitTools (log/diff/blame/show)
│ ├─ GithubTools (issues: label/comment/close/search)
│ └─ ReasoningTools (think/analyze)
├─ SlackTools (notifications, leader only)
├─ LearningMachine (conventions/patterns, shared)
└─ Agentic Memory (user context, leader only)
# Create and activate virtual environment
./scripts/venv_setup.sh
source .venv/bin/activate
# Start database
docker compose up -d coda-db
# Run CLI
python -m coda
# Run evals
python -m evals.run --category security
# Format & lint
./scripts/format.sh
./scripts/validate.sh| Variable | Required | Description |
|---|---|---|
OPENAI_API_KEY |
Yes | OpenAI API key |
GITHUB_ACCESS_TOKEN |
Yes | Fine-grained PAT (setup guide) |
SLACK_TOKEN |
No | Slack bot token (setup guide) |
SLACK_SIGNING_SECRET |
No | Slack request verification |
DB_HOST |
No | PostgreSQL host (default: localhost) |
DB_PORT |
No | PostgreSQL port (default: 5432) |
DB_USER |
No | PostgreSQL user (default: ai) |
DB_PASS |
No | PostgreSQL password (default: ai) |
DB_DATABASE |
No | PostgreSQL database (default: ai) |
PARALLEL_API_KEY |
No | Parallel API key for web research (parallel.ai) |
REPOS_DIR |
No | Path to cloned repos (default: /repos) |
TRIAGE_CHANNEL |
No | Slack channel ID for daily issue triage |
DIGEST_CHANNEL |
No | Slack channel ID for daily activity digest |
JWT_VERIFICATION_KEY |
Production | RBAC public key from os.agno.com |
Production deployments require authentication via Agno AgentOS. This is enforced automatically — Coda enables RBAC authorization when RUNTIME_ENV=prd (the default). Without a valid JWT_VERIFICATION_KEY, production endpoints will reject all requests.
Local development (RUNTIME_ENV=dev, set by Docker Compose) runs without auth so you can iterate freely.
- Deploy Coda to your cloud provider (step 7 above)
- Open os.agno.com and connect your deployed OS
- Go to Settings and generate a key pair
- Add the public key to your
.env(paste the full PEM block, no quotes needed):
JWT_VERIFICATION_KEY=-----BEGIN PUBLIC KEY-----
MIIBIjANBgkq...
-----END PUBLIC KEY------ Push to production and redeploy:
./scripts/railway_env.sh
./scripts/railway_redeploy.shThe Agno control plane handles JWT issuance, session management, traces, metrics, and the web UI. See the AgentOS Security docs for details.
If Coda is already deployed (e.g. on Railway), you can run a second instance locally for development. The key constraint is that each Slack app can only deliver events to one URL, so you need a separate Slack app for local.
Follow the same steps in docs/SLACK_CONNECT.md, but create a new app (e.g. "Coda Dev") in your workspace. You'll get a separate bot token and signing secret.
cp .env .env.localEdit .env.local and replace the Slack credentials with the ones from your "Coda Dev" app:
# .env.local — local development
SLACK_TOKEN=xoxb-***-dev-token
SLACK_SIGNING_SECRET=***-dev-secret
# These can stay the same as production
OPENAI_API_KEY=sk-***
GITHUB_ACCESS_TOKEN=github_pat_***Slack needs a public URL to send events to. Use ngrok:
ngrok http 8000Copy the https://...ngrok.io URL. In your "Coda Dev" Slack app settings, set the Request URL to:
https://<your-id>.ngrok-free.app/slack/events
docker compose --env-file .env.local up -d --buildYour production instance on Railway continues to run with .env and the production Slack app. Your local instance runs with .env.local and the dev Slack app. Both work independently.
Tip: Add
.env.localto.gitignoreif it isn't already. Never commit either env file.
Built on Agno · the runtime for agentic software