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
16 changes: 16 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
node_modules
.wrangler
dist
.git
.github
.env
.env.*
.dev.vars
*.log
npm-debug.log*
Dockerfile
docker-compose*.yml
.dockerignore
.vscode
.idea
.DS_Store
20 changes: 20 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copy to .dev.vars for local development (read by `wrangler dev`) and/or
# to .env for the production compose file (read by `wrangler deploy`).
#
# cp .env.example .dev.vars # for `docker compose ... up` (dev)
# cp .env.example .env # for `docker compose ... run` (prod deploy)

# ----- Worker runtime secrets (read by `wrangler dev` from .dev.vars) -----
# These are the agent-facing LLM/GitHub credentials the orchestrator injects
# into Dynamic Workers at runtime. In production, set them on Cloudflare
# with `wrangler secret put ANTHROPIC_API_KEY`, etc.
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
GITHUB_PAT=ghp_...

# ----- Deploy-time credentials (read by `wrangler deploy` from env) -----
# Required only for the production compose file. Generate an API token at
# https://dash.cloudflare.com/profile/api-tokens with the "Edit Cloudflare
# Workers" template.
CLOUDFLARE_API_TOKEN=
CLOUDFLARE_ACCOUNT_ID=
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ node_modules/
dist/
.wrangler/
.dev.vars
.env
.env.local
*.log
Empty file added CLAUDE.md
Empty file.
50 changes: 50 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# syntax=docker/dockerfile:1.6

# ---------- base ----------
# Shared base: pinned Node + system deps wrangler needs (git for git bindings,
# tini for PID 1 signal handling, ca-certificates for HTTPS to Cloudflare).
FROM node:20-alpine AS base
RUN apk add --no-cache git tini ca-certificates
WORKDIR /app
ENV CI=true \
NPM_CONFIG_FUND=false \
NPM_CONFIG_AUDIT=false

# ---------- deps ----------
# Install the full dependency tree once so downstream stages can reuse the
# layer. Copying only the manifests first keeps this cache hit on code-only
# changes.
FROM base AS deps
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci

# ---------- dev ----------
# Development image: runs `wrangler dev` with hot reload. The source tree is
# bind-mounted in docker-compose.dev.yml, so we only need the toolchain baked
# into the image itself.
FROM deps AS dev
COPY . .
EXPOSE 8787
ENTRYPOINT ["/sbin/tini", "--"]
# --ip 0.0.0.0 is required so the port is reachable from the host, not just
# the container's loopback.
CMD ["npx", "wrangler", "dev", "--ip", "0.0.0.0", "--port", "8787"]

# ---------- typecheck ----------
# Dedicated stage so CI can `docker build --target typecheck` as a gate
# without producing a runtime image.
FROM deps AS typecheck
COPY . .
RUN npm run typecheck

# ---------- prod ----------
# Production image: a reproducible deploy toolchain. Cloudflare Workers run
# on Cloudflare's edge — this image does NOT host the worker. It runs
# `wrangler deploy` (pushing to Cloudflare) and is the image used by CI and
# by docker-compose.prod.yml. Typecheck is a dependency so a failing build
# cannot be deployed.
FROM deps AS prod
COPY --from=typecheck /app /app
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["npx", "wrangler", "deploy"]
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ npm run dev
curl http://localhost:8787/health
```

### Local Development with Docker

If you'd rather not install Node/wrangler on the host:

```bash
cp .env.example .dev.vars # fill in your API keys
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
# → http://localhost:8787 (hot reload enabled via source bind-mount)
```

See [docs/docker.md](docs/docker.md) for the full Compose guide, including
deploying to Cloudflare from a pinned toolchain image.

### Production Deployment

```bash
Expand Down Expand Up @@ -238,13 +251,19 @@ Full API documentation: [docs/api-reference.md](docs/api-reference.md)
├── wrangler.jsonc # Cloudflare Worker configuration
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript (strict mode)
├── Dockerfile # Multi-stage: dev / typecheck / prod deploy
├── docker-compose.yml # Base Compose service definition
├── docker-compose.dev.yml # Dev override (wrangler dev + hot reload)
├── docker-compose.prod.yml # Prod override (wrangler deploy)
├── .env.example # Template for .dev.vars and .env
├── docs/
│ ├── architecture.md # System design and data flow
│ ├── research-brief.md # Dynamic Workers platform research
│ ├── api-reference.md # Full HTTP API documentation
│ ├── agents.md # Agent types and tool API
│ ├── security.md # Security model and egress control
│ ├── deployment.md # Local dev, production, and CI/CD
│ ├── docker.md # Docker Compose usage and deploy workflow
│ └── configuration.md # Wrangler config and tuning guide
├── src/
│ ├── index.ts # Orchestrator Worker (main entry)
Expand Down Expand Up @@ -278,6 +297,7 @@ Full API documentation: [docs/api-reference.md](docs/api-reference.md)
| [Agents](docs/agents.md) | Agent types, tool API interfaces, how to add new agents |
| [Security](docs/security.md) | Sandboxing, egress control, credential separation, threat model |
| [Deployment](docs/deployment.md) | Local dev, production deploy, CI/CD pipelines |
| [Docker](docs/docker.md) | Containerized dev server and pinned deploy toolchain via Docker Compose |
| [Configuration](docs/configuration.md) | Wrangler config, secrets, tuning guide, multi-environment |

---
Expand Down Expand Up @@ -307,6 +327,6 @@ This project is dual-licensed:

The Community License grants full Apache 2.0 freedoms (including an explicit patent grant) with the Commons Clause restriction that prohibits selling the software or offering it as a paid service. All contributions are assigned to the copyright holder under the Contributor License Agreement in the LICENSE file.

For commercial licensing inquiries, contact David Brown via [GitHub](https://github.com/davidbrown).
For commercial licensing inquiries, contact David Brown via [GitHub](https://github.com/papismurf).

See [LICENSE](LICENSE) for the full terms.
36 changes: 36 additions & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Development override — runs `wrangler dev` with hot reload.
#
# Usage:
# docker compose -f docker-compose.yml -f docker-compose.dev.yml up
#
# Secrets come from .dev.vars (same file wrangler reads locally). Copy
# .env.example to .dev.vars and fill in your API keys before starting.

services:
orchestrator:
build:
target: dev
command: ["npx", "wrangler", "dev", "--ip", "0.0.0.0", "--port", "8787"]
ports:
- "8787:8787"
environment:
# Wrangler writes to $HOME; keep it inside the volume so auth/config
# persist and don't collide with the host user's real $HOME.
- HOME=/app/.wrangler/home
volumes:
# Bind-mount the source tree so edits on the host trigger wrangler's
# file watcher inside the container.
- ./src:/app/src
- ./wrangler.jsonc:/app/wrangler.jsonc
- ./tsconfig.json:/app/tsconfig.json
- ./package.json:/app/package.json
- ./package-lock.json:/app/package-lock.json
# .dev.vars is wrangler's local secrets file. Mounted read-only so a
# misbehaving dep can't rewrite it.
- ./.dev.vars:/app/.dev.vars:ro
# Named volume for node_modules so host and container don't fight over
# platform-specific binaries (esbuild, etc.).
- node_modules:/app/node_modules

volumes:
node_modules:
32 changes: 32 additions & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Production override — runs `wrangler deploy` against Cloudflare.
#
# Important: Cloudflare Workers run on Cloudflare's edge. This compose file
# does NOT host the worker; it provides a reproducible, pinned toolchain for
# deploying. Use it from CI or from a workstation that doesn't have the
# correct Node/wrangler versions installed locally.
#
# Usage:
# # One-shot deploy (recommended):
# docker compose -f docker-compose.yml -f docker-compose.prod.yml run --rm orchestrator
#
# # Tail live production logs:
# docker compose -f docker-compose.yml -f docker-compose.prod.yml run --rm orchestrator npx wrangler tail
#
# Secrets are supplied via environment variables (e.g. an .env file or the
# CI provider's secret store). CLOUDFLARE_API_TOKEN is required; the
# per-provider API keys are consumed by `wrangler secret put` in a separate
# step — they are NOT baked into the Worker at deploy time.

services:
orchestrator:
build:
target: prod
# `run --rm` + `restart: no` ensures deploys are one-shot, not a service
# that keeps restarting after a successful push.
restart: "no"
command: ["npx", "wrangler", "deploy"]
environment:
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}
- CLOUDFLARE_ACCOUNT_ID=${CLOUDFLARE_ACCOUNT_ID:-}
# No source bind-mount: the image is the deploy artifact. Reproducibility
# comes from the built image, not from whatever happens to be on disk.
23 changes: 23 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Base compose file — shared service definition consumed by both the dev and
# prod overrides. Invoke it via:
# docker compose -f docker-compose.yml -f docker-compose.dev.yml up
# docker compose -f docker-compose.yml -f docker-compose.prod.yml run --rm orchestrator
#
# On its own this file is not intended to `up` — the overrides pick the
# Dockerfile target and the command.

services:
orchestrator:
image: agent-orchestrator:${TAG:-local}
build:
context: .
dockerfile: Dockerfile
# `tty` keeps wrangler's interactive output readable when attached.
tty: true
# Cache wrangler's local state (D1/KV/DO simulators, build artifacts)
# across container restarts so dev startup stays fast.
volumes:
- wrangler-state:/app/.wrangler

volumes:
wrangler-state:
Loading
Loading