diff --git a/articles/20260920_omni_and_claude_engineers_inside_daytona.md b/articles/20260920_omni_and_claude_engineers_inside_daytona.md new file mode 100644 index 00000000..74dde30a --- /dev/null +++ b/articles/20260920_omni_and_claude_engineers_inside_daytona.md @@ -0,0 +1,227 @@ +--- +title: 'Omni and Claude Engineers Inside Daytona' +description: + 'Run Omni Engineer and Claude Engineer inside isolated Daytona workspaces + with dev containers — setup, API keys, and a real modernization sprint.' +date: 2026-09-20 +author: 'Notdev Ng' +tags: ['ai engineer', 'devcontainers', 'daytona', 'claude', 'openrouter'] +--- + +# Omni and Claude Engineers Inside Daytona + +# Introduction + +AI coding assistants have quietly split into two philosophies. One camp gives +you a fast console where you stay in charge — you add files to context, ask for +edits, and approve every diff. The other camp gives the model a toolbox and +lets it build its own workflow, even writing new tools when the job demands +one. [Omni Engineer](https://github.com/Doriandarko/omni-engineer) and +[Claude Engineer](https://github.com/Doriandarko/claude-engineer) are compact, +open-source examples of each philosophy — and both are a `daytona create` away +from running in an isolated workspace instead of on your machine. + +That isolation matters more than it sounds. These tools can read and write +files, run web searches, and execute the code they help you produce. Running +them inside a Daytona [workspace](https://www.daytona.io/definitions/d/daytona-workspace) +puts a container boundary around all of it: the agent gets a clean checkout of +your project, your host filesystem stays untouched, and the whole experiment +disappears with `daytona delete`. This article walks through adding a dev +container to each repository, launching both engineers in Daytona, and putting +them to work on one concrete task: modernizing a small legacy codebase. + +## TL;DR + +- Omni Engineer is a model-agnostic console client (OpenRouter) for + interactive, file-aware AI assistance; Claude Engineer is a self-extending + Claude agent with CLI and web interfaces. +- A minimal `devcontainer.json` per repo installs dependencies and passes API + keys through from your host environment — no secrets in the image. +- `daytona create --code` builds each workspace; each tool runs inside + its own container. +- The article's worked example pairs the two on a modernization sprint: Omni + Engineer audits a legacy module and drafts the migration plan, Claude + Engineer executes one slice and verifies it. + +## The Two Tools, Briefly + +Both projects come from the same author and share DNA, but they optimize for +different workflows: + +| | Omni Engineer | Claude Engineer | +| --- | --- | --- | +| Interface | Terminal console (`python main.py`) | CLI (`ce3.py`) or web UI on port 5000 | +| Models | Any model on OpenRouter, switchable mid-session | Anthropic Claude | +| Signature skill | Explicit commands: `/add`, `/edit`, `/new`, `/undo`, `/diff`, `/search`, `/image` | Generates and manages its own tools as it works | +| API key | `OPENROUTER_API_KEY` | `ANTHROPIC_API_KEY` (optional `E2B_API_KEY` for code execution) | +| Dependencies | `requirements.txt` | `pyproject.toml` + `uv.lock`, managed with `uv` | + +Think of Omni Engineer as the interactive instrument — you steer file by file — +and Claude Engineer as the autonomous one you point at a goal. Both are useful +inside the same sprint, which is exactly how the example below uses them. + +## Step 1: Add Dev Containers to the Repositories + +Neither upstream repository ships a dev container, so the first contribution +is a minimal `.devcontainer/devcontainer.json` for each. The files were +contributed upstream as pull requests +([omni-engineer#49](https://github.com/Doriandarko/omni-engineer/pull/49), +[claude-engineer#275](https://github.com/Doriandarko/claude-engineer/pull/275)); +until they merge you can copy them verbatim into your own forks. + +**Omni Engineer** — `.devcontainer/devcontainer.json`: + +```json +{ + "name": "Omni Engineer", + "image": "mcr.microsoft.com/devcontainers/python:3.11", + "postCreateCommand": "pip install -r requirements.txt", + "containerEnv": { + "OPENROUTER_API_KEY": "${localEnv:OPENROUTER_API_KEY}" + }, + "remoteUser": "vscode" +} +``` + +**Claude Engineer** — `.devcontainer/devcontainer.json`: + +```json +{ + "name": "Claude Engineer", + "image": "mcr.microsoft.com/devcontainers/python:3.11", + "postCreateCommand": "python -m pip install uv && uv sync", + "containerEnv": { + "ANTHROPIC_API_KEY": "${localEnv:ANTHROPIC_API_KEY}", + "E2B_API_KEY": "${localEnv:E2B_API_KEY}" + }, + "forwardPorts": [5000], + "remoteUser": "vscode" +} +``` + +The pattern worth noticing is `containerEnv` with `${localEnv:...}`: it copies +a variable from your host into the container at create time, so the image and +repository stay free of secrets while the tool inside still finds its key. +Claude Engineer's entry also forwards port 5000 for the optional web UI, and +uses `uv sync` so dependencies resolve from the committed lockfile — the same +reproducibility the project expects locally, now inside the container. + +Export the keys before creating workspaces: + +```bash +export OPENROUTER_API_KEY="sk-or-..." +export ANTHROPIC_API_KEY="sk-ant-..." +``` + +## Step 2: Create the Daytona Workspaces + +With the dev containers in place on your forks, each workspace is one command: + +```bash +daytona create https://github.com//omni-engineer --code +daytona create https://github.com//claude-engineer --code +``` + +Daytona detects `.devcontainer/devcontainer.json`, builds the image, runs +`postCreateCommand`, and injects the environment variables. The `--code` flag +opens your IDE attached to the container. If you prefer the raw terminal, +`daytona ssh ` drops you into the same environment. + +Verify each workspace before the real work: + +```bash +# Inside the Omni Engineer workspace +python main.py --help 2>/dev/null || python -c "import openai, rich; print('deps ok')" + +# Inside the Claude Engineer workspace +uv run python -c "import anthropic; print('deps ok')" +``` + +If `OPENROUTER_API_KEY` was set on your host, Omni Engineer's console starts +immediately — there is no other configuration. Claude Engineer similarly reads +`.env` or the injected environment; `E2B_API_KEY` is only needed if you want +its cloud code-execution sandbox. + +## Step 3: A Real Task — A Modernization Sprint + +Screenshots of "hello world" prompts prove nothing, so here is the example the +article uses end to end: a legacy `reportgen/` package that still uses +`%`-formatting, `os.path` string surgery, and prints instead of logging. The +goal is a Python 3.11-ready module — f-strings, `pathlib`, `logging`, and a +passing smoke test — inside a third, shared workspace containing the project. + +**Audit with Omni Engineer.** In the Omni workspace, pull the project files +into context and ask for a plan: + +``` +/add reportgen/ +Review this module for Python 3.11 modernization. List concrete issues, +then produce a step-by-step migration plan ordered by risk. +``` + +Omni Engineer streams a review, and `/diff` shows proposed edits before you +accept them; `/undo` reverts anything that overreaches. Because it is a +console, you stay in the loop for every file — the right tool for the audit +phase, where judgment matters more than speed. `/save` persists the session so +the plan can be reloaded or handed off. + +**Execute with Claude Engineer.** In the Claude Engineer workspace, give the +agent the plan and one slice of it: + +``` +Read reportgen/io_utils.py. Apply step 2 of this plan: replace os.path +usage with pathlib, keep the public API identical, and add a unittest +that covers read_report(). Then run the test. +``` + +Claude Engineer decomposes the request, and — the interesting part — if it +decides it needs a capability it does not have, it writes a new tool and adds +it to `tools/` mid-conversation. You watch the tool calls stream by in the CLI +(or the web UI on the forwarded port 5000) and end with a modified file plus a +test run, not just advice. `/reset`-style boundaries between slices keep each +change reviewable. + +**Ship one diff.** Back in the project workspace, run the project's own checks +and `git diff`. The sprint produces a single reviewable changeset: an audit +trail from Omni Engineer and an implementation from Claude Engineer, both run +in containers that never touched your host. + +![Omni and Claude Engineers running in Daytona workspaces](assets/20260920_omni_and_claude_engineers_inside_daytona_img1.png) + +## Practical Tips and Pitfalls + +- **One tool per workspace.** Running both agents against the same checkout in + one container invites edit conflicts; separate workspaces make the boundary + explicit and let you discard one cleanly. +- **Budget context deliberately.** Omni Engineer's `/add` pulls whole files + into context — for large repos, add only the module under review or switch + models with `/change_model` to one with a bigger window. +- **Keep secrets out of the image.** The `${localEnv:...}` passthrough means + rotating a key is a host-side `export` — the devcontainer never stores it. +- **Web UI access.** Claude Engineer's `app.py` serves on port 5000; with the + forwarded port you reach it at `localhost:5000` when the workspace runs + locally, or through Daytona's port forwarding on remote targets. +- **PyAutoGUI note.** Claude Engineer's dependency list includes `pyautogui` + for desktop automation; in a headless container it installs fine, but + mouse/keyboard tools simply have nothing to drive — stick to its file and + code tools. + +## Conclusion + +The devcontainer contribution is a few dozen lines of JSON, but it turns two +fascinating AI-engineer projects into disposable, reproducible environments: +`daytona create`, export a key, work. Omni Engineer gives you a steering wheel; +Claude Engineer gives you an autopilot — and Daytona gives both a sandbox where +"let the agent try it" carries no risk to the rest of your machine. + +## References + +- [Omni Engineer](https://github.com/Doriandarko/omni-engineer) — the + OpenRouter-based console client +- [Claude Engineer](https://github.com/Doriandarko/claude-engineer) — the + self-improving Claude agent (CLI and web UI) +- [Daytona documentation](https://www.daytona.io/docs) — workspace creation and + dev container support +- [Dev Containers specification](https://containers.dev/) — `devcontainer.json` + reference for `containerEnv`, `postCreateCommand`, and port forwarding +- [OpenRouter](https://openrouter.ai/) — model access for Omni Engineer diff --git a/articles/assets/20260920_omni_and_claude_engineers_inside_daytona_img1.png b/articles/assets/20260920_omni_and_claude_engineers_inside_daytona_img1.png new file mode 100644 index 00000000..88b88434 Binary files /dev/null and b/articles/assets/20260920_omni_and_claude_engineers_inside_daytona_img1.png differ diff --git a/authors/assets/notdev-ng-company-dark.png b/authors/assets/notdev-ng-company-dark.png new file mode 100644 index 00000000..13677bff Binary files /dev/null and b/authors/assets/notdev-ng-company-dark.png differ diff --git a/authors/assets/notdev-ng-company-white.png b/authors/assets/notdev-ng-company-white.png new file mode 100644 index 00000000..12b794d6 Binary files /dev/null and b/authors/assets/notdev-ng-company-white.png differ diff --git a/authors/assets/notdev-ng.jpg b/authors/assets/notdev-ng.jpg new file mode 100644 index 00000000..d1fe13a2 Binary files /dev/null and b/authors/assets/notdev-ng.jpg differ diff --git a/authors/notdev_ng.md b/authors/notdev_ng.md new file mode 100644 index 00000000..4a3b3394 --- /dev/null +++ b/authors/notdev_ng.md @@ -0,0 +1,15 @@ +Author: Notdev Ng +Title: Software Engineer +Description: Notdev Ng is a software engineer focused on developer tooling, +reproducible development environments, and applied AI workflows. He writes +practical guides that help teams turn messy local setups into containers anyone +can run, and he contributes to open-source projects around developer +experience. +Author Image: ![notdev-ng](./assets/notdev-ng.jpg) +Author LinkedIn: [LinkedIn](https://www.linkedin.com/in/notdevng) +Author Twitter: [Twitter](https://twitter.com/notdevng) +Company Name: Codiev +Company Description: Codiev builds AI-assisted development tools that help +engineers turn ideas into working software faster. +Company Logo Dark: ![company-logo dark](./assets/notdev-ng-company-dark.png) +Company Logo White: ![company-logo white](./assets/notdev-ng-company-white.png) diff --git a/definitions/20260920_definition_ai_coding_agent.md b/definitions/20260920_definition_ai_coding_agent.md new file mode 100644 index 00000000..337a9258 --- /dev/null +++ b/definitions/20260920_definition_ai_coding_agent.md @@ -0,0 +1,35 @@ +--- +title: 'AI Coding Agent' +description: + 'An AI coding agent is a development assistant that goes beyond answering + questions: it reads and edits files, runs commands, and can build its own + tools inside a controlled environment.' +date: 2026-09-20 +author: 'Notdev Ng' +--- + +# AI Coding Agent + +## Definition + +An AI coding agent is a software assistant driven by a large language model +that performs development tasks autonomously or semi-autonomously. Unlike a +plain chat interface, an AI coding agent can act on a project: reading files, +writing and editing code, running shell commands and tests, and iterating on +its own output until a goal is met. Some agents follow fixed tool sets, while +others — like Claude Engineer — can create new tools for themselves at runtime. + +## Context and Usage + +AI coding agents are used for bug reproduction, refactoring, codebase +exploration, test generation, and maintenance sprints. Because they can modify +files and execute code, sandboxing matters: running an agent inside a dev +container or a Daytona workspace confines its changes to a disposable +environment and keeps API keys and host filesystems out of reach. + +Practical concerns when using one include the size of its context window, +which tools it is permitted to call, whether every change is reviewable (diff +display, undo, per-step approval), and cost per task. The agent is most +effective when the task is concrete and verifiable — "make this failing test +pass" beats "improve the codebase" — and when its output lands as a single +reviewable diff.