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
15 changes: 14 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ jobs:
- name: cross-build linux amd64/arm64
run: make build-linux

# The adapter kinds left out of the default build (experimental_adapters
# tag) must keep compiling and passing their fake-server tests.
go-experimental:
name: go (experimental adapters)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: build, vet and test with -tags experimental_adapters
run: make experimental

postgres:
name: postgres conformance
runs-on: ubuntu-latest
Expand Down Expand Up @@ -180,7 +193,7 @@ jobs:
# again. It approves what CI checked, not what a reviewer read.
approve:
name: approve when CI passes
needs: [go, postgres, sdk-typescript, console, sdk-python, helm, images, dco, release-source]
needs: [go, go-experimental, postgres, sdk-typescript, console, sdk-python, helm, images, dco, release-source]
if: >-
always() &&
github.event_name == 'pull_request' &&
Expand Down
12 changes: 9 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ for humans).
make verify
```

It runs gofmt, go vet, Go tests with `-race`, the SDK tests and the Helm lint,
including the replay of recorded OpenSandbox runtimes. For changes touching
It runs gofmt, go vet, Go tests with `-race`, the same build, vet and tests
with `-tags experimental_adapters` (`make experimental`), the SDK tests and
the Helm lint, including the replay of recorded OpenSandbox runtimes. For changes touching
`internal/store/postgres`, also run `make test-postgres`. For `console/`, run
`npm run typecheck && npm run build && npm run build:server` there; for
`site/` or any page it publishes from `docs/`, `npm run build` in `site/`
Expand All @@ -46,7 +47,12 @@ that covers it, and say in the PR what did not run.
(acceptance scenarios A–L) green.
- Backends: `internal/adapters/*` (`opensandbox` is the default private
runtime; Differently runs no sandboxes itself), `internal/wiring` (adapter
factories), `internal/pools`. The real-stack suite is `test/e2e`
factories), `internal/pools`. The default build holds `opensandbox`,
`daytona`, `freestyle`, `remote`, `devhost` and `fake`. Every other
adapter, and the `cloudhttp`, `pyshell` and `shellcmd` helpers, carries
`//go:build experimental_adapters`: a plain `go build`, `go vet` or
`go test` does not see them, so use `make experimental` when you touch
them or anything they share (`httpx`, `pkg/adapter`). The real-stack suite is `test/e2e`
(`make e2e-prepare e2e-up e2e`, or against any install).
- Recorded runtimes: `internal/adapters/opensandbox/testdata/recordings`,
replayed by `TestReplayRecordings`; re-record with the live test after an
Expand Down
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,38 @@ All notable changes are recorded here. The format follows

## [Unreleased] — on `pre-release`

### Changed (breaking): the default build holds only the verified adapters

The published image, the release binaries and `make build` now contain the
`opensandbox`, `daytona` and `freestyle` adapters, the `remote` plugin
protocol and the dev-mode `devhost` and `fake`. The other 13 adapter kinds
are experimental and compile in only with the Go build tag
`experimental_adapters`: `agent-sandbox`, `cubesandbox`, `e2b`, `boat`,
`morph`, `vercel`, `fly`, `blaxel`, `aws-agentcore`, `azure-sandboxes`,
`azure-sessions`, `gcp-sandboxes` and `northflank`. Apart from
`agent-sandbox`, which ran live on a kind cluster, they have only been
tested against fake servers. No adapter code was removed, and CI still
builds, vets and tests it with the tag.

- **If you use one of the 13 kinds**, the next published image will not
start with a config file that names it: the error names the pool, the
kind and the build tag. A pool of such a kind added earlier through the
API stays registered and reports `unavailable` with the same reason.
Build the server with `go build -tags experimental_adapters`, or the image
with `--build-arg GO_TAGS=experimental_adapters`
([provider catalog](docs/providers/README.md#what-the-server-contains)).
- `POST /v1/admin/pools` answers 400 `invalid_request` for these kinds on a
default build.
- Helm: pools of these kinds are refused unless `server.experimentalAdapters`
is `true`, which you set together with a `server.image` built with the
tag.
- The dashboard, the console and `differently admin pool add --help` list
only the default kinds. Experimental pools are added in the config file,
with the CLI or through the API.
- `make verify` and CI gained `make experimental` (build, vet and test with
the tag). The live tests of `agent-sandbox` and `cubesandbox` now need
`-tags live,experimental_adapters`.

### Fixed (placement, scheduler and clients)

Found by reading the code, each with a test that fails on the old behaviour.
Expand Down
22 changes: 17 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@ VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo 0.1.
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
LDFLAGS := -s -w -X github.com/different-ai/differently/internal/version.Version=$(VERSION) -X github.com/different-ai/differently/internal/version.Commit=$(COMMIT)
BINS := differently-server differently
# Go build tags for `make build`, `build-linux` and `images`. The default (none)
# is the published build: opensandbox, daytona, freestyle, remote and devhost.
# GO_TAGS=experimental_adapters adds the other adapter kinds (docs/providers).
GO_TAGS ?=
EXPERIMENTAL_TAG := experimental_adapters
PG_PORT ?= 55432

.PHONY: build build-linux test test-postgres fmt-check vet sdk-test helm-lint verify dev images clean
.PHONY: build build-linux test test-postgres fmt-check vet experimental sdk-test helm-lint verify dev images clean

build:
@mkdir -p bin
CGO_ENABLED=0 go build -trimpath -ldflags "$(LDFLAGS)" -o bin/ $(addprefix ./cmd/,$(BINS))
CGO_ENABLED=0 go build -trimpath -tags "$(GO_TAGS)" -ldflags "$(LDFLAGS)" -o bin/ $(addprefix ./cmd/,$(BINS))

build-linux:
@for arch in amd64 arm64; do \
mkdir -p bin/linux-$$arch; \
CGO_ENABLED=0 GOOS=linux GOARCH=$$arch go build -trimpath -ldflags "$(LDFLAGS)" -o bin/linux-$$arch/ $(addprefix ./cmd/,$(BINS)) || exit 1; \
CGO_ENABLED=0 GOOS=linux GOARCH=$$arch go build -trimpath -tags "$(GO_TAGS)" -ldflags "$(LDFLAGS)" -o bin/linux-$$arch/ $(addprefix ./cmd/,$(BINS)) || exit 1; \
done

fmt-check:
Expand All @@ -27,6 +32,13 @@ vet:
test:
go test -race -count=1 ./...

# The adapter kinds outside the default build must keep compiling and passing
# their fake-server tests: build, vet and test everything with the tag.
experimental:
go build -tags $(EXPERIMENTAL_TAG) ./...
go vet -tags $(EXPERIMENTAL_TAG) ./...
go test -race -count=1 -tags $(EXPERIMENTAL_TAG) ./...

# Runs the store conformance suite against a disposable Postgres container.
test-postgres:
@docker rm -f differently-pg-test >/dev/null 2>&1 || true
Expand All @@ -46,13 +58,13 @@ helm-lint:
helm template differently deploy/helm/differently -f $$f >/dev/null || exit 1; \
done

verify: fmt-check vet test sdk-test helm-lint
verify: fmt-check vet test experimental sdk-test helm-lint

dev: build
./bin/differently-server --dev

images:
docker build -f build/server.Dockerfile -t ghcr.io/different-ai/differently-server:$(VERSION) .
docker build -f build/server.Dockerfile --build-arg GO_TAGS=$(GO_TAGS) -t ghcr.io/different-ai/differently-server:$(VERSION) .
docker build -f build/cli.Dockerfile -t ghcr.io/different-ai/differently-cli:$(VERSION) .

clean:
Expand Down
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/differently-splash-dark.svg">
<img alt="Differently: your apps and agents call one API; differently-server handles tenancy, quotas, policy and audit, and places each sandbox on OpenSandbox or your own backend inside your infrastructure, or on a managed provider such as E2B or Daytona only if policy allows" src="docs/assets/differently-splash-light.svg" width="100%">
<img alt="Differently: your apps and agents call one API; differently-server handles tenancy, quotas, policy and audit, and places each sandbox on OpenSandbox or your own backend inside your infrastructure, or on a managed provider such as Daytona or Freestyle only if policy allows" src="docs/assets/differently-splash-light.svg" width="100%">
</picture>
</p>

Expand Down Expand Up @@ -30,10 +30,12 @@ account of it:

- by default on [OpenSandbox](https://github.com/opensandbox-group/OpenSandbox)
on your own Docker hosts, Kubernetes clusters or microVM nodes;
- on [15 other built-in provider adapters](docs/providers/README.md), from
E2B, Daytona and Vercel to the AWS, Azure and Google Cloud sandbox
services, or a plugin for any other backend, only where your policies
allow it.
- on Daytona or Freestyle, or a plugin for any other backend, only where
your policies allow it;
- on 13 more [provider adapters](docs/providers/README.md#what-the-server-contains),
from E2B and Vercel to the AWS, Azure and Google Cloud sandbox services,
which are experimental: tested against fake servers and left out of the
published build unless you compile them in.

Apache-2.0, fully self-hosted, no telemetry. Built by the
[OpenWork](https://github.com/different-ai) team.
Expand Down Expand Up @@ -145,7 +147,8 @@ prerequisites, [day-2 operations](docs/deploy/day-2.md) and the
- the published `v0.1.0-alpha.1` chart and images install from public
artifacts alone;
- real OpenSandbox responses are recorded and replayed in every `go test`;
- the `agent-sandbox` adapter against a Kubernetes cluster (kind);
- the experimental `agent-sandbox` adapter against a Kubernetes cluster
(kind);
- the Daytona (container class) and Freestyle adapters against live
accounts: exec, files, port URLs, stop/start and snapshots on both, and
egress policy, pause/resume, memory snapshots and fork on Freestyle;
Expand All @@ -161,7 +164,10 @@ prerequisites, [day-2 operations](docs/deploy/day-2.md) and the
- node drains, and more than one KVM node;
- managed EKS, GKE and AKS;
- the other 12 provider adapters against live accounts: each is tested
against a fake of its provider's published API.
against a fake of its provider's published API. These 12 and
`agent-sandbox` are experimental and not in the published image or
binaries; a server built with `-tags experimental_adapters` has them
([what the server contains](docs/providers/README.md#what-the-server-contains)).

Each of the 26 providers has a page with its tested status, capabilities and
configuration in the [provider catalog](docs/providers/README.md). The
Expand All @@ -179,8 +185,11 @@ against global, organization and project policy, ranks what is left, and
records why. Adapters talk to the backends:

- `opensandbox`, the default private runtime;
- 15 more provider adapters, from `agent-sandbox` and `cubesandbox` you run
to `e2b`, `daytona`, `vercel` and the cloud providers' sandbox services
- `daytona` and `freestyle`, managed providers that receive work only when
policy allows it;
- 13 experimental adapters behind the `experimental_adapters` build tag,
from `agent-sandbox` and `cubesandbox` you run to `e2b`, `vercel` and the
cloud providers' sandbox services
([provider catalog](docs/providers/README.md));
- `remote`, any service speaking the [adapter protocol](docs/adapters/specification.md).

Expand Down
7 changes: 5 additions & 2 deletions build/server.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
# differently-server image: control plane plus the CLI (used by `helm test`).
# The published image is built with no Go build tags. To include the
# experimental adapter kinds (docs/providers/README.md):
# docker build -f build/server.Dockerfile --build-arg GO_TAGS=experimental_adapters .
FROM --platform=$BUILDPLATFORM golang:1.26-bookworm AS build
ARG TARGETOS TARGETARCH VERSION=0.1.0-dev COMMIT=unknown
ARG TARGETOS TARGETARCH VERSION=0.1.0-dev COMMIT=unknown GO_TAGS=""
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -trimpath \
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -trimpath -tags "${GO_TAGS}" \
-ldflags "-s -w -X github.com/different-ai/differently/internal/version.Version=${VERSION} -X github.com/different-ai/differently/internal/version.Commit=${COMMIT}" \
-o /out/ ./cmd/differently-server ./cmd/differently

Expand Down
2 changes: 1 addition & 1 deletion cmd/differently/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ func poolAddCmd() *cobra.Command {
return raw("POST", "/v1/admin/pools", body)
}}
f := cmd.Flags()
f.StringVar(&adapterKind, "adapter", "", "opensandbox, daytona, freestyle, remote, vercel, fly, agent-sandbox, cubesandbox, aws-agentcore, azure-sandboxes, azure-sessions, gcp-sandboxes, northflank, boat, e2b, morph or blaxel")
f.StringVar(&adapterKind, "adapter", "", "opensandbox, daytona, freestyle or remote; a server built with -tags experimental_adapters has more (docs/providers)")
f.StringVar(&trust, "trust", "", "external (someone else runs it) or private (you do); managed providers are always external, self-hostable kinds must set one")
f.StringArrayVar(&settings, "config", nil, "adapter setting key=value (repeatable), e.g. apiURL=https://app.daytona.io/api")
f.StringVar(&region, "region", "", "region label")
Expand Down
Loading
Loading