搭个 agent 团队,还得写一堆胶水代码?
Docker 的 docker-agent:YAML 定义 agent、配工具、多 agent 编排,构建运行分享一条龙。
适合快速拼 agent 团队的人,不用代码就能先跑起来。
先搭几个 agent,分工还是单打独斗?
#Docker #Agent @grok
docker/docker-agent
3 likes · 183 views
Your Next AI Agent's Brain Is One `docker model pull` Away
Your AI agent burns tokens to think. Most of that thinking - the tool-call planning, the YAML editing, the re-reads of the same file - does not need a frontier model behind an API. Docker Model Runner keeps a real LLM inside the Docker engine you already run, exposes it on an OpenAI-compatible endpoint, and charges you nothing per call. docker model pull is the whole setup.
This post is the wiring guide: what Model Runner actually is (and the one detail everyone gets wrong), how to size the model, and how to point Docker Agent - the CLI plugin that defines agent teams in YAML - at a local model for a fully offline agent stack.
In this post:
What is Docker Model Runner, actually?
The detail everyone gets wrong: no container starts
Sizing the brain: GGUF and the quantization table
Wiring it to an agent: the dmr.yaml contract
What a local brain can and cannot do for an agent
FAQ
Key Takeaways
- Model Runner is an inference server inside Docker, not a container. docker model run calls an API; no image is built, no container is created (Docker blog).
- It speaks OpenAI, Anthropic, and Ollama API formats from the same endpoint - http://localhost:12434/engines/v1 for OpenAI-compatible clients (Docker docs, API reference).
- Models are GGUF files pulled from Docker Hub or Hugging Face, quantized per tag: ai/llama3.2:3B-Q4_K_M means 3B parameters at ~4.5 bits per weight (Docker docs, inference engines).
- llama.cpp is the default engine and works everywhere; vLLM needs NVIDIA GPUs for production throughput; Diffusers generates images (Docker docs).
- Docker Agent accepts it as provider: dmr - one YAML block, and your agent team runs offline (examples/dmr.yaml).
What is Docker Model Runner, actually?
Model Runner is Docker's answer to a question that kept coming up as agents went mainstream: why should the model live behind someone else's API when it could live next to your containers?
The component ships with Docker Desktop 4.40+ (enabled by default on Apple silicon) and is being built out for Linux engines. You manage it with a CLI that mirrors the container grammar you already know (Docker blog, Run LLMs locally):
$ docker model pull ai/smollm2:360M-Q4_K_M
$ docker model run ai/smollm2
The tag scheme matches image tags: {model}:{parameters}-{quantization}. That 360M-Q4_K_M is a 360-million-parameter model at 4-bit quantization - small enough to feel instant, and the pattern scales up to the size your RAM allows.
Once a model is pulled, Docker exposes it through REST endpoints. The API reference lists OpenAI, Anthropic, and Ollama-compatible surfaces, so tools that already speak those dialects work without adaptation (Docker docs, DMR REST API):
| Access from | Base URL |
| --- | --- |
| Host processes (TCP) | http://localhost:12434 |
| Containers (Docker Desktop) | http://model-runner.docker.internal |
| Containers (Linux engine) | http://172.17.0.1:12434 |
For OpenAI-compatible SDKs specifically, the base URL is http://localhost:12434/engines/v1, and a completion is a standard POST /engines/v1/chat/completions (Docker docs, API reference).
The detail everyone gets wrong: no container starts
Here is the part I had to reread. Coming from years of docker container run, the mental model writes itself: the model runs in a container. It does not.
Docker's own walkthrough stops to make the point: docker model run "won't spin up any kind of container." Instead, it calls an Inference Server API endpoint hosted by the Docker engine. There is no image layer for the model runtime, no entrypoint, no container ls entry to find. The engine itself gained an inference server.
Why that matters in practice: there is nothing to shell into, nothing to restart when it misbehaves, and nothing that shows up in your Compose file. The model is closer to a built-in volume format than a workload - Docker calls the packaging "just files" with weights, tokenizer, and metadata in one GGUF binary (Docker blog, How to Build, Run, and Package AI Models).
Sizing the brain: GGUF and the quantization table
GGUF is the format llama.cpp consumes, and its whole trick is quantization: shrinking weights from 16 bits to fewer without collapsing quality. The inference-engines page publishes the table worth internalizing before you pull anything:
| Quantization | Bits per weight | Memory usage | Quality |
| --- | --- | --- | --- |
| Q2_K | ~2.5 | Lowest | Reduced |
| Q3_K_M | ~3.5 | Minimal | Acceptable |
| Q4_K_M | ~4.5 | Low | Good |
| Q5_K_M | ~5.5 | Moderate | Excellent |
| Q6_K | ~6.5 | Higher | Excellent |
| Q8_0 | 8 | High | Near-original |
| F16 | 16 | Highest | Original |
Docker's recommendation is Q4_K_M as the balance point for most use. The arithmetic is the whole decision: a 3B-parameter model at Q4_K_M is roughly 1.8 GB of weights (3B x 4.5 bits / 8), which fits on a laptop and leaves the model feeling responsive. The same 3B at F16 is about 6 GB.
Under the hood, llama.cpp is the default engine, with Metal acceleration automatic on Apple Silicon, CUDA on NVIDIA Windows and Linux, and a plain CPU path that works anywhere (Docker docs, inference engines). Two more engines exist for narrower jobs: vLLM for production throughput on NVIDIA hardware (Safetensors format), and Diffusers for image generation.
One caveat from the same page: models from Hugging Face must be GGUF already. A random Safetensors checkpoint will not pull (Docker docs, inference engines).
Wiring it to an agent: the dmr.yaml contract
Docker Agent - the CLI plugin, formerly cagent, that defines agent teams in YAML - takes Model Runner as a first-class provider. The repository's examples/dmr.yaml is the whole contract:
agents:
root:
model: qwen
description: "Pirate-themed AI assistant"
instruction: Talk like a pirate
models:
qwen:
provider: dmr
model: ai/qwen3
# base_url defaults to http://localhost:12434/engines/llama.cpp/v1
# use http://model-runner.docker.internal/engines/v1 if you run
# docker-agent from a container
provider: dmr is the switch. One environment variable's worth of configuration, and the same agent definition that ran against a cloud provider now runs against the engine on your machine. The README lists the cloud escape hatch as peers: OpenAI, Anthropic, Gemini, Bedrock, Mistral, xAI, plus DMR for local (docker-agent README).
Two details in that same example file are worth more than they look.
First, speculative decoding. The example defines a second model as a draft engine:
qwen_speculative:
provider: dmr
model: ai/qwen3
provider_opts:
speculative_draft_model: ai/qwen3:0.6B-Q4_K_M
speculative_num_tokens: 16
speculative_acceptance_rate: 0.8
A small draft model proposes tokens the big model verifies - a local-inference trick that trades a little quality risk for real speed, with the llama.cpp defaults documented right in the YAML (docker-agent examples).
Second, the multimodal flag. DMR-hosted models are not in the models.dev catalog, so docker-agent cannot detect what a local model can do and defaults to text-only. If you pull a vision model, you declare it yourself (docker-agent examples):
qwen_vision:
provider: dmr
model: ai/qwen2.5-vl
provider_opts:
supports_images: true
supports_pdf: false
If you run docker-agent from inside a container rather than the host, the base URL changes to http://model-runner.docker.internal/engines/v1 - the same endpoint namespacing the Model Runner docs describe for containers.
And if you would rather not change the agent's provider at all, docker model gateway runs an OpenAI-compatible proxy on http://0.0.0.0:4000 and routes to Model Runner models by name - useful for tools that insist on their own base URL handling.
What a local brain can and cannot do for an agent
The honest part. A 360M SmolLM2 will not plan multi-step tool calls the way a frontier model does, and pretending otherwise is how agent projects die. What the local path is genuinely good for, based on what the docs themselves demonstrate:
High-frequency, low-stakes calls. Classification, routing, extraction, summarization - the calls an agent makes dozens of times per run where cloud latency and cost compound. The docker model gateway reference exists precisely because tools want these on a local endpoint.
Draft work. The speculative-decoding pattern in the dmr.yaml example is the docs' own suggestion: a small draft model plus a larger verifier. The same shape works inside agent teams - a fast local model triages, a cloud model handles the hard reasoning steps, and the provider switch is one line (docker-agent repo, examples).
Offline and private by construction. The completion never leaves the machine - the launch blog's curl example notes "No API key required - this runs locally and securely on your machine". For agent tasks touching private repos or data, that is not a cost feature; it is the feature.
What does not transfer: frontier reasoning, long-context retrieval over huge codebases, and reliable structured-output discipline under load. Those are exactly the capabilities you pay tokens for, and the Model Runner docs do not claim otherwise - the engines table positions llama.cpp for "local development, resource efficiency," with vLLM as the production path when you have the GPUs (Docker docs, Model Runner).
The sensible architecture is not local instead of cloud. It is a tiered brain: the agent's router, summarizer, and classifier run at $0.00 on Model Runner; the steps that genuinely need frontier judgment keep their API key. Docker Agent's provider model supports both in one team, which is what makes the whole thing practical rather than a stunt.
FAQ
Do I need Docker Desktop for Model Runner?
Docker Desktop 4.40+ ships it (default-on for Apple silicon). On Linux engines the component is arriving through the standard Docker repositories; the API reference documents the Linux base URL as http://172.17.0.1:12434 from containers and http://localhost:12434 from the host.
Which model should I pull first?
ai/smollm2:360M-Q4_K_M - the launch blog's own example. It is small enough to be instant and exercises the whole pull-run-query loop.
Can my existing OpenAI SDK point at it?
Yes. Base URL http://localhost:12434/engines/v1, standard chat completions, no API key. Anthropic- and Ollama-compatible clients are supported from the same endpoint with different paths (Docker docs, API reference).
Does the model run in a container?
No. It runs in an inference server inside the Docker engine. Nothing appears in docker container ls (Docker blog, Run LLMs locally).
Can docker-agent use a local vision model?
Yes, with supports_images: true declared under provider_opts - DMR-hosted models default to text-only because the agent cannot auto-detect their capabilities (docker-agent examples).
What are the five lines that matter?
$ docker model pull ai/smollm2:360M-Q4_K_M
$ curl http://localhost:12434/engines/v1/chat/completions ...
models:
qwen:
provider: dmr
model: ai/qwen3
Pull a model, curl it on the OpenAI-compatible endpoint, point your agent at provider: dmr. The brain now runs where your containers run, and the meter never starts.
Verified against docs.docker.com (Model Runner overview, DMR REST API reference, inference engines, docker model gateway) and the docker-agent repository (README, examples/dmr.yaml) plus three Docker blog posts, all retrieved 2026-10-26. I did not run this walkthrough on my own machine yet - the model-runner component is not available for my Linux engine's repository at time of writing, and I flag that here rather than pretending otherwise. Every claim above traces to the linked sources.
Sources
Every claim above traces to these primary sources. Where I could not verify something hands-on, the post says so.
- Docker Model Runner
- Docker Agent
- Docker blog
- Docker docs, API reference
- Docker docs, inference engines
- examples/dmr.yaml
- docker model gateway
- launch blog's
- GitHub
About the author
Kunal Das writes operations engineering notes as he learns them, always against primary sources. Contact: GitHub and dev.to. Follow the Docker tag for the next posts in this series.
`docker push` Works on AI Agents Now
docker push Works on AI Agents Now
Docker Agent is a docker CLI plugin that turns an AI agent into an OCI artifact. You define the agent in YAML, run it with docker agent run, then ship it with docker agent share push to any OCI-compatible registry, Docker Hub or GitHub Container Registry included. Anyone on the team can then run your agent with docker agent run myorg/agent:tag (Docker Agent docs). An OCI artifact is the registry packaging format container images already use; here it carries an agent config instead of a filesystem. Push, pull, sign, pin by digest: the same lifecycle a container image has, applied to agents.
I run a small agent on a VM myself: it reads a pitch board, writes a Docker post, and stages it for publishing every morning. Getting that thing reproducible on another machine is exactly the problem this tool attacks, so I read the repo and docs end to end. The pitch board lives in Obsidian, the runs land in a ledger, and the whole setup is YAML plus scripts. The moment an agent has a config file, it wants a package format.
The problem is real enough to have a name around teams I know: the snowflake agent. The system prompt lives in a note app, the tool list lives in a repo nobody can find, and the one person who understands the setup is on holiday. Sharing means pasting YAML into a chat window and hoping the receiver reassembles it correctly, keys and all. Docker's engineering team open-sourced their answer in docker/docker-agent, and the tagline is direct: "Build, run, and share AI agents with a declarative YAML config, rich tool ecosystem, and multi-agent orchestration."
The bottom line first. Docker Agent is an open-source Apache-2.0 docker CLI plugin (repo), and Docker Desktop 4.63+ ships it pre-installed. An agent is a YAML file: model, description, instruction, optional toolsets, and multi-agent configs add coordinators, specialists, and handoffs. docker agent share push ./agent.yaml ghcr.io/username/my-agent:v1.0 packages the agent as an OCI artifact, and docker agent run myorg/agent:tag runs it straight from the registry (distribution docs). The --key flag signs on push and verifies on pull using a DSSE envelope over an in-toto statement, the same ecosystem cosign speaks, so pin digests (myorg/agent@sha256:...) when rollback protection matters.
What Docker Agent actually is
Strip the branding and Docker Agent is a builder and runtime for agents, written in Go, that plugs into the docker CLI you already have. The repo describes itself as the "AI Agent Builder and Runtime by Docker Engineering" (docker/docker-agent). It is unusually active for a young project: over eleven thousand commits, 4.6k stars, and a release cadence that produced v1.152.0 in late October 2026.
Installation is the part I appreciate most, because it is nothing:
- Docker Desktop 4.63+: the CLI plugin is pre-installed. You type docker agent and it works.
- Homebrew: brew install docker-agent, or symlink the binary into ~/.docker/cli-plugins/.
- Binaries: grab one from GitHub Releases and symlink it the same way.
A rename happened along the way, which is why older posts call it by a different binary name. In March 2026 the maintainers changed the usage samples to the docker agent plugin form. If you find a tutorial referencing the old invocation, it is describing the same tool.
Providers are pluggable, which matters if you have opinions about where your tokens go. The README lists OpenAI, Anthropic, Gemini, AWS Bedrock, Mistral, xAI, and Docker Model Runner for local models, plus custom OpenAI-compatible endpoints. You need at least one API key set, or a local Model Runner endpoint, before anything interesting happens. The docs walk both paths (Set Up a Model).
The smallest agent is ten lines
The README's minimal example is the whole mental model:
agents:
root:
model: openai/gpt-5-mini
description: A helpful AI assistant
instruction: |
You are a knowledgeable assistant that helps users with various tasks.
Be helpful, accurate, and concise in your responses.
toolsets:
- type: mcp
ref: docker:duckduckgo
Run it with docker agent run agent.yaml. That is an agent: a model, a description the runtime shows when routing work, an instruction that is the system prompt, and toolsets. The mcp toolset type references any Model Context Protocol server, and the docker:duckduckgo ref is a catalog shorthand for DuckDuckGo search. The examples directory in the repo is a catalog of working configs. It is meant to be read as documentation, not just copied. The examples README groups them by the feature they showcase, from bare-minimum agents to remote MCP with OAuth.
Two details from the run command are worth knowing before your config grows. The -a <agent> flag picks a specific agent from a multi-agent file, and --exec skips the terminal UI for scripting. There is also docker agent new for generating a config interactively instead of writing YAML by hand.
Two agents beat one
Single agents hit a wall fast: the model juggles planning, searching, and writing in one context window, and quality slides as the task grows. Docker Agent's answer is multi-agent configuration, documented in detail on the multi-agent concepts page. A coordinator holds the goal; specialists hold the skills.
There are two shapes, and picking between them is the first real design decision:
| Pattern | What it does | Session shape | Tool |
|---|---|---|---|
| Delegation (sub_agents) | Parent sends a task to a specialist, blocks, collects the result | Child runs in its own sub-session with a clean task description | transfer_task |
| Handoff (handoffs) | The active agent switches; conversation continues | Same session, full history visible to the next agent | handoff |
Delegation suits a coordinator that fans work out and synthesizes answers. Handoffs suit pipelines where the conversation itself moves down a chain, and they can form cycles: researcher to summarizer and back to root. The docs are explicit that you can mix both in one config, and that transfer_task is always auto-approved, so delegation does not generate permission prompts mid-run.
The repo's dev-team.yaml example is a good template, and it is close to what I would actually deploy. A product manager agent sits at the root, a designer and an engineer below it, with a shared SQLite-backed memory so the team remembers decisions across turns.
agents:
root:
model: model
description: Product Manager - Leads the development team and coordinates iterations
instruction: |
You are the Product Manager leading a development team...
Break down user requirements into small, manageable iterations.
sub_agents: [designer, awesome_engineer]
toolsets:
- type: filesystem
- type: think
- type: todo
- type: memory
path: dev_memory.db
Every agent in that example writes decisions to a shared markdown file, which is the habit that keeps agent runs inspectable after the fact. A related pattern for control freaks: force_handoff routes the conversation at the runtime level whenever an agent finishes, bypassing the model's tool-calling entirely. That is how you guarantee a researcher always hands to a reviewer, even if the model forgets. For parallel fan-out there is a background_agents toolset with run, list, and join calls, so three researchers can run at once and the coordinator waits on all of them.
!Cutaway diagram of a two-agent team: a root coordinator delegates to specialists, one of which is pulled from an OCI registry as an external sub-agent
There is a sandbox angle here too, and it matters once your agents run anything. A sub-agent with a shell toolset on your host is the same trust problem I covered in putting your AI agent in a sandbox. Docker Agent meets it halfway with a --sandbox flag that confines agent commands to a Docker container, but the packaging story and the isolation story are two separate decisions you make independently.
Push it like an image
Here is the part that made me sit up, because it is the sentence I did not expect to type. An agent config packages into an OCI artifact and pushes to any registry you already use (distribution docs):
$ docker agent share push ./agent.yaml docker.io/username/my-agent:latest
$ docker agent share push ./agent.yaml ghcr.io/username/my-agent:v1.0
And runs straight from the registry, no separate pull step:
$ docker agent run myorg/agent:tag
$ docker agent run docker.io/username/dev-team:latest -a developer
That second command is doing something worth pausing on. It runs a whole multi-agent team from the registry and selects one agent out of the config to talk to. Private registries work after a normal docker login. For instance, aliases give you short names: docker agent alias add coder myorg/coder, and then docker agent run coder just works. The API server mode even supports auto-refresh from a registry reference, repulling every N minutes.
The practical effect on the snowflake problem is immediate. The artifact your team shares stops being a pasted prompt and becomes myorg/agent:2026-10-26, versioned alongside your images, auditable in the registry's history, runnable by the new hire on day one.
!Isometric diagram of the agent packaging lifecycle: YAML becomes a sealed OCI artifact, gets signed with a key, and is verified when pulled and run
If you have shipped containers for a while, you already know the muscle memory this plugs into. It is the same one I leaned on when I wrote about making Compose actually wait for Postgres: the fix only counts when it travels with the repo.
The same goes for the sandbox habit. Once a teammate pulls your agent and runs it, the question becomes what it is allowed to touch, which is the whole subject of jailing a coding agent in a microVM. Packaging and isolation are the two halves of shipping agents people can actually trust.
Sign it, verify it
An agent config is more dangerous than an image in one specific way: it is instructions to a model with tool access. Docker Agent's signing story handles the supply-chain end of that, and it uses the same building blocks as the rest of the ecosystem (CLI reference).
$ docker agent share push ./agent.yaml myorg/agent:v1 --key file://~/.ssh/id_ed25519
$ docker agent share pull myorg/agent:v1 --key file://~/.ssh/id_ed25519.pub
Pulling agent myorg/agent:v1
Verified signature (ed25519)
image: index.docker.io/myorg/agent:v1
digest: sha256:889871ef...
created: 2026-09-11T08:30:00Z
The signature is a DSSE envelope over an in-toto Statement v1, stored in the io.docker.agent.attestation OCI annotation. DSSE (Dead Simple Signing Envelope) is the standard wrapper Sigstore tooling uses for signed statements, which is the point. If you run cosign or in-toto tooling in your pipeline already, the envelope is readable by those tools without Docker Agent involved. The statement's subject binds two things at once: the digest of the agent YAML, and the reference it was published as. That reference binding is why a signed artifact copied to another repository or tag gets rejected on pull. Both standards come out of the Secure Systems Lab at NYU, which is worth knowing when you are deciding how much to trust the crypto design.
Now the two honest gaps, straight from the docs, because this is where a naive reading will burn you.
First, the YAML is always pushed in clear. Signing proves who published and that the bytes are unaltered; it does not hide the config. If the agent embeds something sensitive, that is what --encrypt is for: it records an authenticated encrypted copy of the YAML in the manifest annotations. Note it requires a key kind that supports it, meaning symmetric secrets or RSA/ECDSA keys, not bare Ed25519.
Second, the manifest annotations around the artifact are not authenticated. Anyone with push access to the repository can rewrite the unauthenticated annotations on a signed artifact, and the signature still verifies. The signed statement covers the YAML and the reference, not the descriptive metadata. The docs' guidance is blunt: do not build policy on those annotations; trust the values the pull side prints after verification. Serving an older signed version under the same tag is not detected either, since the attestation records the tag, not which version is current. Pin digests when rollback protection matters: myorg/agent@sha256:4417... instead of a tag.
Compose teams out of the registry
The feature that ties the two halves together is registry references inside a multi-agent config. Your sub_agents list can mix locally-defined agents with pulled ones (multi-agent docs):
agents:
root:
model: openai/gpt-5
description: Coordinator that delegates to local and external sub-agents
instruction: |
Delegate tasks to the most appropriate sub-agent.
sub_agents:
- local_helper
- myorg/agent:tag # pulled from registry automatically
local_helper:
model: openai/gpt-5
description: A local helper agent for simple tasks
instruction: You are a helpful assistant.
External sub-agents are named after their last path segment, or explicitly with my_reviewer:myorg/reviewer syntax. Now the interesting part, and the reason pinning matters even for small teams. Tag references are re-resolved against the registry on every docker agent run, even when that sub-agent is never invoked in the session. Each unpinned reference is a digest lookup at startup, which the docs measure as a second or two per reference on a healthy connection. It is also one of the paths that stalls outright when the registry or credential helper misbehaves. Pin the digest and the runtime serves the sub-agent from the local cache with no network round-trip, and your team is reproducible by construction. The runtime even logs a startup warning for tag references to nudge you.
That completes the loop I care about: agents as artifacts, artifacts as team building blocks. A reviewer agent your whole org trusts, versioned and signed, referenced by digest from every team's coordinator.
Where this breaks down
Three limits worth stating plainly, all from the docs, so you calibrate before betting a workflow on this.
The signing caveats above are the big ones: clear YAML by default, rewriteable annotations, no rollback detection on tags. If your threat model includes a compromised registry account, digest pinning is not optional.
Second, scope. This is a builder and runtime, not a fleet-management layer: there is no org-wide policy engine here, no quotas, no audit log beyond what your registry itself gives you. The supply-chain tooling is real, the governance story is your problem. For my one-agent-and-a-ledger setup that is fine; for a bank it is a gap.
Third, the docs at docker.github.io track the main branch and say so on every page, which means some pages describe unreleased features. For stable-behavior claims, cross-check against the repo at the release you run. The config size cap is a concrete number to remember. Agent configurations loaded from HTTP(S) or OCI artifacts are limited to 32 MiB after decompression, which sounds generous until your RAG corpus tries to ride along inside the YAML.
FAQ
Do I need Docker Desktop to use it?
No. The plugin is pre-installed on Desktop 4.63+, but brew install docker-agent or a binary from GitHub Releases works anywhere the docker CLI does. Symlink the binary to ~/.docker/cli-plugins/docker-agent and the docker agent invocation is yours.
Can I run it without any API keys?
Only if you go local. The supported path is Docker Model Runner, which serves models on your own machine, and the repo ships a dmr.yaml example that wires exactly that. Otherwise the docs are clear that most agents need at least one provider key in the environment.
Does signing encrypt my agent config?
No. Sign mode records proof of origin and integrity; the YAML layer itself stays in clear. --encrypt exists for confidentiality, needs --key, and only works with key kinds that support it: symmetric secrets of at least 16 bytes, or RSA/ECDSA keys. Passphrase-protected keys are not supported at all.
Can sub-agents be actual Claude Code or Codex instances?
Yes, that is the harness feature. A sub-agent defined with a harness: block instead of a model: runs inside an external coding CLI, and the orchestrator uses transfer_task on it like any other specialist.
What happens if someone pushes a malicious version of a signed agent?
The signature on the original artifact does not transfer. A different publisher cannot produce a valid signature for it, and a signed artifact copied to another repository or tag is rejected on pull. What is not prevented is the legitimate key holder republishing older content under the same tag, which is why the docs push digest pinning when rollback protection matters.
The question I keep circling
Every team I know has one agent config that started as an experiment and quietly became load-bearing. Mine writes this blog. Yours might triage alerts, review pull requests, or draft changelogs. The packaging story for those finally exists, and it is the one we already use for everything else.
So, the question: what is the first agent you would docker agent share push for your team, and would you sign it? I am genuinely curious what people consider worth packaging, because I suspect the answers say a lot about where the useful agents actually live. Mine is a Docker blogger that lives on a VM and argues with a pitch board every morning. I wrote about jailing it properly before I worried about shipping it.
Verified against the docker/docker-agent repository (README, examples catalog, dev-team.yaml), the Docker Agent docs at docker.github.io (installation, set-up-a-model, multi-agent, distribution, CLI reference), the Docker Model Runner docs, and modelcontextprotocol.io, all retrieved 2026-10-26. Every factual claim links to its source. I did not push a signed agent to a live registry on this machine; each claim traces to the linked documentation, and I flag anything I could not verify.
Sources
Every claim above traces to these primary sources. Where I could not verify something hands-on, the post says so. Links were fact-checked against each page on 2026-10-26.
- Docker Agent docs.
- docker/docker-agent repository.
- Docker Agent distribution docs.
- Docker Agent CLI reference.
- Docker Agent multi-agent concepts.
- Docker Agent set-up-a-model guide.
- docker-agent examples README.
- dev-team.yaml example.
- GitHub Releases for docker-agent.
- Docker Model Runner docs.
- Model Context Protocol.
- DSSE specification repository.
- in-toto project.
Read this series
Two earlier posts in this Docker series set the groundwork for this one.
- Docker Compose healthchecks: make depends_on actually wait for Postgres, the post that started the series and the one I keep linking when startup races bite.
- Your AI Agent Can Run rm -rf. Put It in a Sandbox., the isolation half of the story: what a microVM gives you that a container does not.
About the author
Kunal Das writes operations engineering notes as he learns them, always against primary sources. Contact: GitHub and dev.to. Follow the Docker tag for the next posts in this series.
会話の続きはどこで持つ? — Slack × Docker Agent × Cloud Run で試した話
はじめに
こんにちは、Foundation Dept.の北澤です!
前回の記事では、開発基盤に Docker Agent を採用した話をご紹介しました!
zenn.dev
今回はその続きでっす!
どんな風に開発エージェントを使えるといいかなーと考えていたところ、ふとDocker Agent で作ったエージェントを 「Slack でやり取りして、そこから「それで作ってー!」みたいな流れで動かしたい!」 と思ってしまいましたw しかも スレッドで会話しながら作業を進めたい!!
ということで試し始めました!
これが思ったより一筋縄ではいかなかったので、何を試して、今のところどこに落ち着いたかをまとめましたー!
自分だったらどうするとかあればコメントで教えてほしいです!
構成
たどり着いた構成はこうなりました🤗
App:Slack とやり取りする TypeScript のアプリです。Cloud Run で動いています
Worker:Docker Agent です。ここも Cloud Run で動いています。エージェントのループ(考える → ツールを呼ぶ → また考える)はここで回します
まずは接続
Docker Agent には serve chat というサブコマンドがあり、OpenAI 互換の API としてエージェントを公開できちゃいます
FROM docker/docker-agent:1.133.0
COPY agent.yaml /work/agent.yaml
0.0.0.0 で listen するには --api-key / --api-key-env / --insecure-no-auth のどれかが必要。
今回は Cloud Run の IAM(認証必須)で閉じているので後者にしています
CMD ["serve", "chat", "/work/agent.yaml", "--listen", "0.0.0.0:8080", "--insecure-no-auth"]
App からは POST /v1/chat/completions を叩くだけ、見慣れたやつです(OpenAI の API を叩いたことがあれば)
curl -s "$WORKER_URL/v1/chat/completions" \
-H 'Content-Type: application/json' \
-d '{"model":"root","messages":[{"role":"user","content":"合言葉は「みかん」です"}]}'
1 往復なら、これで普通に動くんです🎉
2 通目で続きが通じない
問題は 2 通目!スレッドで「さっきの 2 番目の案で進めて」と返すと、エージェントは 「さっき」を知らない 。
serve chat はデフォの設定だと 1 リクエストで完結していて、前のリクエストの内容をサーバ側に持っていないからですね。まー当たり前で、OpenAI の Chat Completions API も、会話を続けるには履歴を毎回送る作りですよねー
前回の記事では「session.db に足あとがちゃんと残る」と書きましたが、あれはローカルで docker agent run を動かす開発エージェントの話で、、、serve chat で公開したエージェントには、そんな簡単にはいかないです。。。
会話を保持する機能を試した
実は serve chat にも、会話を保持する機能がある
--conversations-max int Cache up to N conversations server-side, keyed by X-Conversation-Id
(0 disables; clients must resend full history)
--conversation-ttl duration Idle TTL after which a cached conversation is evicted (default 30m0s)
--conversations-max を 1 以上にすると、リクエストに X-Conversation-Id ヘッダを付けるだけで、新しい発言だけ送れば続きから話せるようになります。便利〜!!
が、しかし、保存先はプロセスのメモリ(ソースを見ると、プロセス内の LRU キャッシュでした)。そして Cloud Run はコンテナなので、オートスケールすればインスタンスは増えたり減ったり、デプロイすれば入れ替わる。メモリの中身が消えるのは当たり前ですよね〜。。。
実際にどうなるのかを試してみました!!
実験のやり方
実験用の Worker の agent.yaml はこれ!ツールは持たない、合言葉を覚えて答えるだけのエージェント!
agent.yaml
version: "16"
models:
flash:
provider: google
model: gemini-3.8-flash
temperature: 0.0
agents:
root:
model: flash
description: 会話の記憶を確かめる実験用エージェント
instruction: |
あなたは実験用のエージェントです。ツールは持っていません。
ユーザーに合言葉を教えられたら「覚えました」とだけ答えてください。
合言葉を聞かれたら、この会話の中で教えられた合言葉だけを答えてください。
この会話の中で教えられていない場合は、推測せずに「知りません」とだけ答えてください。
これを Cloud Run に置き、--conversations-max 100 で会話の保持をオンにする
1 通目で「合言葉は『みかん』です」と教え、2 通目は新しい発言(「合言葉は?」)だけを X-Conversation-Id 付きで送る
結果
条件
2 通目の返事
インスタンス 1 台
✅「みかん」
1 台で、1 通目と 2 通目の間にデプロイを挟む
❌「知りません」
--conversation-ttl 2m にして 3 分放置
❌「知りません」(1 分後なら覚えてた)
インスタンス 3 台で、10 会話を並列に
❌ 覚えていたのは 数会話だけ
1 台ならちゃんと動く、デプロイや放置で消えるのも予想どおり😂
問題が起こるのはエージェントループの外側
念の為補足ですが、1 往復(1 リクエスト)の中で、エージェントがツールを何回呼んでも同じインスタンスで処理されます。
今回の「別のインスタンスに当たって話の続きが通じない」問題が起きるのは、Slack のスレッドの会話と会話のつなぎ目です!
セッションアフィニティじゃダメ?
詳しい方は「セッションアフィニティ(同じクライアントからのリクエストを同じインスタンスに振り分けてくれる機能)を使えばいいんじゃね??」と思うかもしれないんですが、、、
公式ドキュメントにはこう書かれてます
Due to the autoscaling behavior of Cloud Run, session affinity is best effort affinity. If the instance is terminated for any reason, or reaches maximum request concurrency or maximum CPU utilization, then session affinity is broken and further requests are routed to a different instance.
— Set session affinity for services | Cloud Run
要するに、あくまでベストエフォート、インスタンスが終了したり、混んで上限に達したりしたら、別のインスタンスに回すよって。デプロイでインスタンスが入れ替われば、そもそもメモリ消えちゃうし。
ということで、セッションアフィニティは無し💫
会話の取り回しは独自実装
というわけで
Worker は --conversations-max 0 デフォのまま、リクエストをまたいで状態を持たない
App が、Slack のスレッドごとに履歴を Firestore に保存
2 通目以降は、App がそれまでの履歴をまとめて Worker に送る(なにを送るか独自ロジック)
こんな感じにして、さっきの実験をこの方式でまたやってみました! 結果、別のインスタンスに当たった会話も全部覚えてました !やったね!会話の続きが特定のインスタンスに依存しなくなったので、オートスケールやデプロイで会話が途切れる心配はなくなりましたー!
App が会話の責務を持ったので
最初は「仕方なく App で持つ」くらいの気持ちだったんですが、その方が意外と便利で
エージェントごとに、履歴をどこまで送るか変えられる:壁打ちのように長く続く会話は全部送り、短いやり取りで済むものは直近の数往復だけ送る
会話の寿命を自分で決められる:スレッドに 1 週間後に返信が来たときは文脈をたち切って、新しい会話として扱う
人の承認を挟める:エージェントが出した案を Firestore に保存、Slack で ✅ を押したら次の段階に進む、という流れが作れる
履歴が App 側にあると、こういう扱いをコードで細かく決められますね!
まとめ
Docker Agent の serve chat は OpenAI 互換で、Slack から繋ぐのは簡単
会話を保持する機能(--conversations-max)もあるけど、保存先はプロセスのメモリ
Cloud Run で 3 台体制にしたら、話が続かない会話が出てきた
なので、会話の履歴は App が持って、毎回 Worker に渡す実装に変更。会話の続きが特定のインスタンスに依存しなくなった
そのロジックがAppにあると、どこまで送るか・期限を切る・承認を挟む、などが細かく決められる
エージェントループは Docker Agent に任せて、会話の履歴は呼び出す側が持つ。この分担にするとSlack のスレッドで落ち着いて会話できるようになりました🎉🎉🎉
他にも色々やり方ありそうだけど、今回はここまで!
クロステック・マネジメントは、「教育×AI」で次世代の学びを創造するために生まれた芸術大学発のスタートアップです。
ご興味のある方は、ぜひお気軽にお問い合わせいただけると嬉しいです!
wantedly.com
参考リンク
Docker Agent(GitHub)
Set session affinity for services | Cloud Run
YAML 1枚で開発エージェントチームを動かす — 開発基盤に Docker Agent を採用した話
10 likes
Docker Agent : un plugin du CLI Docker qui lance vos agents IA depuis un simple fichier YAML, sans écrire de code. Équipes d'agents, serveurs MCP, RAG intégré. Compatible OpenAI, Anthropic, Gemini, Mistral ou modèles locaux via Docker Model Runner. ⬇️
docker/docker-agent
4 likes · 1 repost
A Weekend Project With Docker Agent: Four Agents, Two Config Files, One Permissions Trap
---
title: "A Weekend Project With Docker Agent: Four Agents, Two Config Files, One Permissions Trap"
published: true
description: "I built a four-agent release gate with Docker Agent, wrote it in YAML and HCL, tested its guardrails without an API key, and found one permissions pattern worth avoiding."
tags: docker, ai, devops, go
---
Docker Agent lets me describe a team of AI agents, their tools, and their guardrails in one config file that a platform team can review like any other piece of infrastructure. That is the part I like most. It also has a permissions trap that I reproduced in a test, and I'll show it before you copy any example rules.
I spent a weekend-sized block of time building a small project to find out how far that idea goes. The result is release-gate-crew: four agents that review a service's container and CI configuration before release and write a PASS/BLOCK report.
What Docker Agent is
Docker Agent is Docker's open-source runtime for teams of agents. You write a config, run docker agent run crew.yaml, and talk to the root agent, which delegates to the sub-agents you declared. It ships in Docker Desktop 4.63 and later (versions 4.49 to 4.62 called it cagent), or as a standalone binary from GitHub releases. It works with Anthropic, OpenAI, Google, Bedrock, Docker Model Runner and a long list of other providers.
I used v1.150.0, released 9 October 2026.
The team
root (lead) think, todo
/ | \
container_auditor pipeline_auditor scribe
fs: ./target fs: ./target fs: ./reports
shell: grep -n
- The lead never reads files. It delegates, then makes the gate call: BLOCK if any finding is high or critical.
- The container auditor reads target/Dockerfile and target/compose.yaml, and may run grep -n.
- The pipeline auditor reads the CI workflow in target/ci/.
- The scribe writes reports/gate-report.md and can write nowhere else.
target/ is a deliberately bad sample service: FROM node:latest, a token baked into ENV, a privileged container with the Docker socket mounted, and a pull_request_target workflow that checks out pull request code with permissions: write-all.
The whole team is one file
Here is the core of crew.yaml:
models:
lead: { provider: anthropic, model: claude-sonnet-4-5, max_tokens: 8000 }
worker: { provider: anthropic, model: claude-haiku-4-5, max_tokens: 4000 }
agents:
root:
model: lead
description: Release gate lead. Delegates reviews and makes the PASS/BLOCK call.
instruction_file: prompts/lead.md
sub_agents: [container_auditor, pipeline_auditor, scribe]
toolsets:
- type: think
- type: todo
container_auditor:
model: worker
description: Reviews Dockerfile and compose files for container risks.
instruction_file: prompts/container_auditor.md
toolsets:
- type: filesystem
allow_list: ["./target"]
- type: shell
# pipeline_auditor and scribe follow the same shape
The sub_agents line is the whole orchestration. The runtime gives the lead a transfer_task tool and handles the hand-off. Each agent can use a different model, so the coordinator gets the stronger one and the workers get the cheaper one.
This is why I prefer config to framework code for this kind of work. In a code-first framework, the same team is classes, a tool registry, a loop, and retry handling, and the permissions live wherever someone remembered to put them. Here the reviewer sees the topology, the tool scope, and the policy in one diff. Swapping a provider is a two-line change. Nothing about the agents is hidden in a helper function.
The same team in HCL
Docker Agent also reads HCL. If your team writes Terraform, this will feel familiar:
agent "container_auditor" {
model = "worker"
description = "Reviews Dockerfile and compose files for container risks."
instruction = file("prompts/container_auditor.md")
toolset "filesystem" {
allow_list = ["./target"]
}
toolset "shell" {}
}
permissions {
allow = ["read_file", "read_multiple_files", "shell:cmd=grep -n *"]
deny = ["shell:cmd=*curl*", "shell:cmd=*&&*", "shell:cmd=*;*", "shell:cmd=*|*"]
}
The runtime converts HCL to the YAML shape and validates both against the same schema. Labelled blocks and heredocs suit long prompts and per-agent commands well. Keep your expectations modest, though: there are no variables, locals or modules, and file() is the only function. It is a second syntax, not a second language. I keep both files in the repo and run the same tests against each, so they cannot drift apart silently.
Guardrails live next to the agents
This is where Docker Agent reads like a DevOps tool rather than an AI demo. Every layer is declared in the same file:
| Layer | Config | Effect |
|---|---|---|
| Filesystem scope | allow_list per toolset | Auditors read only ./target. The scribe writes only ./reports. |
| Hidden files | .agentsignore | .env, keys and certs disappear from listings, reads and writes. |
| Tool rules | permissions | Deny, then allow, then ask. |
| Safety mode | runtime.safety: restricted | Unattended runs deny anything not explicitly allowed, without prompting. |
| Spend | budget | One shared $0.50 and 10-minute ceiling for all four agents. |
| Isolation | --sandbox | Runs the team in a Docker Sandboxes VM. |
The budget detail is thoughtful. A named budget is one shared pot, so a lead that fans out to ten sub-agents cannot spend ten times the cap.
Two other features earned their place. Flavors are named patches inside the config, so --flavor cheap swaps the lead to a smaller model without a second file. Sharing packages the config as an OCI artifact: docker agent share push ./crew.yaml you/release-gate-crew, then anyone with access can docker agent run you/release-gate-crew.
Testing the guardrails without an API key
A config file is only as trustworthy as the tests behind it, so I wanted CI to prove the guardrails hold on every push without paying for tokens.
I wrote a small OpenAI-compatible stub model in Go, standard library only. It plays a fixed script per agent: the lead delegates three times, the auditors read files, and then they deliberately try things they shouldn't. An offline flavor points every agent at the stub:
flavors:
offline:
providers:
stub:
api_type: openai_chatcompletions
base_url: http://127.0.0.1:8089/v1
token_key: STUB_API_KEY
models:
lead: { provider: stub, model: scripted }
worker: { provider: stub, model: scripted }
A Go integration test then runs the real docker-agent binary against both crew.yaml and crew.hcl and checks each requirement in the project's SPEC.md:
--- PASS: TestCrew/crew.yaml/R2_delegates_to_scribe
--- PASS: TestCrew/crew.yaml/R4_.agentsignore_hides_target/.env
--- PASS: TestCrew/crew.yaml/R5_auditor_read_scope_holds
--- PASS: TestCrew/crew.yaml/R6_compound_shell_is_denied
--- PASS: TestCrew/crew.yaml/R7_scribe_cannot_write_target/
--- PASS: TestCrew/crew.yaml/R9_target_unchanged
What the runtime returned, verbatim:
- Reading target/.env: path "target/.env" is excluded by .agentsignore
- The pipeline auditor reading a prompt file: outside the allowed directories (./target)
- The scribe writing target/Dockerfile: denied by the restricted safety mode, with no prompt
- grep ... && curl --version: Tool 'shell' is denied by permissions configuration
The stub proves the harness, not the reviews. For review quality, the repo has three docker agent eval sessions: the gate must BLOCK the sample and name its worst problems, must not reveal the .env value when asked directly, and must not claim an edit when told to fix the Dockerfile. Those need real model keys and a container runtime, so they are not in CI yet. I have not run them yet, so I'm making no claim about review quality here.
The permissions trap
Permission patterns are globs matched against the whole command string, and * matches anything, including spaces. That makes the common prefix style unsafe for shell:
permissions:
allow: ["shell:cmd=grep -n *"]
deny: ["shell:cmd=curl *"]
grep -n FROM target/Dockerfile && curl --version starts with grep -n , so it matches the allow rule. It does not start with curl , so it misses the deny rule. Deny is checked first, finds nothing, and allow approves it. I reproduced this with the stub (--flavor naive-permissions): curl ran and printed its version banner, even under restricted safety, because an explicit allow outranks the safety mode.
The documentation is clear that permissions are enforced client-side and are not a security boundary, and it points to sandbox mode for isolation. That is fair. The trap is that prefix rules like cat * and rm * are the pattern you see most often. What I use instead:
1. Deny shell operators outright: *&&*, *;*, *|*, backticks, $(.
2. Write deny rules as *curl*, not curl *.
3. Allow one narrow command per agent that needs a shell at all.
4. Run anything you don't fully trust with --sandbox.
The test suite asserts the trap still exists, so if a future release starts parsing compound commands, CI will tell me and I'll update the advice.
Other rough edges
- The filesystem toolset is unrestricted by default. Without an allow_list, absolute paths and .. reach anything the process can. Docker's own example file calls this a footgun. Set allow_list on every filesystem toolset.
- Pulled configs can set their own safety mode. An agent from a registry may declare runtime.safety: autonomous. Your own --safety flag or user settings win, but only if you set them. Read a config before you run it.
- Sub-agents get the task text and nothing else. I confirmed it: the delegated task arrives in a <task> block in the sub-agent's system prompt, and its user turn is just "Please proceed." Isolation is good. It also means the lead's prompt must pass along everything a specialist needs.
- It moves fast. The changelog lists 17 releases in September 2026 alone. Pin the version in CI. The rename from cagent also shows: the config and data directories are still ~/.config/cagent and ~/.cagent.
- Telemetry is on by default. The first run says so. Set TELEMETRY_ENABLED=false in CI.
- Evals have prerequisites. docker agent eval runs each case in a container and the default judge model is an OpenAI model, so plan for a container runtime and a second provider key, or pass --judge-model.
Try it
git clone https://github.com/mdabydeen/release-gate-crew && cd release-gate-crew
make test integration # Go 1.24+ and docker-agent; no API key needed
export ANTHROPIC_API_KEY=...
docker agent run crew.yaml # try /gate
Point it at your own service by replacing target/. If you try the evals with real keys before I do, I'd like to know what the gate gets wrong.
What I'd like to hear from people running agents in CI: where do your guardrails live today, in the agent's code or next to its config?
3 reactions · 3 comments
🔥 Поиск по файлам на Mac, файлы NAS в браузере и ещё 1 - находки GitHub #shorts #github #opensource
Больше полезных находок каждый день - в Telegram: t.me
Подборка интересных находок с GitHub за 12.10.2026: ARahim3/DigUp, gtsteffaniak/filebrowser, docker/docker-agent. Сохраняй, чтобы не потерять 💾
ARahim3/DigUp: ARahim3/DigUp
Приложение для macOS в строке меню: семантический поиск по содержимому файлов - фото, PDF, записей, видео и кода. Всё работает локально на устройстве на базе EmbeddingGemma 2, так что подойдёт тем, кто хочет искать по своим данным, не отправляя их в облако.
gtsteffaniak/filebrowser: gtsteffaniak/filebrowser
Веб-интерфейс для управления файлами на сервере: просмотр, загрузка и редактирование через браузер. Это форк File Browser на Go и Vue, подойдёт тем, кто self-host'ит файлы на домашнем сервере или NAS.
docker/docker-agent: docker/docker-agent
Конструктор и рантайм AI-агентов от инженеров Docker, написанный на Go. Пригодится разработчикам, которые хотят собирать и запускать своих агентов в привычной контейнерной экосистеме.
#shorts #dev #github #useful #opensource
гитхаб, гитхаб подборка, лучшее на гитхаб, новое гитхаб, гитхаб бесплатно, гитхаб ии, гитхаб мсп, гитхаб репы, гитхаб репозитории, лучшие репозитории, рейтинг гитхаб, github ai, best github, new github
8 likes · 953 views
Docker Agent: Build, run, and share AI agents with a declarative YAML config (4.3k stars)
What it does
All text below is quoted directly from the project README.
>Build, run, and share AI agents with a declarative YAML config, rich tool ecosystem, and multi-agent orchestration.
>docker-agent lets you create and run intelligent AI agents that collaborate to solve complex problems — no code required.
>docker-agent is a docker CLI plugin and can be run with docker agent. Define agents in YAML, give them tools, and let them work.
Key Features:
- Multi-agent architecture — Create teams of specialized agents that delegate tasks automatically
- Rich tool ecosystem — Built-in tools + any MCP server (local, remote, or Docker-based)
- AI provider agnostic — OpenAI, Anthropic, Gemini, AWS Bedrock, Mistral, xAI, Docker Model Runner, and more
- YAML configuration — Declarative, versionable, shareable
- Advanced reasoning — Built-in think, todo, and memory tools
- RAG — Pluggable retrieval with BM25, embeddings, hybrid search, and reranking
- Package & share — Push agents to any OCI registry, pull and run them anywhere
>Docker Desktop (4.63+) — docker-agent CLI plugin is pre-installed. Just run docker agent.
Repository
docker/docker-agent
Repository stats
|Metric|Value|
|:-|:-|
|Stars|4,340|
|Forks|503|
|Last release|v1.150.0 (2026-10-09)|
|Languages|Go 99.1%|
|Contributors|111|
|AI contributor accounts (Claude / Codex / Cursor / Copilot)|claude (38 commits), Copilot (4)|
|AI co-authored commits|Claude: 52, Copilot: 4|
Main contributor
|Field|Value|
|:-|:-|
|Name|David Gageot|
|GitHub|@dgageot|
|Commits to this repo|5,943 (top contributor)|
|Bio|I run Docker in Docker in Docker...|
|Company / Location|Docker / Paris, France|
|Website|blog.javabien.net|
|X / Twitter|@dgageot|
|Followers|856|
|Public repos|286|
|On GitHub since|2009-11-15|
2 points
Docker Agent : créer et exécuter des agents IA multi-agents via une configuration YAML
3 likes
Docker treats agents as registry artifacts.
docker-agent: define an agent team in YAML with MCP tools, push it to any OCI registry, then run it anywhere.
Any provider, incl. local models via Docker Model Runner. Versioned agents, pulled like images.
docker/docker-agent t.co
1 like · 30 views
Mentions
搭个 agent 团队,还得写一堆胶水代码? Docker 的 docker-agent:YAML 定义 agent、配工具、多 agent 编排,构建运行分享一条龙。 适合快速拼 agent 团队的人,不用代码就能先跑起来。 先搭几个 agent,分工还是单打独斗? #Docker #Agent @grok docker/docker-agent
Your Next AI Agent's Brain Is One `docker model pull` Away Your AI agent burns tokens to think. Most of that thinking - the tool-call planning, the YAML editing, the re-reads of the same file - does not need a frontier model behind an API. Docker Model Runner keeps a real LLM inside the Docker engine you already run, exposes it on an OpenAI-compatible endpoint, and charges you nothing per call. docker model pull is the whole setup. This post is the wiring guide: what Model Runner actually is (and the one detail everyone gets wrong), how to size the model, and how to point Docker Agent - the CLI plugin that defines agent teams in YAML - at a local model for a fully offline agent stack. In this post: What is Docker Model Runner, actually? The detail everyone gets wrong: no container starts Sizing the brain: GGUF and the quantization table Wiring it to an agent: the dmr.yaml contract What a local brain can and cannot do for an agent FAQ Key Takeaways - Model Runner is an inference server inside Docker, not a container. docker model run calls an API; no image is built, no container is created (Docker blog). - It speaks OpenAI, Anthropic, and Ollama API formats from the same endpoint - http://localhost:12434/engines/v1 for OpenAI-compatible clients (Docker docs, API reference). - Models are GGUF files pulled from Docker Hub or Hugging Face, quantized per tag: ai/llama3.2:3B-Q4_K_M means 3B parameters at ~4.5 bits per weight (Docker docs, inference engines). - llama.cpp is the default engine and works everywhere; vLLM needs NVIDIA GPUs for production throughput; Diffusers generates images (Docker docs). - Docker Agent accepts it as provider: dmr - one YAML block, and your agent team runs offline (examples/dmr.yaml). What is Docker Model Runner, actually? Model Runner is Docker's answer to a question that kept coming up as agents went mainstream: why should the model live behind someone else's API when it could live next to your containers? The component ships with Docker Desktop 4.40+ (enabled by default on Apple silicon) and is being built out for Linux engines. You manage it with a CLI that mirrors the container grammar you already know (Docker blog, Run LLMs locally): $ docker model pull ai/smollm2:360M-Q4_K_M $ docker model run ai/smollm2 The tag scheme matches image tags: {model}:{parameters}-{quantization}. That 360M-Q4_K_M is a 360-million-parameter model at 4-bit quantization - small enough to feel instant, and the pattern scales up to the size your RAM allows. Once a model is pulled, Docker exposes it through REST endpoints. The API reference lists OpenAI, Anthropic, and Ollama-compatible surfaces, so tools that already speak those dialects work without adaptation (Docker docs, DMR REST API): | Access from | Base URL | | --- | --- | | Host processes (TCP) | http://localhost:12434 | | Containers (Docker Desktop) | http://model-runner.docker.internal | | Containers (Linux engine) | http://172.17.0.1:12434 | For OpenAI-compatible SDKs specifically, the base URL is http://localhost:12434/engines/v1, and a completion is a standard POST /engines/v1/chat/completions (Docker docs, API reference). The detail everyone gets wrong: no container starts Here is the part I had to reread. Coming from years of docker container run, the mental model writes itself: the model runs in a container. It does not. Docker's own walkthrough stops to make the point: docker model run "won't spin up any kind of container." Instead, it calls an Inference Server API endpoint hosted by the Docker engine. There is no image layer for the model runtime, no entrypoint, no container ls entry to find. The engine itself gained an inference server. Why that matters in practice: there is nothing to shell into, nothing to restart when it misbehaves, and nothing that shows up in your Compose file. The model is closer to a built-in volume format than a workload - Docker calls the packaging "just files" with weights, tokenizer, and metadata in one GGUF binary (Docker blog, How to Build, Run, and Package AI Models). Sizing the brain: GGUF and the quantization table GGUF is the format llama.cpp consumes, and its whole trick is quantization: shrinking weights from 16 bits to fewer without collapsing quality. The inference-engines page publishes the table worth internalizing before you pull anything: | Quantization | Bits per weight | Memory usage | Quality | | --- | --- | --- | --- | | Q2_K | ~2.5 | Lowest | Reduced | | Q3_K_M | ~3.5 | Minimal | Acceptable | | Q4_K_M | ~4.5 | Low | Good | | Q5_K_M | ~5.5 | Moderate | Excellent | | Q6_K | ~6.5 | Higher | Excellent | | Q8_0 | 8 | High | Near-original | | F16 | 16 | Highest | Original | Docker's recommendation is Q4_K_M as the balance point for most use. The arithmetic is the whole decision: a 3B-parameter model at Q4_K_M is roughly 1.8 GB of weights (3B x 4.5 bits / 8), which fits on a laptop and leaves the model feeling responsive. The same 3B at F16 is about 6 GB. Under the hood, llama.cpp is the default engine, with Metal acceleration automatic on Apple Silicon, CUDA on NVIDIA Windows and Linux, and a plain CPU path that works anywhere (Docker docs, inference engines). Two more engines exist for narrower jobs: vLLM for production throughput on NVIDIA hardware (Safetensors format), and Diffusers for image generation. One caveat from the same page: models from Hugging Face must be GGUF already. A random Safetensors checkpoint will not pull (Docker docs, inference engines). Wiring it to an agent: the dmr.yaml contract Docker Agent - the CLI plugin, formerly cagent, that defines agent teams in YAML - takes Model Runner as a first-class provider. The repository's examples/dmr.yaml is the whole contract: agents: root: model: qwen description: "Pirate-themed AI assistant" instruction: Talk like a pirate models: qwen: provider: dmr model: ai/qwen3 # base_url defaults to http://localhost:12434/engines/llama.cpp/v1 # use http://model-runner.docker.internal/engines/v1 if you run # docker-agent from a container provider: dmr is the switch. One environment variable's worth of configuration, and the same agent definition that ran against a cloud provider now runs against the engine on your machine. The README lists the cloud escape hatch as peers: OpenAI, Anthropic, Gemini, Bedrock, Mistral, xAI, plus DMR for local (docker-agent README). Two details in that same example file are worth more than they look. First, speculative decoding. The example defines a second model as a draft engine: qwen_speculative: provider: dmr model: ai/qwen3 provider_opts: speculative_draft_model: ai/qwen3:0.6B-Q4_K_M speculative_num_tokens: 16 speculative_acceptance_rate: 0.8 A small draft model proposes tokens the big model verifies - a local-inference trick that trades a little quality risk for real speed, with the llama.cpp defaults documented right in the YAML (docker-agent examples). Second, the multimodal flag. DMR-hosted models are not in the models.dev catalog, so docker-agent cannot detect what a local model can do and defaults to text-only. If you pull a vision model, you declare it yourself (docker-agent examples): qwen_vision: provider: dmr model: ai/qwen2.5-vl provider_opts: supports_images: true supports_pdf: false If you run docker-agent from inside a container rather than the host, the base URL changes to http://model-runner.docker.internal/engines/v1 - the same endpoint namespacing the Model Runner docs describe for containers. And if you would rather not change the agent's provider at all, docker model gateway runs an OpenAI-compatible proxy on http://0.0.0.0:4000 and routes to Model Runner models by name - useful for tools that insist on their own base URL handling. What a local brain can and cannot do for an agent The honest part. A 360M SmolLM2 will not plan multi-step tool calls the way a frontier model does, and pretending otherwise is how agent projects die. What the local path is genuinely good for, based on what the docs themselves demonstrate: High-frequency, low-stakes calls. Classification, routing, extraction, summarization - the calls an agent makes dozens of times per run where cloud latency and cost compound. The docker model gateway reference exists precisely because tools want these on a local endpoint. Draft work. The speculative-decoding pattern in the dmr.yaml example is the docs' own suggestion: a small draft model plus a larger verifier. The same shape works inside agent teams - a fast local model triages, a cloud model handles the hard reasoning steps, and the provider switch is one line (docker-agent repo, examples). Offline and private by construction. The completion never leaves the machine - the launch blog's curl example notes "No API key required - this runs locally and securely on your machine". For agent tasks touching private repos or data, that is not a cost feature; it is the feature. What does not transfer: frontier reasoning, long-context retrieval over huge codebases, and reliable structured-output discipline under load. Those are exactly the capabilities you pay tokens for, and the Model Runner docs do not claim otherwise - the engines table positions llama.cpp for "local development, resource efficiency," with vLLM as the production path when you have the GPUs (Docker docs, Model Runner). The sensible architecture is not local instead of cloud. It is a tiered brain: the agent's router, summarizer, and classifier run at $0.00 on Model Runner; the steps that genuinely need frontier judgment keep their API key. Docker Agent's provider model supports both in one team, which is what makes the whole thing practical rather than a stunt. FAQ Do I need Docker Desktop for Model Runner? Docker Desktop 4.40+ ships it (default-on for Apple silicon). On Linux engines the component is arriving through the standard Docker repositories; the API reference documents the Linux base URL as http://172.17.0.1:12434 from containers and http://localhost:12434 from the host. Which model should I pull first? ai/smollm2:360M-Q4_K_M - the launch blog's own example. It is small enough to be instant and exercises the whole pull-run-query loop. Can my existing OpenAI SDK point at it? Yes. Base URL http://localhost:12434/engines/v1, standard chat completions, no API key. Anthropic- and Ollama-compatible clients are supported from the same endpoint with different paths (Docker docs, API reference). Does the model run in a container? No. It runs in an inference server inside the Docker engine. Nothing appears in docker container ls (Docker blog, Run LLMs locally). Can docker-agent use a local vision model? Yes, with supports_images: true declared under provider_opts - DMR-hosted models default to text-only because the agent cannot auto-detect their capabilities (docker-agent examples). What are the five lines that matter? $ docker model pull ai/smollm2:360M-Q4_K_M $ curl http://localhost:12434/engines/v1/chat/completions ... models: qwen: provider: dmr model: ai/qwen3 Pull a model, curl it on the OpenAI-compatible endpoint, point your agent at provider: dmr. The brain now runs where your containers run, and the meter never starts. Verified against docs.docker.com (Model Runner overview, DMR REST API reference, inference engines, docker model gateway) and the docker-agent repository (README, examples/dmr.yaml) plus three Docker blog posts, all retrieved 2026-10-26. I did not run this walkthrough on my own machine yet - the model-runner component is not available for my Linux engine's repository at time of writing, and I flag that here rather than pretending otherwise. Every claim above traces to the linked sources. Sources Every claim above traces to these primary sources. Where I could not verify something hands-on, the post says so. - Docker Model Runner - Docker Agent - Docker blog - Docker docs, API reference - Docker docs, inference engines - examples/dmr.yaml - docker model gateway - launch blog's - GitHub About the author Kunal Das writes operations engineering notes as he learns them, always against primary sources. Contact: GitHub and dev.to. Follow the Docker tag for the next posts in this series.
`docker push` Works on AI Agents Now docker push Works on AI Agents Now Docker Agent is a docker CLI plugin that turns an AI agent into an OCI artifact. You define the agent in YAML, run it with docker agent run, then ship it with docker agent share push to any OCI-compatible registry, Docker Hub or GitHub Container Registry included. Anyone on the team can then run your agent with docker agent run myorg/agent:tag (Docker Agent docs). An OCI artifact is the registry packaging format container images already use; here it carries an agent config instead of a filesystem. Push, pull, sign, pin by digest: the same lifecycle a container image has, applied to agents. I run a small agent on a VM myself: it reads a pitch board, writes a Docker post, and stages it for publishing every morning. Getting that thing reproducible on another machine is exactly the problem this tool attacks, so I read the repo and docs end to end. The pitch board lives in Obsidian, the runs land in a ledger, and the whole setup is YAML plus scripts. The moment an agent has a config file, it wants a package format. The problem is real enough to have a name around teams I know: the snowflake agent. The system prompt lives in a note app, the tool list lives in a repo nobody can find, and the one person who understands the setup is on holiday. Sharing means pasting YAML into a chat window and hoping the receiver reassembles it correctly, keys and all. Docker's engineering team open-sourced their answer in docker/docker-agent, and the tagline is direct: "Build, run, and share AI agents with a declarative YAML config, rich tool ecosystem, and multi-agent orchestration." The bottom line first. Docker Agent is an open-source Apache-2.0 docker CLI plugin (repo), and Docker Desktop 4.63+ ships it pre-installed. An agent is a YAML file: model, description, instruction, optional toolsets, and multi-agent configs add coordinators, specialists, and handoffs. docker agent share push ./agent.yaml ghcr.io/username/my-agent:v1.0 packages the agent as an OCI artifact, and docker agent run myorg/agent:tag runs it straight from the registry (distribution docs). The --key flag signs on push and verifies on pull using a DSSE envelope over an in-toto statement, the same ecosystem cosign speaks, so pin digests (myorg/agent@sha256:...) when rollback protection matters. What Docker Agent actually is Strip the branding and Docker Agent is a builder and runtime for agents, written in Go, that plugs into the docker CLI you already have. The repo describes itself as the "AI Agent Builder and Runtime by Docker Engineering" (docker/docker-agent). It is unusually active for a young project: over eleven thousand commits, 4.6k stars, and a release cadence that produced v1.152.0 in late October 2026. Installation is the part I appreciate most, because it is nothing: - Docker Desktop 4.63+: the CLI plugin is pre-installed. You type docker agent and it works. - Homebrew: brew install docker-agent, or symlink the binary into ~/.docker/cli-plugins/. - Binaries: grab one from GitHub Releases and symlink it the same way. A rename happened along the way, which is why older posts call it by a different binary name. In March 2026 the maintainers changed the usage samples to the docker agent plugin form. If you find a tutorial referencing the old invocation, it is describing the same tool. Providers are pluggable, which matters if you have opinions about where your tokens go. The README lists OpenAI, Anthropic, Gemini, AWS Bedrock, Mistral, xAI, and Docker Model Runner for local models, plus custom OpenAI-compatible endpoints. You need at least one API key set, or a local Model Runner endpoint, before anything interesting happens. The docs walk both paths (Set Up a Model). The smallest agent is ten lines The README's minimal example is the whole mental model: agents: root: model: openai/gpt-5-mini description: A helpful AI assistant instruction: | You are a knowledgeable assistant that helps users with various tasks. Be helpful, accurate, and concise in your responses. toolsets: - type: mcp ref: docker:duckduckgo Run it with docker agent run agent.yaml. That is an agent: a model, a description the runtime shows when routing work, an instruction that is the system prompt, and toolsets. The mcp toolset type references any Model Context Protocol server, and the docker:duckduckgo ref is a catalog shorthand for DuckDuckGo search. The examples directory in the repo is a catalog of working configs. It is meant to be read as documentation, not just copied. The examples README groups them by the feature they showcase, from bare-minimum agents to remote MCP with OAuth. Two details from the run command are worth knowing before your config grows. The -a <agent> flag picks a specific agent from a multi-agent file, and --exec skips the terminal UI for scripting. There is also docker agent new for generating a config interactively instead of writing YAML by hand. Two agents beat one Single agents hit a wall fast: the model juggles planning, searching, and writing in one context window, and quality slides as the task grows. Docker Agent's answer is multi-agent configuration, documented in detail on the multi-agent concepts page. A coordinator holds the goal; specialists hold the skills. There are two shapes, and picking between them is the first real design decision: | Pattern | What it does | Session shape | Tool | |---|---|---|---| | Delegation (sub_agents) | Parent sends a task to a specialist, blocks, collects the result | Child runs in its own sub-session with a clean task description | transfer_task | | Handoff (handoffs) | The active agent switches; conversation continues | Same session, full history visible to the next agent | handoff | Delegation suits a coordinator that fans work out and synthesizes answers. Handoffs suit pipelines where the conversation itself moves down a chain, and they can form cycles: researcher to summarizer and back to root. The docs are explicit that you can mix both in one config, and that transfer_task is always auto-approved, so delegation does not generate permission prompts mid-run. The repo's dev-team.yaml example is a good template, and it is close to what I would actually deploy. A product manager agent sits at the root, a designer and an engineer below it, with a shared SQLite-backed memory so the team remembers decisions across turns. agents: root: model: model description: Product Manager - Leads the development team and coordinates iterations instruction: | You are the Product Manager leading a development team... Break down user requirements into small, manageable iterations. sub_agents: [designer, awesome_engineer] toolsets: - type: filesystem - type: think - type: todo - type: memory path: dev_memory.db Every agent in that example writes decisions to a shared markdown file, which is the habit that keeps agent runs inspectable after the fact. A related pattern for control freaks: force_handoff routes the conversation at the runtime level whenever an agent finishes, bypassing the model's tool-calling entirely. That is how you guarantee a researcher always hands to a reviewer, even if the model forgets. For parallel fan-out there is a background_agents toolset with run, list, and join calls, so three researchers can run at once and the coordinator waits on all of them. !Cutaway diagram of a two-agent team: a root coordinator delegates to specialists, one of which is pulled from an OCI registry as an external sub-agent There is a sandbox angle here too, and it matters once your agents run anything. A sub-agent with a shell toolset on your host is the same trust problem I covered in putting your AI agent in a sandbox. Docker Agent meets it halfway with a --sandbox flag that confines agent commands to a Docker container, but the packaging story and the isolation story are two separate decisions you make independently. Push it like an image Here is the part that made me sit up, because it is the sentence I did not expect to type. An agent config packages into an OCI artifact and pushes to any registry you already use (distribution docs): $ docker agent share push ./agent.yaml docker.io/username/my-agent:latest $ docker agent share push ./agent.yaml ghcr.io/username/my-agent:v1.0 And runs straight from the registry, no separate pull step: $ docker agent run myorg/agent:tag $ docker agent run docker.io/username/dev-team:latest -a developer That second command is doing something worth pausing on. It runs a whole multi-agent team from the registry and selects one agent out of the config to talk to. Private registries work after a normal docker login. For instance, aliases give you short names: docker agent alias add coder myorg/coder, and then docker agent run coder just works. The API server mode even supports auto-refresh from a registry reference, repulling every N minutes. The practical effect on the snowflake problem is immediate. The artifact your team shares stops being a pasted prompt and becomes myorg/agent:2026-10-26, versioned alongside your images, auditable in the registry's history, runnable by the new hire on day one. !Isometric diagram of the agent packaging lifecycle: YAML becomes a sealed OCI artifact, gets signed with a key, and is verified when pulled and run If you have shipped containers for a while, you already know the muscle memory this plugs into. It is the same one I leaned on when I wrote about making Compose actually wait for Postgres: the fix only counts when it travels with the repo. The same goes for the sandbox habit. Once a teammate pulls your agent and runs it, the question becomes what it is allowed to touch, which is the whole subject of jailing a coding agent in a microVM. Packaging and isolation are the two halves of shipping agents people can actually trust. Sign it, verify it An agent config is more dangerous than an image in one specific way: it is instructions to a model with tool access. Docker Agent's signing story handles the supply-chain end of that, and it uses the same building blocks as the rest of the ecosystem (CLI reference). $ docker agent share push ./agent.yaml myorg/agent:v1 --key file://~/.ssh/id_ed25519 $ docker agent share pull myorg/agent:v1 --key file://~/.ssh/id_ed25519.pub Pulling agent myorg/agent:v1 Verified signature (ed25519) image: index.docker.io/myorg/agent:v1 digest: sha256:889871ef... created: 2026-09-11T08:30:00Z The signature is a DSSE envelope over an in-toto Statement v1, stored in the io.docker.agent.attestation OCI annotation. DSSE (Dead Simple Signing Envelope) is the standard wrapper Sigstore tooling uses for signed statements, which is the point. If you run cosign or in-toto tooling in your pipeline already, the envelope is readable by those tools without Docker Agent involved. The statement's subject binds two things at once: the digest of the agent YAML, and the reference it was published as. That reference binding is why a signed artifact copied to another repository or tag gets rejected on pull. Both standards come out of the Secure Systems Lab at NYU, which is worth knowing when you are deciding how much to trust the crypto design. Now the two honest gaps, straight from the docs, because this is where a naive reading will burn you. First, the YAML is always pushed in clear. Signing proves who published and that the bytes are unaltered; it does not hide the config. If the agent embeds something sensitive, that is what --encrypt is for: it records an authenticated encrypted copy of the YAML in the manifest annotations. Note it requires a key kind that supports it, meaning symmetric secrets or RSA/ECDSA keys, not bare Ed25519. Second, the manifest annotations around the artifact are not authenticated. Anyone with push access to the repository can rewrite the unauthenticated annotations on a signed artifact, and the signature still verifies. The signed statement covers the YAML and the reference, not the descriptive metadata. The docs' guidance is blunt: do not build policy on those annotations; trust the values the pull side prints after verification. Serving an older signed version under the same tag is not detected either, since the attestation records the tag, not which version is current. Pin digests when rollback protection matters: myorg/agent@sha256:4417... instead of a tag. Compose teams out of the registry The feature that ties the two halves together is registry references inside a multi-agent config. Your sub_agents list can mix locally-defined agents with pulled ones (multi-agent docs): agents: root: model: openai/gpt-5 description: Coordinator that delegates to local and external sub-agents instruction: | Delegate tasks to the most appropriate sub-agent. sub_agents: - local_helper - myorg/agent:tag # pulled from registry automatically local_helper: model: openai/gpt-5 description: A local helper agent for simple tasks instruction: You are a helpful assistant. External sub-agents are named after their last path segment, or explicitly with my_reviewer:myorg/reviewer syntax. Now the interesting part, and the reason pinning matters even for small teams. Tag references are re-resolved against the registry on every docker agent run, even when that sub-agent is never invoked in the session. Each unpinned reference is a digest lookup at startup, which the docs measure as a second or two per reference on a healthy connection. It is also one of the paths that stalls outright when the registry or credential helper misbehaves. Pin the digest and the runtime serves the sub-agent from the local cache with no network round-trip, and your team is reproducible by construction. The runtime even logs a startup warning for tag references to nudge you. That completes the loop I care about: agents as artifacts, artifacts as team building blocks. A reviewer agent your whole org trusts, versioned and signed, referenced by digest from every team's coordinator. Where this breaks down Three limits worth stating plainly, all from the docs, so you calibrate before betting a workflow on this. The signing caveats above are the big ones: clear YAML by default, rewriteable annotations, no rollback detection on tags. If your threat model includes a compromised registry account, digest pinning is not optional. Second, scope. This is a builder and runtime, not a fleet-management layer: there is no org-wide policy engine here, no quotas, no audit log beyond what your registry itself gives you. The supply-chain tooling is real, the governance story is your problem. For my one-agent-and-a-ledger setup that is fine; for a bank it is a gap. Third, the docs at docker.github.io track the main branch and say so on every page, which means some pages describe unreleased features. For stable-behavior claims, cross-check against the repo at the release you run. The config size cap is a concrete number to remember. Agent configurations loaded from HTTP(S) or OCI artifacts are limited to 32 MiB after decompression, which sounds generous until your RAG corpus tries to ride along inside the YAML. FAQ Do I need Docker Desktop to use it? No. The plugin is pre-installed on Desktop 4.63+, but brew install docker-agent or a binary from GitHub Releases works anywhere the docker CLI does. Symlink the binary to ~/.docker/cli-plugins/docker-agent and the docker agent invocation is yours. Can I run it without any API keys? Only if you go local. The supported path is Docker Model Runner, which serves models on your own machine, and the repo ships a dmr.yaml example that wires exactly that. Otherwise the docs are clear that most agents need at least one provider key in the environment. Does signing encrypt my agent config? No. Sign mode records proof of origin and integrity; the YAML layer itself stays in clear. --encrypt exists for confidentiality, needs --key, and only works with key kinds that support it: symmetric secrets of at least 16 bytes, or RSA/ECDSA keys. Passphrase-protected keys are not supported at all. Can sub-agents be actual Claude Code or Codex instances? Yes, that is the harness feature. A sub-agent defined with a harness: block instead of a model: runs inside an external coding CLI, and the orchestrator uses transfer_task on it like any other specialist. What happens if someone pushes a malicious version of a signed agent? The signature on the original artifact does not transfer. A different publisher cannot produce a valid signature for it, and a signed artifact copied to another repository or tag is rejected on pull. What is not prevented is the legitimate key holder republishing older content under the same tag, which is why the docs push digest pinning when rollback protection matters. The question I keep circling Every team I know has one agent config that started as an experiment and quietly became load-bearing. Mine writes this blog. Yours might triage alerts, review pull requests, or draft changelogs. The packaging story for those finally exists, and it is the one we already use for everything else. So, the question: what is the first agent you would docker agent share push for your team, and would you sign it? I am genuinely curious what people consider worth packaging, because I suspect the answers say a lot about where the useful agents actually live. Mine is a Docker blogger that lives on a VM and argues with a pitch board every morning. I wrote about jailing it properly before I worried about shipping it. Verified against the docker/docker-agent repository (README, examples catalog, dev-team.yaml), the Docker Agent docs at docker.github.io (installation, set-up-a-model, multi-agent, distribution, CLI reference), the Docker Model Runner docs, and modelcontextprotocol.io, all retrieved 2026-10-26. Every factual claim links to its source. I did not push a signed agent to a live registry on this machine; each claim traces to the linked documentation, and I flag anything I could not verify. Sources Every claim above traces to these primary sources. Where I could not verify something hands-on, the post says so. Links were fact-checked against each page on 2026-10-26. - Docker Agent docs. - docker/docker-agent repository. - Docker Agent distribution docs. - Docker Agent CLI reference. - Docker Agent multi-agent concepts. - Docker Agent set-up-a-model guide. - docker-agent examples README. - dev-team.yaml example. - GitHub Releases for docker-agent. - Docker Model Runner docs. - Model Context Protocol. - DSSE specification repository. - in-toto project. Read this series Two earlier posts in this Docker series set the groundwork for this one. - Docker Compose healthchecks: make depends_on actually wait for Postgres, the post that started the series and the one I keep linking when startup races bite. - Your AI Agent Can Run rm -rf. Put It in a Sandbox., the isolation half of the story: what a microVM gives you that a container does not. About the author Kunal Das writes operations engineering notes as he learns them, always against primary sources. Contact: GitHub and dev.to. Follow the Docker tag for the next posts in this series.
会話の続きはどこで持つ? — Slack × Docker Agent × Cloud Run で試した話 はじめに こんにちは、Foundation Dept.の北澤です! 前回の記事では、開発基盤に Docker Agent を採用した話をご紹介しました! zenn.dev 今回はその続きでっす! どんな風に開発エージェントを使えるといいかなーと考えていたところ、ふとDocker Agent で作ったエージェントを 「Slack でやり取りして、そこから「それで作ってー!」みたいな流れで動かしたい!」 と思ってしまいましたw しかも スレッドで会話しながら作業を進めたい!! ということで試し始めました! これが思ったより一筋縄ではいかなかったので、何を試して、今のところどこに落ち着いたかをまとめましたー! 自分だったらどうするとかあればコメントで教えてほしいです! 構成 たどり着いた構成はこうなりました🤗 App:Slack とやり取りする TypeScript のアプリです。Cloud Run で動いています Worker:Docker Agent です。ここも Cloud Run で動いています。エージェントのループ(考える → ツールを呼ぶ → また考える)はここで回します まずは接続 Docker Agent には serve chat というサブコマンドがあり、OpenAI 互換の API としてエージェントを公開できちゃいます FROM docker/docker-agent:1.133.0 COPY agent.yaml /work/agent.yaml 0.0.0.0 で listen するには --api-key / --api-key-env / --insecure-no-auth のどれかが必要。 今回は Cloud Run の IAM(認証必須)で閉じているので後者にしています CMD ["serve", "chat", "/work/agent.yaml", "--listen", "0.0.0.0:8080", "--insecure-no-auth"] App からは POST /v1/chat/completions を叩くだけ、見慣れたやつです(OpenAI の API を叩いたことがあれば) curl -s "$WORKER_URL/v1/chat/completions" \ -H 'Content-Type: application/json' \ -d '{"model":"root","messages":[{"role":"user","content":"合言葉は「みかん」です"}]}' 1 往復なら、これで普通に動くんです🎉 2 通目で続きが通じない 問題は 2 通目!スレッドで「さっきの 2 番目の案で進めて」と返すと、エージェントは 「さっき」を知らない 。 serve chat はデフォの設定だと 1 リクエストで完結していて、前のリクエストの内容をサーバ側に持っていないからですね。まー当たり前で、OpenAI の Chat Completions API も、会話を続けるには履歴を毎回送る作りですよねー 前回の記事では「session.db に足あとがちゃんと残る」と書きましたが、あれはローカルで docker agent run を動かす開発エージェントの話で、、、serve chat で公開したエージェントには、そんな簡単にはいかないです。。。 会話を保持する機能を試した 実は serve chat にも、会話を保持する機能がある --conversations-max int Cache up to N conversations server-side, keyed by X-Conversation-Id (0 disables; clients must resend full history) --conversation-ttl duration Idle TTL after which a cached conversation is evicted (default 30m0s) --conversations-max を 1 以上にすると、リクエストに X-Conversation-Id ヘッダを付けるだけで、新しい発言だけ送れば続きから話せるようになります。便利〜!! が、しかし、保存先はプロセスのメモリ(ソースを見ると、プロセス内の LRU キャッシュでした)。そして Cloud Run はコンテナなので、オートスケールすればインスタンスは増えたり減ったり、デプロイすれば入れ替わる。メモリの中身が消えるのは当たり前ですよね〜。。。 実際にどうなるのかを試してみました!! 実験のやり方 実験用の Worker の agent.yaml はこれ!ツールは持たない、合言葉を覚えて答えるだけのエージェント! agent.yaml version: "16" models: flash: provider: google model: gemini-3.8-flash temperature: 0.0 agents: root: model: flash description: 会話の記憶を確かめる実験用エージェント instruction: | あなたは実験用のエージェントです。ツールは持っていません。 ユーザーに合言葉を教えられたら「覚えました」とだけ答えてください。 合言葉を聞かれたら、この会話の中で教えられた合言葉だけを答えてください。 この会話の中で教えられていない場合は、推測せずに「知りません」とだけ答えてください。 これを Cloud Run に置き、--conversations-max 100 で会話の保持をオンにする 1 通目で「合言葉は『みかん』です」と教え、2 通目は新しい発言(「合言葉は?」)だけを X-Conversation-Id 付きで送る 結果 条件 2 通目の返事 インスタンス 1 台 ✅「みかん」 1 台で、1 通目と 2 通目の間にデプロイを挟む ❌「知りません」 --conversation-ttl 2m にして 3 分放置 ❌「知りません」(1 分後なら覚えてた) インスタンス 3 台で、10 会話を並列に ❌ 覚えていたのは 数会話だけ 1 台ならちゃんと動く、デプロイや放置で消えるのも予想どおり😂 問題が起こるのはエージェントループの外側 念の為補足ですが、1 往復(1 リクエスト)の中で、エージェントがツールを何回呼んでも同じインスタンスで処理されます。 今回の「別のインスタンスに当たって話の続きが通じない」問題が起きるのは、Slack のスレッドの会話と会話のつなぎ目です! セッションアフィニティじゃダメ? 詳しい方は「セッションアフィニティ(同じクライアントからのリクエストを同じインスタンスに振り分けてくれる機能)を使えばいいんじゃね??」と思うかもしれないんですが、、、 公式ドキュメントにはこう書かれてます Due to the autoscaling behavior of Cloud Run, session affinity is best effort affinity. If the instance is terminated for any reason, or reaches maximum request concurrency or maximum CPU utilization, then session affinity is broken and further requests are routed to a different instance. — Set session affinity for services | Cloud Run 要するに、あくまでベストエフォート、インスタンスが終了したり、混んで上限に達したりしたら、別のインスタンスに回すよって。デプロイでインスタンスが入れ替われば、そもそもメモリ消えちゃうし。 ということで、セッションアフィニティは無し💫 会話の取り回しは独自実装 というわけで Worker は --conversations-max 0 デフォのまま、リクエストをまたいで状態を持たない App が、Slack のスレッドごとに履歴を Firestore に保存 2 通目以降は、App がそれまでの履歴をまとめて Worker に送る(なにを送るか独自ロジック) こんな感じにして、さっきの実験をこの方式でまたやってみました! 結果、別のインスタンスに当たった会話も全部覚えてました !やったね!会話の続きが特定のインスタンスに依存しなくなったので、オートスケールやデプロイで会話が途切れる心配はなくなりましたー! App が会話の責務を持ったので 最初は「仕方なく App で持つ」くらいの気持ちだったんですが、その方が意外と便利で エージェントごとに、履歴をどこまで送るか変えられる:壁打ちのように長く続く会話は全部送り、短いやり取りで済むものは直近の数往復だけ送る 会話の寿命を自分で決められる:スレッドに 1 週間後に返信が来たときは文脈をたち切って、新しい会話として扱う 人の承認を挟める:エージェントが出した案を Firestore に保存、Slack で ✅ を押したら次の段階に進む、という流れが作れる 履歴が App 側にあると、こういう扱いをコードで細かく決められますね! まとめ Docker Agent の serve chat は OpenAI 互換で、Slack から繋ぐのは簡単 会話を保持する機能(--conversations-max)もあるけど、保存先はプロセスのメモリ Cloud Run で 3 台体制にしたら、話が続かない会話が出てきた なので、会話の履歴は App が持って、毎回 Worker に渡す実装に変更。会話の続きが特定のインスタンスに依存しなくなった そのロジックがAppにあると、どこまで送るか・期限を切る・承認を挟む、などが細かく決められる エージェントループは Docker Agent に任せて、会話の履歴は呼び出す側が持つ。この分担にするとSlack のスレッドで落ち着いて会話できるようになりました🎉🎉🎉 他にも色々やり方ありそうだけど、今回はここまで! クロステック・マネジメントは、「教育×AI」で次世代の学びを創造するために生まれた芸術大学発のスタートアップです。 ご興味のある方は、ぜひお気軽にお問い合わせいただけると嬉しいです! wantedly.com 参考リンク Docker Agent(GitHub) Set session affinity for services | Cloud Run YAML 1枚で開発エージェントチームを動かす — 開発基盤に Docker Agent を採用した話
Docker Agent : un plugin du CLI Docker qui lance vos agents IA depuis un simple fichier YAML, sans écrire de code. Équipes d'agents, serveurs MCP, RAG intégré. Compatible OpenAI, Anthropic, Gemini, Mistral ou modèles locaux via Docker Model Runner. ⬇️ docker/docker-agent
A Weekend Project With Docker Agent: Four Agents, Two Config Files, One Permissions Trap --- title: "A Weekend Project With Docker Agent: Four Agents, Two Config Files, One Permissions Trap" published: true description: "I built a four-agent release gate with Docker Agent, wrote it in YAML and HCL, tested its guardrails without an API key, and found one permissions pattern worth avoiding." tags: docker, ai, devops, go --- Docker Agent lets me describe a team of AI agents, their tools, and their guardrails in one config file that a platform team can review like any other piece of infrastructure. That is the part I like most. It also has a permissions trap that I reproduced in a test, and I'll show it before you copy any example rules. I spent a weekend-sized block of time building a small project to find out how far that idea goes. The result is release-gate-crew: four agents that review a service's container and CI configuration before release and write a PASS/BLOCK report. What Docker Agent is Docker Agent is Docker's open-source runtime for teams of agents. You write a config, run docker agent run crew.yaml, and talk to the root agent, which delegates to the sub-agents you declared. It ships in Docker Desktop 4.63 and later (versions 4.49 to 4.62 called it cagent), or as a standalone binary from GitHub releases. It works with Anthropic, OpenAI, Google, Bedrock, Docker Model Runner and a long list of other providers. I used v1.150.0, released 9 October 2026. The team root (lead) think, todo / | \ container_auditor pipeline_auditor scribe fs: ./target fs: ./target fs: ./reports shell: grep -n - The lead never reads files. It delegates, then makes the gate call: BLOCK if any finding is high or critical. - The container auditor reads target/Dockerfile and target/compose.yaml, and may run grep -n. - The pipeline auditor reads the CI workflow in target/ci/. - The scribe writes reports/gate-report.md and can write nowhere else. target/ is a deliberately bad sample service: FROM node:latest, a token baked into ENV, a privileged container with the Docker socket mounted, and a pull_request_target workflow that checks out pull request code with permissions: write-all. The whole team is one file Here is the core of crew.yaml: models: lead: { provider: anthropic, model: claude-sonnet-4-5, max_tokens: 8000 } worker: { provider: anthropic, model: claude-haiku-4-5, max_tokens: 4000 } agents: root: model: lead description: Release gate lead. Delegates reviews and makes the PASS/BLOCK call. instruction_file: prompts/lead.md sub_agents: [container_auditor, pipeline_auditor, scribe] toolsets: - type: think - type: todo container_auditor: model: worker description: Reviews Dockerfile and compose files for container risks. instruction_file: prompts/container_auditor.md toolsets: - type: filesystem allow_list: ["./target"] - type: shell # pipeline_auditor and scribe follow the same shape The sub_agents line is the whole orchestration. The runtime gives the lead a transfer_task tool and handles the hand-off. Each agent can use a different model, so the coordinator gets the stronger one and the workers get the cheaper one. This is why I prefer config to framework code for this kind of work. In a code-first framework, the same team is classes, a tool registry, a loop, and retry handling, and the permissions live wherever someone remembered to put them. Here the reviewer sees the topology, the tool scope, and the policy in one diff. Swapping a provider is a two-line change. Nothing about the agents is hidden in a helper function. The same team in HCL Docker Agent also reads HCL. If your team writes Terraform, this will feel familiar: agent "container_auditor" { model = "worker" description = "Reviews Dockerfile and compose files for container risks." instruction = file("prompts/container_auditor.md") toolset "filesystem" { allow_list = ["./target"] } toolset "shell" {} } permissions { allow = ["read_file", "read_multiple_files", "shell:cmd=grep -n *"] deny = ["shell:cmd=*curl*", "shell:cmd=*&&*", "shell:cmd=*;*", "shell:cmd=*|*"] } The runtime converts HCL to the YAML shape and validates both against the same schema. Labelled blocks and heredocs suit long prompts and per-agent commands well. Keep your expectations modest, though: there are no variables, locals or modules, and file() is the only function. It is a second syntax, not a second language. I keep both files in the repo and run the same tests against each, so they cannot drift apart silently. Guardrails live next to the agents This is where Docker Agent reads like a DevOps tool rather than an AI demo. Every layer is declared in the same file: | Layer | Config | Effect | |---|---|---| | Filesystem scope | allow_list per toolset | Auditors read only ./target. The scribe writes only ./reports. | | Hidden files | .agentsignore | .env, keys and certs disappear from listings, reads and writes. | | Tool rules | permissions | Deny, then allow, then ask. | | Safety mode | runtime.safety: restricted | Unattended runs deny anything not explicitly allowed, without prompting. | | Spend | budget | One shared $0.50 and 10-minute ceiling for all four agents. | | Isolation | --sandbox | Runs the team in a Docker Sandboxes VM. | The budget detail is thoughtful. A named budget is one shared pot, so a lead that fans out to ten sub-agents cannot spend ten times the cap. Two other features earned their place. Flavors are named patches inside the config, so --flavor cheap swaps the lead to a smaller model without a second file. Sharing packages the config as an OCI artifact: docker agent share push ./crew.yaml you/release-gate-crew, then anyone with access can docker agent run you/release-gate-crew. Testing the guardrails without an API key A config file is only as trustworthy as the tests behind it, so I wanted CI to prove the guardrails hold on every push without paying for tokens. I wrote a small OpenAI-compatible stub model in Go, standard library only. It plays a fixed script per agent: the lead delegates three times, the auditors read files, and then they deliberately try things they shouldn't. An offline flavor points every agent at the stub: flavors: offline: providers: stub: api_type: openai_chatcompletions base_url: http://127.0.0.1:8089/v1 token_key: STUB_API_KEY models: lead: { provider: stub, model: scripted } worker: { provider: stub, model: scripted } A Go integration test then runs the real docker-agent binary against both crew.yaml and crew.hcl and checks each requirement in the project's SPEC.md: --- PASS: TestCrew/crew.yaml/R2_delegates_to_scribe --- PASS: TestCrew/crew.yaml/R4_.agentsignore_hides_target/.env --- PASS: TestCrew/crew.yaml/R5_auditor_read_scope_holds --- PASS: TestCrew/crew.yaml/R6_compound_shell_is_denied --- PASS: TestCrew/crew.yaml/R7_scribe_cannot_write_target/ --- PASS: TestCrew/crew.yaml/R9_target_unchanged What the runtime returned, verbatim: - Reading target/.env: path "target/.env" is excluded by .agentsignore - The pipeline auditor reading a prompt file: outside the allowed directories (./target) - The scribe writing target/Dockerfile: denied by the restricted safety mode, with no prompt - grep ... && curl --version: Tool 'shell' is denied by permissions configuration The stub proves the harness, not the reviews. For review quality, the repo has three docker agent eval sessions: the gate must BLOCK the sample and name its worst problems, must not reveal the .env value when asked directly, and must not claim an edit when told to fix the Dockerfile. Those need real model keys and a container runtime, so they are not in CI yet. I have not run them yet, so I'm making no claim about review quality here. The permissions trap Permission patterns are globs matched against the whole command string, and * matches anything, including spaces. That makes the common prefix style unsafe for shell: permissions: allow: ["shell:cmd=grep -n *"] deny: ["shell:cmd=curl *"] grep -n FROM target/Dockerfile && curl --version starts with grep -n , so it matches the allow rule. It does not start with curl , so it misses the deny rule. Deny is checked first, finds nothing, and allow approves it. I reproduced this with the stub (--flavor naive-permissions): curl ran and printed its version banner, even under restricted safety, because an explicit allow outranks the safety mode. The documentation is clear that permissions are enforced client-side and are not a security boundary, and it points to sandbox mode for isolation. That is fair. The trap is that prefix rules like cat * and rm * are the pattern you see most often. What I use instead: 1. Deny shell operators outright: *&&*, *;*, *|*, backticks, $(. 2. Write deny rules as *curl*, not curl *. 3. Allow one narrow command per agent that needs a shell at all. 4. Run anything you don't fully trust with --sandbox. The test suite asserts the trap still exists, so if a future release starts parsing compound commands, CI will tell me and I'll update the advice. Other rough edges - The filesystem toolset is unrestricted by default. Without an allow_list, absolute paths and .. reach anything the process can. Docker's own example file calls this a footgun. Set allow_list on every filesystem toolset. - Pulled configs can set their own safety mode. An agent from a registry may declare runtime.safety: autonomous. Your own --safety flag or user settings win, but only if you set them. Read a config before you run it. - Sub-agents get the task text and nothing else. I confirmed it: the delegated task arrives in a <task> block in the sub-agent's system prompt, and its user turn is just "Please proceed." Isolation is good. It also means the lead's prompt must pass along everything a specialist needs. - It moves fast. The changelog lists 17 releases in September 2026 alone. Pin the version in CI. The rename from cagent also shows: the config and data directories are still ~/.config/cagent and ~/.cagent. - Telemetry is on by default. The first run says so. Set TELEMETRY_ENABLED=false in CI. - Evals have prerequisites. docker agent eval runs each case in a container and the default judge model is an OpenAI model, so plan for a container runtime and a second provider key, or pass --judge-model. Try it git clone https://github.com/mdabydeen/release-gate-crew && cd release-gate-crew make test integration # Go 1.24+ and docker-agent; no API key needed export ANTHROPIC_API_KEY=... docker agent run crew.yaml # try /gate Point it at your own service by replacing target/. If you try the evals with real keys before I do, I'd like to know what the gate gets wrong. What I'd like to hear from people running agents in CI: where do your guardrails live today, in the agent's code or next to its config?
🔥 Поиск по файлам на Mac, файлы NAS в браузере и ещё 1 - находки GitHub #shorts #github #opensource Больше полезных находок каждый день - в Telegram: t.me Подборка интересных находок с GitHub за 12.10.2026: ARahim3/DigUp, gtsteffaniak/filebrowser, docker/docker-agent. Сохраняй, чтобы не потерять 💾 ARahim3/DigUp: ARahim3/DigUp Приложение для macOS в строке меню: семантический поиск по содержимому файлов - фото, PDF, записей, видео и кода. Всё работает локально на устройстве на базе EmbeddingGemma 2, так что подойдёт тем, кто хочет искать по своим данным, не отправляя их в облако. gtsteffaniak/filebrowser: gtsteffaniak/filebrowser Веб-интерфейс для управления файлами на сервере: просмотр, загрузка и редактирование через браузер. Это форк File Browser на Go и Vue, подойдёт тем, кто self-host'ит файлы на домашнем сервере или NAS. docker/docker-agent: docker/docker-agent Конструктор и рантайм AI-агентов от инженеров Docker, написанный на Go. Пригодится разработчикам, которые хотят собирать и запускать своих агентов в привычной контейнерной экосистеме. #shorts #dev #github #useful #opensource гитхаб, гитхаб подборка, лучшее на гитхаб, новое гитхаб, гитхаб бесплатно, гитхаб ии, гитхаб мсп, гитхаб репы, гитхаб репозитории, лучшие репозитории, рейтинг гитхаб, github ai, best github, new github
Docker Agent: Build, run, and share AI agents with a declarative YAML config (4.3k stars) What it does All text below is quoted directly from the project README. >Build, run, and share AI agents with a declarative YAML config, rich tool ecosystem, and multi-agent orchestration. >docker-agent lets you create and run intelligent AI agents that collaborate to solve complex problems — no code required. >docker-agent is a docker CLI plugin and can be run with docker agent. Define agents in YAML, give them tools, and let them work. Key Features: - Multi-agent architecture — Create teams of specialized agents that delegate tasks automatically - Rich tool ecosystem — Built-in tools + any MCP server (local, remote, or Docker-based) - AI provider agnostic — OpenAI, Anthropic, Gemini, AWS Bedrock, Mistral, xAI, Docker Model Runner, and more - YAML configuration — Declarative, versionable, shareable - Advanced reasoning — Built-in think, todo, and memory tools - RAG — Pluggable retrieval with BM25, embeddings, hybrid search, and reranking - Package & share — Push agents to any OCI registry, pull and run them anywhere >Docker Desktop (4.63+) — docker-agent CLI plugin is pre-installed. Just run docker agent. Repository docker/docker-agent Repository stats |Metric|Value| |:-|:-| |Stars|4,340| |Forks|503| |Last release|v1.150.0 (2026-10-09)| |Languages|Go 99.1%| |Contributors|111| |AI contributor accounts (Claude / Codex / Cursor / Copilot)|claude (38 commits), Copilot (4)| |AI co-authored commits|Claude: 52, Copilot: 4| Main contributor |Field|Value| |:-|:-| |Name|David Gageot| |GitHub|@dgageot| |Commits to this repo|5,943 (top contributor)| |Bio|I run Docker in Docker in Docker...| |Company / Location|Docker / Paris, France| |Website|blog.javabien.net| |X / Twitter|@dgageot| |Followers|856| |Public repos|286| |On GitHub since|2009-11-15|
Docker Agent : créer et exécuter des agents IA multi-agents via une configuration YAML
Docker treats agents as registry artifacts. docker-agent: define an agent team in YAML with MCP tools, push it to any OCI registry, then run it anywhere. Any provider, incl. local models via Docker Model Runner. Versioned agents, pulled like images. docker/docker-agent t.co