Skip to content
This repository was archived by the owner on Sep 22, 2026. It is now read-only.
Closed
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
227 changes: 227 additions & 0 deletions articles/20260920_omni_and_claude_engineers_inside_daytona.md
Original file line number Diff line number Diff line change
@@ -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 <repo> --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/<your-user>/omni-engineer --code
daytona create https://github.com/<your-user>/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 <workspace>` 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added authors/assets/notdev-ng-company-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added authors/assets/notdev-ng-company-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added authors/assets/notdev-ng.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions authors/notdev_ng.md
Original file line number Diff line number Diff line change
@@ -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)
35 changes: 35 additions & 0 deletions definitions/20260920_definition_ai_coding_agent.md
Original file line number Diff line number Diff line change
@@ -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.