From 251b50ef94401047142ab1158969af6d1e428801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20H=C3=A9ritier?= Date: Wed, 24 Jun 2026 04:02:56 +0000 Subject: [PATCH 1/5] docs: update api-server session endpoints for #3199 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add POST /api/sessions/:id/fork to the Sessions endpoint table and document the Session Forking section: request body, message_index semantics (exclusive cut), response shape, title numbering, and validation errors (non-user message, out-of-range, sub-session). Signed-off-by: Arnaud Héritier --- docs/features/api-server/index.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/features/api-server/index.md b/docs/features/api-server/index.md index 104451fc0..d2b4ec456 100644 --- a/docs/features/api-server/index.md +++ b/docs/features/api-server/index.md @@ -50,6 +50,7 @@ All endpoints are under the `/api` prefix. | `DELETE` | `/api/sessions/:id` | Delete a session | | `PATCH` | `/api/sessions/:id/title` | Update session title | | `PATCH` | `/api/sessions/:id/permissions` | Update session permissions | +| `POST` | `/api/sessions/:id/fork` | Fork a session at a user message — creates a new session with messages `[0, message_index)` of the parent (see [Session Forking](#session-forking)) | | `POST` | `/api/sessions/:id/resume` | Resume a paused session (after tool confirmation) | | `POST` | `/api/sessions/:id/tools/toggle` | Toggle auto-approve (YOLO) mode | | `POST` | `/api/sessions/:id/elicitation` | Respond to an MCP tool elicitation request | @@ -293,6 +294,35 @@ runtime is attached and ready to accept follow-ups, then return its status, or `503` on timeout. This is session-scoped, unlike `GET /api/ready`, which fires as soon as any session is ready. +## Session Forking + +`POST /api/sessions/:id/fork` creates a new session whose history is a copy of the parent up to (but **excluding**) a specified user message. This lets a client "branch" a conversation — e.g. rewind to an earlier question and try a different prompt — without losing the shared history that came before. + +**Request body:** + +```json +{ "message_index": 2 } +``` + +`message_index` is a **0-based index** into the flat, user-visible message list (the same shape `GET /api/sessions/:id` returns in `messages`). The fork includes messages `[0, message_index)` — the message at `message_index` is **excluded**, so clients can prefill it into their chat input for the user to edit and resubmit. + +**Example:** + +```bash +# Fork a session before message index 4 (the user message the user wants to rewrite) +$ curl -X POST http://localhost:8080/api/sessions/$SID/fork \ + -H 'Content-Type: application/json' \ + -d '{"message_index": 4}' +# Returns: api.SessionResponse for the new forked session +# New session title: " (fork 1)", "(fork 2)", etc. +``` + +**Validation:** + +- `message_index` must point to a **user-role message**; pointing at an assistant turn returns `400 Bad Request`. +- Out-of-range indices return `400 Bad Request`. +- An index that falls inside a sub-session returns `400 Bad Request`. + ## Idempotent follow-ups `POST /api/sessions/:id/followup` accepts an optional `Idempotency-Key` From 876a61d85f22b74592d971d043e984ffd1813af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20H=C3=A9ritier?= Date: Wed, 24 Jun 2026 04:03:26 +0000 Subject: [PATCH 2/5] docs: document pprof-addr diagnostics flag for serve api for #3201 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a callout to the API Server page and an inline note to the CLI reference describing CAGENT_PPROF_ADDR / --pprof-addr: a hidden flag that starts a Go pprof HTTP server at /debug/pprof/ for heap/goroutine profiling on long-running serve api deployments. Signed-off-by: Arnaud Héritier --- docs/features/api-server/index.md | 7 +++++++ docs/features/cli/index.md | 2 ++ 2 files changed, 9 insertions(+) diff --git a/docs/features/api-server/index.md b/docs/features/api-server/index.md index d2b4ec456..aec57b9a1 100644 --- a/docs/features/api-server/index.md +++ b/docs/features/api-server/index.md @@ -180,6 +180,13 @@ docker agent serve api | [flags] | `--record` | (none) | Record AI API interactions to cassette file | | `--mcp-oauth-redirect-uri` | (none) | Public HTTPS URL advertised as the OAuth `redirect_uri` for unmanaged MCP OAuth flows. When set, docker-agent drives PKCE and code exchange in-process and sends the full authorize URL to the client via elicitation. See [Remote MCP]({{ '/features/remote-mcp/' | relative_url }}) for details. | +
+
Live profiling (advanced) +
+

For production diagnostics, set the CAGENT_PPROF_ADDR environment variable (or the hidden --pprof-addr flag) to a TCP address such as 127.0.0.1:6060. docker-agent will start a Go pprof HTTP server at /debug/pprof/, which you can query with go tool pprof. Use a loopback address — a non-loopback binding logs a security warning. This flag is intentionally hidden from --help.

+ +
+
Multi-agent configs
diff --git a/docs/features/cli/index.md b/docs/features/cli/index.md index 40773f2e5..3eb538661 100644 --- a/docs/features/cli/index.md +++ b/docs/features/cli/index.md @@ -219,6 +219,8 @@ $ docker agent serve api || [flags] | `--record [path]` | (none) | Record AI API interactions to a cassette file. | | `--mcp-oauth-redirect-uri ` | (none) | OAuth redirect URI for the unmanaged MCP OAuth flow in server mode. When set, the runtime drives PKCE and code exchange in-process and sends the full authorize URL to the client via elicitation. See [Remote MCP]({{ '/features/remote-mcp/' | relative_url }}) for details. | +> **Diagnostics:** Set `CAGENT_PPROF_ADDR=127.0.0.1:6060` (or `--pprof-addr`, a hidden flag) to start a live Go pprof server at `/debug/pprof/`. Use a loopback address; a non-loopback binding logs a security warning. + All [runtime configuration flags](#runtime-configuration-flags) (`--working-dir`, `--env-from-file`, `--models-gateway`, `--hook-*`, …) are also accepted. ```bash From dd06c8e11d2fddd410c7a4d3deed715d7bc81cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20H=C3=A9ritier?= Date: Wed, 24 Jun 2026 04:03:43 +0000 Subject: [PATCH 3/5] docs: document DMR local-model auto-discovery for #3206 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a note to the DMR provider overview explaining that docker-agent now enumerates locally-pulled models at startup. Auto-selection prefers an already-pulled model (default tag first, then first non-embedding model) rather than always defaulting to ai/qwen3:latest and triggering an interactive pull prompt. Signed-off-by: Arnaud Héritier --- docs/providers/dmr/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/providers/dmr/index.md b/docs/providers/dmr/index.md index 97555d011..9b62918c5 100644 --- a/docs/providers/dmr/index.md +++ b/docs/providers/dmr/index.md @@ -12,6 +12,8 @@ _Run AI models locally with Docker — no API keys, no costs, full data privacy. Docker Model Runner (DMR) lets you run open-source AI models directly on your machine. Models run in Docker, so there's no API key needed and no data leaves your computer. +docker-agent automatically discovers models you have already pulled from DMR. When no model is explicitly configured, auto-selection prefers a locally-installed model (choosing the configured default if it is already pulled, or otherwise the first available non-embedding model) rather than always defaulting to `ai/qwen3:latest` and triggering a pull prompt. +
No API key needed
From 4919c3d580ea605a7512d7d178634b57890128d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20H=C3=A9ritier?= Date: Wed, 24 Jun 2026 04:04:25 +0000 Subject: [PATCH 4/5] docs: document styles.RegisterBuiltinThemes for Go SDK embedders for #3182 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a 'Registering Custom Built-in Themes' section to the Go SDK guide explaining styles.RegisterBuiltinThemes: how to supply an embed.FS of partial-override YAML files, masking the default theme, and the eagerly-validated precedence rules. Signed-off-by: Arnaud Héritier --- docs/guides/go-sdk/index.md | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/guides/go-sdk/index.md b/docs/guides/go-sdk/index.md index 25b93e913..8d1b0912b 100644 --- a/docs/guides/go-sdk/index.md +++ b/docs/guides/go-sdk/index.md @@ -177,6 +177,44 @@ registry := teamloader.NewToolsetRegistry(creators) Pass the custom registry via `teamloader.WithToolsetRegistry(registry)` when calling `teamloader.Load`. Note that `teamloader.Load()` does not return an error for unknown toolset types — the failure is recorded as a load-time warning and can be retrieved with `agent.DrainWarnings()`; it is also surfaced via logging and TUI notifications. +## Registering Custom Built-in Themes + +When embedding docker-agent, you can contribute your own built-in themes via `styles.RegisterBuiltinThemes`. Registered themes integrate seamlessly with the existing theme picker, `/theme` command, and `settings.theme` config key — they behave exactly like docker-agent's own bundled themes. + +```go +import ( + "embed" + + "github.com/docker/docker-agent/pkg/tui/styles" +) + +//go:embed themes/*.yaml +var brandThemes embed.FS + +// Call at startup, before applying any persisted theme: +if err := styles.RegisterBuiltinThemes(brandThemes); err != nil { + return err +} +``` + +Each theme file lives at `themes/.yaml` inside the embedded filesystem and is a **partial override** — only the colors you want to change are required; everything else falls back to `DefaultTheme()`. + +```yaml +# themes/brand.yaml +name: Brand +colors: + accent: "#FF6A00" + background: "#1A0F0A" +``` + +To replace docker-agent's default theme entirely, ship the file as `themes/default.yaml` — it masks the bundled default while inheriting any colors you don't set. + +**Semantics:** + +- Registered sources take precedence over bundled themes; a registered ref overrides a bundled theme of the same name. +- Among multiple registered sources, last-registered wins on a collision. +- `RegisterBuiltinThemes` validates eagerly (nil fs, missing `themes/` dir) so errors surface at registration time, not at picker time. + ## MCP OAuth Token Persistence By default, MCP OAuth tokens are stored in-memory only and are not persisted across process restarts. The CLI registers a keyring-backed store automatically at startup; when embedding docker-agent as a library you must do this yourself if you want tokens to survive restarts. From dc53ff140efc4d130ee00475c0622f8cad840e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20H=C3=A9ritier?= Date: Wed, 24 Jun 2026 04:11:53 +0000 Subject: [PATCH 5/5] docs: address review feedback on PR #3215 - go-sdk: add note that omitting name: in a theme YAML falls back to the filename stem as the picker display name - dmr: clarify 'configured default' as the model: key in the agent YAML - api-server: define sub-session in the fork validation bullet --- docs/features/api-server/index.md | 2 +- docs/guides/go-sdk/index.md | 2 ++ docs/providers/dmr/index.md | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/features/api-server/index.md b/docs/features/api-server/index.md index aec57b9a1..e73cee023 100644 --- a/docs/features/api-server/index.md +++ b/docs/features/api-server/index.md @@ -328,7 +328,7 @@ $ curl -X POST http://localhost:8080/api/sessions/$SID/fork \ - `message_index` must point to a **user-role message**; pointing at an assistant turn returns `400 Bad Request`. - Out-of-range indices return `400 Bad Request`. -- An index that falls inside a sub-session returns `400 Bad Request`. +- An index that falls inside a sub-session returns `400 Bad Request`. A sub-session is a nested session created when a multi-agent config delegates work to a child agent; its messages are embedded within the parent session's message list and cannot be used as a fork boundary. ## Idempotent follow-ups diff --git a/docs/guides/go-sdk/index.md b/docs/guides/go-sdk/index.md index 8d1b0912b..de86dd013 100644 --- a/docs/guides/go-sdk/index.md +++ b/docs/guides/go-sdk/index.md @@ -207,6 +207,8 @@ colors: background: "#1A0F0A" ``` +If `name:` is omitted, docker-agent uses the filename stem as the display name in the theme picker (e.g. `brand` from `themes/brand.yaml`). + To replace docker-agent's default theme entirely, ship the file as `themes/default.yaml` — it masks the bundled default while inheriting any colors you don't set. **Semantics:** diff --git a/docs/providers/dmr/index.md b/docs/providers/dmr/index.md index 9b62918c5..48afd99f4 100644 --- a/docs/providers/dmr/index.md +++ b/docs/providers/dmr/index.md @@ -12,7 +12,7 @@ _Run AI models locally with Docker — no API keys, no costs, full data privacy. Docker Model Runner (DMR) lets you run open-source AI models directly on your machine. Models run in Docker, so there's no API key needed and no data leaves your computer. -docker-agent automatically discovers models you have already pulled from DMR. When no model is explicitly configured, auto-selection prefers a locally-installed model (choosing the configured default if it is already pulled, or otherwise the first available non-embedding model) rather than always defaulting to `ai/qwen3:latest` and triggering a pull prompt. +docker-agent automatically discovers models you have already pulled from DMR. When no model is explicitly configured, auto-selection prefers a locally-installed model (choosing the model specified via the `model:` key in the agent YAML if it is already pulled locally, or otherwise the first available non-embedding model) rather than always defaulting to `ai/qwen3:latest` and triggering a pull prompt.
No API key needed