Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
249 changes: 56 additions & 193 deletions AGENTS.md

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions docs/deploying.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Deploying

**Deploys are manual.** Run `npm run deploy:safe` locally after merging to `main` — it builds, deploys, then runs `scripts/post-deploy-smoke.sh` against the deployed Worker. The probe asserts:

- `/health` and `/version.json` (deployed commit equals HEAD)
- codemode `execute` round-trips through `globalOutbound`
- a real `git clone` lands in the workspace

Use plain `npm run deploy` only when you intentionally want to skip the probe (e.g. you're about to run it manually with extra args).

## Why CI deploys are disabled

Workers Builds CI is off because the `"experimental"` compat flag (required by `@cloudflare/think` and the Agents SDK `subAgent()` facet API) blocks non-local deploys by design — see [issue #46](https://github.com/jonnyparris/dodo/issues/46). When Think graduates out of experimental, this can be re-enabled.

PR validation runs via `.github/workflows/dodo-verify.yml` (typecheck + test) instead of a deploy.
57 changes: 57 additions & 0 deletions docs/file-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# File Map

Source layout. `src/index.ts` is the entry point; everything else hangs off the DOs it routes to.

## Entry & routing

- `src/index.ts` — Worker router (Hono), all HTTP routes, auth middleware, session fork, admin routes
- `src/auth.ts` — Cloudflare Access JWT verification, user allowlist check, admin guard
- `src/rpc-api.ts` / `src/rpc-transport.ts` — JSON-RPC API surface and transport
- `src/share.ts` — session sharing (tokens, permissions, cookies)
- `src/onboarding.ts` — guided passkey and secrets setup

## Agent core

- `src/coding-agent.ts` — per-session agent DO (extends Think, chat via Think.chat(), fibers, workspace, git, cron, prompts, snapshots, SSE). **Contains the system prompt.**
- `src/think-adapter.ts` — Think integration boundary: re-exports, types (DodoConfig, MessageMetadata, SnapshotV2), adapter functions
- `src/agentic.ts` — LLM provider construction (buildProvider), tool composition (buildToolsForThink), git tools
- `src/executor.ts` — DynamicWorkerExecutor wrapper for sandboxed code execution (direct API route)
- `src/typecheck.ts` — in-isolate `tsc --noEmit` tool
- `src/presence.ts` — WebSocket presence tracking

## Per-user / global state

- `src/user-control.ts` — per-user DO (config, sessions, memory, tasks, skills, key envelope, encrypted secrets, fork snapshots)
- `src/shared-index.ts` — global singleton DO (user allowlist, host allowlist, models cache, session shares/permissions)
- `src/crypto.ts` — hybrid envelope encryption (PBKDF2 + HKDF + AES-GCM) for per-user secrets
- `src/rate-limit.ts` — per-user rate limiting

## Skills

- `src/skill-registry.ts` — Claude/OpenCode-compatible SKILL.md loader (parser, manifest renderer, workspace scanner, R2 asset helpers)
- `src/builtin-skills.ts` — built-in SKILL.md content shipped with Dodo

## Git, MCP, outbound

- `src/git.ts` — git helpers via @cloudflare/shell, multi-host token injection (GitHub + GitLab)
- `src/repos.ts` — known repository registry for orchestration
- `src/mcp.ts` — MCP server exposing all Dodo capabilities as tools
- `src/mcp-codemode.ts` — code-mode MCP endpoint (2 tools, minimal context)
- `src/mcp-gatekeeper.ts` — MCP server auth and rate limiting
- `src/mcp-catalog.ts` — curated catalog of recommended MCP servers
- `src/outbound.ts` — AllowlistOutbound WorkerEntrypoint for gated sandbox fetch
- `src/notify.ts` — push notifications via ntfy.sh (per-user topic from encrypted secrets)

## Plumbing

- `src/sql-helpers.ts` — lightweight SQLite query helpers
- `src/health-check.ts` — health endpoint handler
- `src/logger.ts` — structured logging helpers
- `src/types.ts` — shared TypeScript types

## Tests & UI

- `test/dodo.test.ts` — integration tests via vitest-pool-workers
- `public/index.html` — three-panel web UI (mobile-responsive)
- `public/docs.html` — architecture documentation page
- `public/howto.html` — task-oriented how-to guides
10 changes: 10 additions & 0 deletions docs/linting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Linting

Two layers:

1. **In-isolate** — the `typecheck` tool with `extraStrict: true`. Catches unused locals/parameters, missing returns, and switch fall-through via TypeScript's own diagnostics. No extra bundle cost, sub-second feedback inside a session.
2. **External (CI)** — Biome runs in `.github/workflows/dodo-verify.yml` for every PR and dispatched verify run. Catches the wider set: unused imports, suspicious patterns, double-equals, etc. Configured in `biome.jsonc` (correctness + suspicious rules only — formatting and style are intentionally off).

**Why two layers:** Biome's wasm bundle is ~8 MB gzipped, which would push Dodo past the Workers 10 MB compressed script limit if loaded in-isolate. The in-isolate check is the agent's fast feedback loop; the CI check is the thorough gate before merge.

Run `npm run lint` locally before pushing if you want the same signal CI will give you. `npm run lint:fix` applies safe auto-fixes.
25 changes: 25 additions & 0 deletions docs/skills.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Skills

Dodo supports SKILL.md files compatible with both Claude Code and OpenCode. Three sources merged into one deduplicated list (precedence: personal > workspace > builtin):

1. **Personal** — per-user, stored in UserControl DO SQLite. Created via the `skill_write` MCP tool or `POST /api/skills`. Bundled assets live in R2 under `skills/{userId}/{skillName}/...`.
2. **Workspace** — scanned from the cloned repo's `.dodo/skills/`, `.claude/skills/`, `.agents/skills/`, `.opencode/skill/`, `.opencode/skills/` directories. Read-only — promote to personal to edit.
3. **Builtin** — shipped with Dodo via `src/builtin-skills.ts`.

## Loading model

Two-stage progressive disclosure (matches Claude Code / OpenCode):

- **Session start:** `getSystemPrompt()` injects `<available_skills>` with name + description per enabled skill (~150 tokens each, capped at 4 KB total).
- **On demand:** the `skill` tool returns the full SKILL.md body and a sampled list of bundled file paths. Bundled files are NOT auto-loaded — the model uses `read` to fetch.

## MCP tools

- `skill_list` — list personal skills
- `skill_read` — get full body of a personal skill
- `skill_write` — create/update a personal skill
- `skill_enable` — toggle enabled flag
- `skill_delete` — remove a personal skill
- `skill_import_url` — fetch a SKILL.md from a URL and store it as personal

Workspace and built-in skills are visible from inside the chat (via the `skill` tool) but cannot be modified through the MCP CRUD surface. To edit a workspace skill, copy its body into a personal skill via `skill_write`.
63 changes: 63 additions & 0 deletions docs/system-prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# System Prompt Design

The system prompt lives in `src/coding-agent.ts` as `const SYSTEM_PROMPT`. It's a static string — not dynamically assembled from config or user preferences. The `CodingAgent` class returns it via `getSystemPrompt()`.

## Design principles

**Teach the tools, not the model.** The prompt documents what tools exist and when to use each one. It doesn't teach the model how to code — that's what the model already knows. The prompt bridges the gap between the model's general capabilities and Dodo's specific tool surface.

**Match reality.** Every tool mentioned in the prompt must actually exist. Every constraint mentioned (30s timeout, 10-step limit, sandboxed network) must be accurate. The prompt is a contract with the model.

**Concise over exhaustive.** A Sonnet-class model doesn't need 1500 lines of instruction. Cover identity, tool surface, key behaviors, safety rules, and limits. Trust the model for everything else.

**No sycophancy instructions.** The model should be direct and technically accurate. No "Great question!" or "I'd be happy to help." Focus on the work.

## Sections

| Section | Purpose |
|---------|---------|
| Identity | "You are Dodo" — establishes the agent's name and platform |
| Tone and style | Concise, markdown, no emojis, prefer edits over new files |
| Doing tasks | Todo discipline: explicit lists of task shapes that always need todos (cloned-repo work, multi-file edits, review/audit/investigate tasks) vs. shapes that can skip them; post-compaction `todo_list` re-grounding hint; when to delegate with `task` |
| Workspace tools | Documents read_file, write_file, search_files, replace_in_file |
| Code execution | Documents codemode: sandboxed JS, fetch with auto-auth, 30s timeout |
| Git | Documents all git tools, auto-auth for GitHub/GitLab |
| Git safety | Stage specific files, clear commit messages, no force-push |
| Working with errors | State what failed, fix it, move on |
| Limits | 10-step cap, ephemeral workspace, no shell |

## Changing the prompt

When modifying the system prompt:

1. Keep it factual. If you add a section about a tool, verify the tool exists in `buildToolsForThink()`.
2. Test with real prompts. The prompt shapes every interaction — small wording changes can have outsized effects on behavior.
3. Don't duplicate tool descriptions. The AI SDK sends tool schemas automatically. The prompt should explain *when* and *why* to use tools, not re-document their parameters.
4. The max steps limit (10) is set in `getMaxSteps()` on the `CodingAgent` class. If you change it, update the prompt too.

## Tool surface

These tools are available to the agent at runtime (built in `src/agentic.ts`):

**Workspace tools** (from `@cloudflare/think/tools/workspace`):
- `read_file` — read file contents
- `write_file` — create or overwrite a file
- `search_files` — glob + content search
- `replace_in_file` — find-and-replace within a file

**Git tools** (built in `buildGitTools()`):
- **Top-level (hot path):** `git_status`, `git_add`, `git_commit`, `git_diff`
- **Inside codemode only (call as `git.<name>`):** `git_clone_known`, `git_clone`, `git_push`, `git_push_checked`, `git_pull`, `git_branch`, `git_checkout`, `git_log`, `git_verify_remote_branch`, `pr_create`

The lower-frequency git tools are reachable via codemode's `git` provider namespace rather than as individual top-level tools. This saves roughly 1k tokens of tool-schema budget per turn without losing any capability — see `buildTools()` in `src/agentic.ts` for the split.

**Code execution** (from `@cloudflare/think/tools/execute`):
- `codemode` — sandboxed JS execution with workspace filesystem and git access, gated outbound fetch

**Typecheck** (from `src/typecheck.ts`):
- `typecheck` — runs `tsc --noEmit` against the workspace inside the CodingAgent DO. Bundles `typescript` and every `lib.*.d.ts` into the Worker so the check happens without a subprocess. Honours user `tsconfig.json`; refuses oversized projects (> 50 .ts/.tsx files or > 5 MB) with a structured `skipped` payload. Pass `extraStrict: true` to layer `noUnusedLocals` + `noUnusedParameters` + `noImplicitReturns` + `noFallthroughCasesInSwitch` on top of the user's tsconfig — a cheap stand-in for a real linter at zero extra bundle cost. Lib map (`src/typecheck-libs.generated.ts`) is checked in and regenerated by `scripts/generate-typecheck-libs.mjs` during `npm run build`. Manual validation: `npm run test:typecheck-smoke`.

**Skill loader** (`src/skill-registry.ts`):
- `skill` — load a SKILL.md body on demand. The system prompt's `<available_skills>` block lists name + description per skill; this tool returns the full body when the model picks one. Two-stage progressive disclosure mirrors Claude Code / OpenCode.

The hot-path tools (workspace primitives, the four top-level git tools, `codemode`, the subagent tools, and `skill`) are top-level. The rest of the git surface is exposed only through codemode's provider namespaces.
Loading