Manage coding agents inside cloud development environments connected to your repositories
Fully open source under the MIT License.
Instead of editing code locally or inside restricted LLM sandboxes, Eva provisions full development environments where agents can:
β’ run shell commands β’ install dependencies β’ execute tests β’ build and preview apps β’ open pull requests
GitHub Repository
β
Eva
β
Cloud Sandbox (Daytona)
β
AI Agent (Claude, Codex, opencode, Cursor)
β
Code Changes β Diff β Pull Request β Preview
- Connect your GitHub repository
- Build a sandbox snapshot with your dependencies
- Run a task (e.g. βfix failing testsβ)
- Review the diff and open a pull request
Describe a bug or change and Eva spins up an isolated sandbox to execute it. Tasks run independently so you can launch multiple in parallel.
Persistent cloud development environments with live previews where you and the agent collaborate in real time.
Structured workflows for larger changes. Agents can plan, implement, and verify features across your codebase.
Store PRDs, specs, and context that the agent references during tasks. Keep your requirements close to the work.
Run your test suite in sandboxes automatically. Validate changes before they land without tying up local resources.
Access your connected databases (Convex, Supabase) directly from Claude. Query, inspect, and debug your data without leaving your AI workflow.
Frontend: Vite, TanStack Router, React, Tailwind CSS** Backend**: Convex** Sandboxes**: Daytona SDK** Auth**: Clerk
| App | Description |
|---|---|
apps/web |
|
| Main dashboard for managing repos, tasks, and sessions | |
apps/chrome-extension |
|
| Browser extension for quick task execution |
Eva is self-hosted - there is no managed cloud version. You create your own Convex deployment, set up your own Clerk project, and run the app yourself. This gives you full control over your data and infrastructure.
- Node.js 20+
- pnpm
- Convex account
- Clerk account
- Daytona account
- GitHub account (for GitHub App)
git clone https://github.com/your-org/eva.git
cd eva
pnpm install
npx convex dev
Follow the prompts to create or link a Convex project. Note your deployment URL (e.g. https://your-deployment.convex.cloud
).
- Create a Clerk application at
clerk.com - Note your
Publishable Key(starts with
pk_
) - Note your
JWT Issuer Domain from Clerk Dashboard β JWT Templates (e.g.https://your-app.clerk.accounts.dev
)
Go to
GitHub Settings β Developer settings β GitHub Apps β New GitHub App - Configure:
Name:Eva (your-org)
Homepage URL: your Eva instance URL** Webhook URL**:https://your-deployment.convex.site/api/github/webhook
Webhook secret: generate a random string (save forGITHUB_WEBHOOK_SECRET
)
Repository permissions:- Contents: Read & write
-
Pull requests: Read & write
-
Issues: Read & write
-
Metadata: Read-only
Subscribe to events: Push, Pull request, Installation - Click
Create GitHub App - After creation, note:
App IDβGITHUB_APP_ID
Client IDβGITHUB_CLIENT_ID
App slug(from the public URLgithub.com/apps/<slug>
) βGITHUB_APP_SLUG
Generate:
Client secretβGITHUB_CLIENT_SECRET
Private key(.pem file) βGITHUB_PRIVATE_KEY
Install the app on your account/org - Look up the App's bot user ID β this is used as the git commit author email so commits are attributed to the bot on GitHub (App IDs and bot user IDs live in different namespaces):
curl -s https://api.github.com/users/<slug>\[bot\] | jq .id
openssl rand -hex 32
openssl rand -hex 32
openssl ecparam -genkey -name prime256v1 -noout -out private.pem
openssl ec -in private.pem -pubout -out public.pem
VITE_CONVEX_URL=https://your-deployment.convex.cloud
VITE_CLERK_PUBLISHABLE_KEY=pk_test_...
Required:
| Variable | Value |
|---|---|
CLERK_JWT_ISSUER_DOMAIN |
|
https://your-app.clerk.accounts.dev |
|
ENCRYPTION_KEY |
|
| 64-char hex string from Step 5 | |
EVA_DEPLOY_KEY |
|
| 64-char hex string from Step 5 | |
GITHUB_APP_ID |
|
| App ID from GitHub App | |
GITHUB_APP_SLUG |
|
App slug from github.com/apps/<slug> |
|
GITHUB_BOT_USER_ID |
|
| Numeric bot user ID (from Step 4 lookup) | |
GITHUB_CLIENT_ID |
|
| Client ID from GitHub App | |
GITHUB_CLIENT_SECRET |
|
| Client secret from GitHub App | |
GITHUB_PRIVATE_KEY |
|
Full contents of .pem file |
|
GITHUB_WEBHOOK_SECRET |
|
| Random string from Step 4 |
Optional:
| Variable | Purpose |
|---|---|
SANDBOX_JWT_PRIVATE_KEY |
|
| ES256 JWK for sandbox auth (JSON) | |
SANDBOX_JWT_JWKS |
|
| Public JWKS for sandbox auth (JSON) | |
MCP_BOOTSTRAP_SECRET |
|
| Secret for MCP bootstrap API | |
MCP_JWT_SECRET |
|
| Secret for MCP JWT signing | |
CLERK_SECRET_KEY |
|
| Clerk secret key (for MCP server) | |
CLERK_PUBLISHABLE_KEY |
|
| Clerk publishable key (for MCP server) |
Git default branch (not an env var): When a task has no baseBranch
and the repo has no Default base branch (Eva Settings β Config), sandboxes and PRs use staging
(FALLBACK_GIT_BASE_BRANCH
in @conductor/shared
). Team/repo env vars apply inside sandboxes only; they do not set the PR merge base.
The Daytona API key is stored as a team or repo env var in the dashboard (not as a Convex deployment env var).
- Get your API key from
Daytona - In Eva dashboard, go to
Team Settings β Environment Variables - Add
DAYTONA_API_KEY
with your key
npx convex dev
pnpm dev
Open http://localhost:5173
Eva supports Convex and Supabase MCP connections. To add these, add your Convex URL and Supabase URL to the repo or team environment variables in the dashboard.
Eva runs agents inside Daytona sandboxes that boot from pre-built snapshots. Snapshots bundle the OS, system tooling, agent CLIs, your dependencies, and a clone of your repo so sandboxes start fast.
Eva builds snapshots itself from the backend β no GitHub Actions workflow is involved. When a build is triggered, packages/backend/convex/snapshotActions.ts
(buildSnapshotImage
):
-
Defines a Daytona image with all required tooling (see the list below)
-
Clones your repo at the configured branch using a GitHub installation token, then runs
pnpm install -
Runs any custom build commands you have configured
-
Pushes the built image to Daytona as a named snapshot, then warms Daytona's cache so the first sandbox starts fast
DAYTONA_API_KEY
is read from your team or repo environment variables (see Step 7) β not from a GitHub Actions secret.
In the Eva dashboard, open your repo's Settings β Snapshots:
Configurationβ set the snapshot name, the branch to clone (** Workflow Branch**, defaults tomain
), a rebuildSchedule(a cron expression ormanual
), andBuild Commands that run afterpnpm install
.Statusβ click** Rebuild Nowto trigger a build on demand. Builds**β watch progress and read build logs.** Config Files**β upload files (e.g. database seeds) to bake into the image.
If a snapshot is missing or in an error state, sandbox creation falls back to a default Daytona snapshot plus a fresh git clone
, so tasks still run (slower on first setup).
- Node.js 20, pnpm, git, git-lfs, curl, jq, ripgrep, fd, gh CLI
- Chrome + Xvfb + VNC (for browser automation and desktop/preview mode)
- Docker Engine (for nested containers, e.g.
supabase start
) - Agent CLIs: Claude Code, Codex, opencode, Cursor
- agent-browser, Convex CLI, Supabase CLI, code-server (VS Code in the browser)
To change the base tooling, edit buildSnapshotImage()
in packages/backend/convex/snapshotActions.ts
. For per-project needs, prefer Build Commands and Config Files in the Snapshots settings over editing the image definition.
Rebuild your snapshot when:
- Dependencies change significantly (new major packages)
- You update the base tooling (Node.js version, system packages)
- You want sandboxes to start with a fresher copy of the codebase
Your codebase needs the agent-browser
skill installed for screenshots or video walkthroughs to be captured.
You may face authentication issues in the preview URL if your auth provider blocks frame ancestors (e.g. AuthKit does this for security). Options:
Open in a new tabβ simplest fix.** Add the Daytona domainto your auth provider's allowlist and callback URLs, then use the preview URL directly. Implement backend auth**β if you want the iframe to work, implement a separate login page that doesn't make network requests to your auth provider (e.g. AuthKit), so it renders inside the iframe. Add instructions to yourCLAUDE.md
so the agent knows how to use this flow withagent-browser
.
This restriction is not unique to Eva β it's a standard iframe security limitation.
- Testing arena for running and comparing agent strategies
- Improved project interview UI/UX