Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Created by https://www.toptal.com/developers/gitignore/api/node
# Edit at https://www.toptal.com/developers/gitignore?templates=node

.claude/
*.bak

### Node ###
Expand Down
234 changes: 25 additions & 209 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,209 +1,25 @@
This file provides guidance to coding agents working in this repository.

## What This Repo Is

`deva.sh` is a Docker-based multi-agent launcher for:

- OpenAI Codex
- Claude Code
- Google Gemini CLI

The container is the sandbox. Agent-level permission theater is not.

That is the core design. Do not "improve" it by moving trust back into
interactive prompt confirmations.

## Workflow Rules

We use issue-based development.

1. Before any Git or GitHub CLI command, read the matching file in
`workflows/`:
- `GITHUB-ISSUE.md`
- `GIT-COMMIT.md`
- `GITHUB-PR.md`
- `RELEASE.md`
2. Keep one branch per issue when practical.
3. PRs should reference and close the relevant issue.

## Release Rules

Release workflow lives in `workflows/RELEASE.md`.

Current release source of truth:

- version comes from `deva.sh`
- changelog comes from `CHANGELOG.md`
- images are published by GitHub Actions

Do not use `claude.sh` as the version source. That is old baggage.

## Project Structure

```text
deva/
├── deva.sh
├── claude.sh
├── claude-yolo
├── agents/
├── Dockerfile
├── Dockerfile.rust
├── docker-entrypoint.sh
├── install.sh
├── .deva.example
├── examples/
├── docs/
├── .github/workflows/
├── workflows/
├── CHANGELOG.md
├── DEV-LOGS.md
└── AGENTS.md
```

Important current roles:

- `deva.sh`: primary entrypoint and container lifecycle manager
- `agents/*.sh`: agent-specific auth and command wiring
- `install.sh`: one-line installer
- `.github/workflows/ci.yml`: lint, docs, and smoke coverage
- `.github/workflows/release.yml`: tagged image + release flow
- `.github/workflows/nightly-images.yml`: scheduled nightly image refresh

Legacy compatibility wrappers still exist:

- `claude.sh`
- `claude-yolo`

They are compatibility shims, not primary branding.

## Security Model

Deva runs agent CLIs inside Docker and disables their built-in permission
prompts:

- Claude: `--dangerously-skip-permissions`
- Gemini: `--yolo`
- Codex: unrestricted mode equivalent

That is deliberate.

The security boundary is:

- the container
- the exact mounts and env vars we pass into it

So the real risks are the host bridges we expose:

- mounted workspace paths
- mounted auth files
- `/var/run/docker.sock`
- `--host-net`
- tmux bridge tooling

Do not document or implement this as if the agent sandbox is protecting the
host. It is not.

## Auth And Config Model

Deva supports multiple auth modes per agent.

Current design:

- default config root is `~/.config/deva`
- per-agent homes live under that root
- `--config-home` isolates auth state
- `-Q` means bare mode: no config loading, no autolink, no host auth mounts
- non-default auth overlays default credential paths instead of moving live
host files around

If you touch auth code, verify real `--dry-run` output and one live path.
Auth bugs are usually mount bugs wearing a fake auth moustache.

## Container Model

Persistent containers are keyed by workspace plus container shape.

Shape includes things like:

- selected agent
- extra volumes
- explicit config home
- auth mode

So it is not "one container per repo" in the naive sense. Different shapes
must not collide.

For clean repros and CI smoke tests, use:

```bash
deva.sh claude -Q -- --version
deva.sh codex -Q -- --version
deva.sh gemini -Q -- --version
```

Non-interactive launch paths must work without a TTY.

## Common Checks

Run these before claiming things work:

```bash
./deva.sh --help
./deva.sh --version
./claude-yolo --help
./scripts/version-check.sh
```

If you changed container launch, mounts, auth, or the installer, also run:

```bash
./deva.sh claude --debug --dry-run
./deva.sh claude -Q -- --version
./deva.sh codex -Q -- --version
./deva.sh gemini -Q -- --version
```

If you changed docs site plumbing, also run:

```bash
mkdocs build --strict
```

## Bridges

Bridges are deliberate holes from container back to host.

Current ones:

- Docker socket mount
- tmux bridge

Treat bridge changes as security-sensitive. They change the real trust
boundary, not some fake marketing boundary.

## Documentation Rules

Public copy should say `deva.sh` first.

Allowed:

- mention `claude.sh` / `claude-yolo` as compatibility wrappers
- historical notes in changelog/dev logs

Not allowed:

- presenting the project as Claude-only
- using `claude.sh` as the primary interface in current docs
- leaving stale release or workflow prompts centered on old naming

## Issue Hygiene

Do not use the issue queue as a mirror of every upstream vendor changelog.

If upstream version tracking is automated, close the old noise and keep the
real issue queue for:

- bugs in deva
- missing features in deva
- docs gaps in deva
- concrete release/process work in deva
@./.claude/CLAUDE.md
@./CLAUDE.md

<!-- deva:container-context -->
# Container Environment (deva)

You are inside a Docker container running Ubuntu Linux 24.04 LTS
(Noble Numbat), not on the host machine. The workspace is a
bind-mount from the host at the same absolute path, but the
runtime is Linux.

- This is Linux. Host-only tools (open, pbcopy, pbpaste, sw_vers,
diskutil, defaults, launchctl) are not available.
- No display server. Browsers and GUI tools will not work.
- Hard links (`ln` without -s) fail across mount boundaries.
Use `cp` or relative symbolic links (`ln -sr`).
- Prefer relative paths for project-internal references.
Absolute paths work here but are container-specific.
- $HOME is /home/deva (not /root). sudo works without password.
- Pre-installed: Node.js, Python (use `uv`, not pip), Go, git,
gh, make, curl. pip is NOT in PATH.
- Docker is available (socket mounted from host).
- System packages and build caches persist across sessions.
- Container details are in DEVA_* environment variables.
<!-- /deva:container-context -->
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.12.0] - 2026-05-27

### Added
- `deva status` command: Docker-native workspace inspection showing
containers, categorized mounts (workspace/config/bridge/user),
agent homes, and health checks. Flags: `-g` global, `--verbose`
for env vars
- Agent context injection: deva.sh writes container-awareness
instructions to `.claude/CLAUDE.md` and `AGENTS.md` before agent
start. Dynamic content (Docker socket, ephemeral mode). Replace
semantics on each startup. Sentinel markers for recovery
- `scripts/test-status-helpers.sh` (22 tests) and
`scripts/test-workspace-context.sh` (25 tests)

### Changed
- Replace atlas-cli (lroolle/atlas-cli) with ccx (thevibeworks/ccx)
as the session viewer. Binary renamed `atl` -> `ccx`. Skill
installed from `.skill` zip archive
- `deva status` replaces the old session-file-only implementation
with `docker inspect` queries for live container state

## [0.11.0] - 2026-05-22

### Added
Expand Down
10 changes: 6 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,11 @@ RUN --mount=type=cache,target=/tmp/tmux-cache,sharing=locked \
hash -r && \
tmux -V

ENV NPM_CONFIG_FETCH_RETRIES=5 \
ENV NPM_CONFIG_FETCH_RETRIES=2 \
NPM_CONFIG_FETCH_RETRY_FACTOR=2 \
NPM_CONFIG_FETCH_RETRY_MINTIMEOUT=10000
NPM_CONFIG_FETCH_RETRY_MINTIMEOUT=1000 \
NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT=10000 \
NPM_CONFIG_FETCH_TIMEOUT=30000

# Stable agent base: user, shell, and shared runtimes.
# Keep volatile agent package installs out of this stage so downstream
Expand Down Expand Up @@ -216,9 +218,9 @@ LABEL org.opencontainers.image.claude_trace_version=${CLAUDE_TRACE_VERSION}
LABEL org.opencontainers.image.codex_version=${CODEX_VERSION}
LABEL org.opencontainers.image.gemini_cli_version=${GEMINI_CLI_VERSION}

ARG ATLAS_CLI_VERSION=v0.1.4
ARG CCX_VERSION=v0.7.0

LABEL org.opencontainers.image.atlas_cli_version=${ATLAS_CLI_VERSION}
LABEL org.opencontainers.image.ccx_version=${CCX_VERSION}

COPY --chown=deva:deva scripts/install-agent-tooling.sh /tmp/install-agent-tooling.sh

Expand Down
4 changes: 2 additions & 2 deletions Dockerfile.rust
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ARG CLAUDE_CODE_VERSION=2.1.143
ARG CLAUDE_TRACE_VERSION=1.0.9
ARG CODEX_VERSION=0.131.0
ARG GEMINI_CLI_VERSION=0.42.0
ARG ATLAS_CLI_VERSION=v0.1.4
ARG CCX_VERSION=v0.7.0
ARG PLAYWRIGHT_VERSION=1.60.0
ARG RUST_TOOLCHAINS="stable"
ARG RUST_DEFAULT_TOOLCHAIN="stable"
Expand All @@ -22,7 +22,7 @@ LABEL org.opencontainers.image.claude_code_version=${CLAUDE_CODE_VERSION}
LABEL org.opencontainers.image.claude_trace_version=${CLAUDE_TRACE_VERSION}
LABEL org.opencontainers.image.codex_version=${CODEX_VERSION}
LABEL org.opencontainers.image.gemini_cli_version=${GEMINI_CLI_VERSION}
LABEL org.opencontainers.image.atlas_cli_version=${ATLAS_CLI_VERSION}
LABEL org.opencontainers.image.ccx_version=${CCX_VERSION}
LABEL org.opencontainers.image.playwright_version=${PLAYWRIGHT_VERSION}

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
Expand Down
Loading
Loading