Skip to content

Commit 8e2c1f7

Browse files
committed
feat(0.3.0): HTTP transport + OpenAPI via huma; auth guard for non-loopback
Adds a REST surface alongside the unix socket. One daemon serves both; the repo's own locks serialize concurrent mutations across transports. internal/api/http.go (huma v2 + humago adapter) - Typed Input/Output structs → OpenAPI 3.1 spec at /openapi.json + interactive docs at /docs, both always in sync with the running code. - 12 endpoints (head/log/branches/show/diff/commit/checkout/delete/tags get+set/tournament/gc). Streaming exec stays socket-only (SSE follow-up). - isLoopback(): bare ":PORT" treated as non-loopback (Go binds all interfaces) so the no-token guard does the safer thing. Unit test pins the rule. - bearerAuth: /v1/* requires Authorization: Bearer <AGENTENV_HTTP_TOKEN>; /openapi.json + /docs stay open for discoverability. Unit-tested. cmdDaemon takes --http :PORT (or AGENTENV_HTTP), opens the HTTP listener in a goroutine. AGENTENV_HTTP_TOKEN required for any non-loopback bind, checked at startup (won't quietly expose itself). examples/http_client.sh: curl walkthrough. README + examples/README + CHANGELOG updated to call out the new transport, the discoverability of /docs, and the headline use case (curl/Postman/SDK generation, all without a socket library).
1 parent 7d113c2 commit 8e2c1f7

13 files changed

Lines changed: 1718 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,30 @@ All notable changes to this project are documented here. The format is based on
44
[Keep a Changelog](https://keepachangelog.com/), and the project aims to follow
55
[Semantic Versioning](https://semver.org/).
66

7-
## [Unreleased]
7+
## [0.3.0] - 2026-06-17
88

99
### Added
10+
- **HTTP transport + OpenAPI**: `agentenv daemon --http :PORT` (or
11+
`AGENTENV_HTTP=":PORT"`) opens a REST surface alongside the unix socket.
12+
Built on `huma` v2 — every typed handler signature contributes to an
13+
OpenAPI 3.1 spec served at `/openapi.json`, with interactive docs at
14+
`/docs`. 12 endpoints grouped into 4 tags (History / Mutation / Branching /
15+
Tags) cover head/log/branches/show/diff/commit/checkout/delete/tags(get,
16+
set)/tournament/gc; streaming `exec` stays socket-only (SSE port is
17+
follow-up). Loopback is no-auth; non-loopback binds require
18+
`AGENTENV_HTTP_TOKEN` (verified at startup — won't quietly expose itself).
19+
See `examples/http_client.sh` for a curl walkthrough.
20+
- `docs/openapi.json` — pretty-printed snapshot of the live spec, so GitHub /
21+
reviewers / SDK generators can read it without running the daemon.
22+
`make openapi-snapshot` regenerates it from a one-off daemon (run before
23+
tagging a release).
24+
- `examples/mcp_client.py`: drive `agentenv mcp` over JSON-RPC stdio from any
25+
language (no Claude Code needed) — covers `agentenv__log` / `__branches` /
26+
`__delete`.
27+
- `examples/goclient/main.go`: rewritten around the high-level `tournament`
28+
socket op (one round-trip, parallel workspaces) + the new `delete` op.
29+
- `examples/branch_explore.py`: kept the manual-loop exploration pattern,
30+
added a `delete` pass that prunes the losing branches.
1031
- New README hero GIF: real Claude Code, running inside `rewindable-claude`,
1132
deletes its own binary then calls `agentenv__checkout` MCP tool to roll the
1233
whole environment back — the binary is restored, the Claude session keeps
@@ -18,6 +39,9 @@ All notable changes to this project are documented here. The format is based on
1839
pure `COPY` over `rewindable-claude` — seconds to build.
1940

2041
### Removed
42+
- `examples/Client.java` — three near-identical socket clients was noise;
43+
the goclient + python pair plus the new mcp_client / http_client cover the
44+
patterns that matter.
2145
- Obsolete shell-scripted demos and recorders that the real Claude Code GIF
2246
supersedes: `examples/demo/` (killer-demo + self-rollback-demo + README),
2347
`scripts/make-demo-gif.sh`, `scripts/make-claude-gif.sh`,
@@ -200,6 +224,7 @@ drive rollback natively.
200224
incremental checkout (copy only the diff); `AGENTENV_IGNORE` excludes ephemeral
201225
paths; auto-snapshot labels list the changed files.
202226

227+
[0.3.0]: https://github.com/css521/agentenv/releases/tag/v0.3.0
203228
[0.2.0]: https://github.com/css521/agentenv/releases/tag/v0.2.0
204229
[0.1.1]: https://github.com/css521/agentenv/releases/tag/v0.1.1
205230
[0.1.0]: https://github.com/css521/agentenv/releases/tag/v0.1.0

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ GOOS_LINUX ?= linux
1515
GOARCH ?= $(shell uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/;s/arm64/arm64/')
1616
GOPROXY ?= $(shell go env GOPROXY)
1717

18-
.PHONY: help build test vet verify-rootless verify-btrfs verify-supervise verify-mcp verify-rollback dev-shell dev-shell-stop clean
18+
.PHONY: help build test vet verify-rootless verify-btrfs verify-supervise verify-mcp verify-rollback openapi-snapshot dev-shell dev-shell-stop clean
1919

2020
help:
2121
@awk 'BEGIN{FS=":.*##"; printf "Targets:\n"} /^[a-zA-Z_-]+:.*##/ { printf " %-22s %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
@@ -66,6 +66,9 @@ verify-rollback: ## MCP-driven end-to-end rollback (asserts files actually rever
6666
--security-opt seccomp=unconfined --security-opt apparmor=unconfined \
6767
agentenv-rollback-smoke
6868

69+
openapi-snapshot: ## regenerate docs/openapi.json from a one-off daemon (run before tagging)
70+
bash scripts/snapshot-openapi.sh
71+
6972
# --- Persistent dev container: fast inner loop on macOS -----------------------
7073
# `make dev-shell` starts (or reattaches to) a long-running container with the
7174
# source bind-mounted; rebuilds and verifies inside are seconds (no setup tax).

README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ CGO_ENABLED=1 go build -tags btrfs -o agentenv .
8282
# run modes
8383
agentenv supervise -- <agent> run an UNMODIFIED agent inside the env; auto-snapshot;
8484
rollback (out-of-band) kills + restarts it ← primary
85-
agentenv daemon [--socket p] serve the JSON API over a unix socket (for orchestrators)
85+
agentenv daemon [--socket p] [--http :PORT]
86+
serve the JSON API over a unix socket (default) and/or HTTP+OpenAPI
8687
agentenv mcp [--socket p] MCP server over stdio (Claude Code & other MCP hosts)
8788
agentenv shell interactive shell inside the env (human/debug)
8889
agentenv exec -- <cmd...> run one command in the env (scripting/CI)
@@ -105,6 +106,7 @@ agentenv show <ref> | diff <a> <b> what changed (confirm a change / rollbac
105106
agentenv gc reclaim disk from sparsified snapshots
106107
107108
Env: AGENTENV_ROOT (default /agentfs), AGENTENV_SOCKET, AGENTENV_BACKEND,
109+
AGENTENV_HTTP (=":PORT" / "127.0.0.1:PORT"), AGENTENV_HTTP_TOKEN (required for non-loopback HTTP),
108110
AGENTENV_KEEP_RECENT, AGENTENV_IGNORE.
109111
```
110112

@@ -174,6 +176,35 @@ silent for 10 minutes), then ends with a terminal frame:
174176
Clients keep reading frames until they see `"ok":true` or `"error":"..."` — see
175177
`examples/branch_explore.py` for the streaming client pattern.
176178

179+
## HTTP + OpenAPI (REST surface)
180+
181+
Prefer `curl`, Postman, or a generated SDK over a raw unix socket? Enable the
182+
HTTP transport — it lives alongside the socket on the same daemon:
183+
184+
```bash
185+
# loopback, no auth (local development)
186+
agentenv daemon --http 127.0.0.1:8911
187+
188+
# exposed; a Bearer token is REQUIRED for any non-loopback bind
189+
AGENTENV_HTTP_TOKEN=secret agentenv daemon --http :8911
190+
```
191+
192+
Auto-served:
193+
- `GET /v1/head` `GET /v1/log` `GET /v1/branches` `GET /v1/nodes/{id}`
194+
`GET /v1/diff?a=&b=` `GET /v1/tags`
195+
- `POST /v1/commit` `POST /v1/checkout` `POST /v1/tags` `POST /v1/tournament`
196+
`POST /v1/gc`
197+
- `DELETE /v1/nodes/{id}` (the v0.2.0 node-delete op, RESTful)
198+
- `GET /openapi.json` — OpenAPI 3.1 spec generated by `huma` from the typed
199+
handler signatures (always in sync with the running code). A pretty-printed
200+
snapshot for offline viewing lives at [`docs/openapi.json`](./docs/openapi.json);
201+
regenerate it with `make openapi-snapshot` before tagging a release.
202+
- `GET /docs` — interactive API docs, one URL to open in a browser
203+
204+
`exec` is still socket-only (it's a stdout/stderr stream — Server-Sent Events
205+
support is a follow-up). Everything else is on HTTP. See
206+
[`examples/http_client.sh`](./examples/http_client.sh) for a curl walkthrough.
207+
177208
## MCP (Claude Code & other MCP hosts)
178209

179210
`agentenv mcp` is a Model Context Protocol server over stdio. It exposes six

docs/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
Shareable assets:
44

5+
- `openapi.json` — pretty-printed snapshot of the HTTP daemon's `/openapi.json`
6+
(regenerated by `make openapi-snapshot`; authoritative source is whatever a
7+
live `agentenv daemon --http :PORT` serves at runtime).
8+
59
- `claude-rewind.cast` — asciinema recording of a real Claude Code session
610
(running inside the `rewindable-claude` image) deleting its own binary,
711
then calling the `agentenv__checkout` MCP tool to roll the WHOLE environment

0 commit comments

Comments
 (0)