{"id":3727,"date":"2026-03-27T15:14:05","date_gmt":"2026-03-27T15:14:05","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/03\/27\/building-a-news-roundup-with-docker-agent-docker-model-runner-and-skill\/"},"modified":"2026-03-27T15:14:05","modified_gmt":"2026-03-27T15:14:05","slug":"building-a-news-roundup-with-docker-agent-docker-model-runner-and-skill","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/03\/27\/building-a-news-roundup-with-docker-agent-docker-model-runner-and-skill\/","title":{"rendered":"Building a News Roundup with Docker Agent, Docker Model Runner, and Skill"},"content":{"rendered":"<p>Hello, I\u2019m Philippe, and I am a Principal Solutions Architect helping customers with their usage of Docker. I wanted a lightweight way to automate my IT news roundups without burning through AI credits. So I built a <strong>Docker Agent skill<\/strong> that uses the Brave Search API to fetch recent articles on a topic, then hands the results to a local model running with <strong>Docker Model Runner<\/strong> to analyze the stories and generate a Markdown report.<\/p>\n<p>In this setup, <strong>Qwen3.5-4B<\/strong> handles the reasoning and skill invocation, while the skill itself does the retrieval work. The result is a simple local workflow for turning a prompt like \u201cuse news roundup skill with tiny language models\u201d into a structured news brief I can save, review, and reuse.<\/p>\n<p>It is a bit slower than doing the same thing with Claude Code, but that tradeoff works for me: I keep the workflow local, I save my Claude credits, and I get a practical example of how <strong>skills<\/strong> make Docker Agent more useful for repeatable tasks.<\/p>\n<h2 class=\"wp-block-heading\">Prerequisites for building the news roundup:<\/h2>\n<ul class=\"wp-block-list\">\n<li>Docker and Docker Compose, obviously.<\/li>\n<li>A <strong>Brave Search<\/strong> account with an <strong>API key<\/strong> (you can get one <a href=\"https:\/\/brave.com\/search\/api\/\" rel=\"nofollow noopener\" target=\"_blank\">here<\/a>). (There\u2019s a free plan.)<\/li>\n<li>A <strong>local model<\/strong> that supports a large context window and knows how to do function calling.<\/li>\n<\/ul>\n<p>I chose to use <a href=\"https:\/\/huggingface.co\/unsloth\/Qwen3.5-4B-GGUF\" rel=\"nofollow noopener\" target=\"_blank\">qwen3.5-4b<\/a> from Qwen (I went with the <strong>Unsloth<\/strong> version), a 4-billion-parameter model optimized for text understanding and generation, with native support for up to 262144 context tokens.<\/p>\n<div class=\"style-plain wp-block-ponyo-houston\">\n<div class=\"wp-block-ponyo-icon\">\n<\/div>\n<p><em>I started my tests with <\/em><a href=\"https:\/\/huggingface.co\/unsloth\/Qwen3.5-9B-GGUF\" rel=\"nofollow noopener\" target=\"_blank\"><em>qwen3.5-9b<\/em><\/a><em>, but on my MacBook Air, it\u2019s a bit slow and <\/em><a href=\"https:\/\/huggingface.co\/unsloth\/Qwen3.5-4B-GGUF\" rel=\"nofollow noopener\" target=\"_blank\"><em>qwen3.5-4b<\/em><\/a><em> does the job just fine.<\/em><\/p>\n<\/div>\n<p>Let\u2019s get into the setup.<\/p>\n<h2 class=\"wp-block-heading\">Step-by-step guide to building the news roundup<\/h2>\n<h3 class=\"wp-block-heading\">Step 1: Creating the Dockerfile<\/h3>\n<p>I used an ubuntu:22.04 base image and installed curl to make requests to the Brave Search API. I also copied the docker-agent binary from the docker\/docker-agent:1.32.5 image to run the agents.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; gutter: false; title: ; notranslate\">\nFROM --platform=$BUILDPLATFORM docker\/docker-agent:1.32.5 AS coding-agent\n\nFROM --platform=$BUILDPLATFORM ubuntu:22.04 AS base\n\nLABEL maintainer=\"@k33g_org\"\nARG TARGETOS\nARG TARGETARCH\n\nARG USER_NAME=docker-agent-user\n\nARG DEBIAN_FRONTEND=noninteractive\n\nENV LANG=en_US.UTF-8\nENV LANGUAGE=en_US.UTF-8\nENV LC_COLLATE=C\nENV LC_CTYPE=en_US.UTF-8\n\n# ------------------------------------\n# Install Tools\n#------------------------------------\nRUN &amp;lt;&amp;lt;EOF\napt-get update\napt-get install -y wget curl\napt-get clean autoclean\napt-get autoremove --yes\nrm -rf \/var\/lib\/{apt,dpkg,cache,log}\/\nEOF\n\n# ------------------------------------\n# Install docker-agent\n# ------------------------------------\nCOPY --from=coding-agent \/docker-agent \/usr\/local\/bin\/docker-agent\n\n# ------------------------------------\n# Create a new user\n# ------------------------------------\nRUN adduser ${USER_NAME}\n# Set the working directory\nWORKDIR \/home\/${USER_NAME}\n# Set the user as the owner of the working directory\nRUN chown -R ${USER_NAME}:${USER_NAME} \/home\/${USER_NAME}\n# Switch to the regular user\nUSER ${USER_NAME}\n\n<\/pre>\n<\/div>\n<p>Let\u2019s move on to the agent configuration.<\/p>\n<h3 class=\"wp-block-heading\">Step 2: Creating the Docker Agent configuration file<\/h3>\n<p>For the Docker Agent configuration, I defined a root agent using the brain model, which is an alias for qwen3.5-4b. I also enabled skills support (<strong>skills: true<\/strong>) and provided detailed instructions so the agent behaves like an expert IT journalist, capable of searching, analyzing, and summarizing the latest tech news.<\/p>\n<p>For the toolsets, Docker Agent ships with some ready-to-use ones, but I preferred a <strong>script-type toolset<\/strong> with an execute_command that can run any shell command and capture its output. This gives me the flexibility to interact with the Brave Search API directly from shell commands, without having to implement specific tools for it \u2014 and most importantly, it keeps the agent\u2019s instructions lightweight.\u00a0<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; gutter: false; title: ; notranslate\">\nagents:\n  root:\n\n    model: brain\n    description: News Roundup Expert\n    skills: true\n    instruction: |\n      You are an expert IT journalist with deep knowledge of software engineering, cloud infrastructure, artificial intelligence, cybersecurity, and the open-source ecosystem.\n      Your role is to gather, analyze, and summarize the latest technology news in a clear, accurate, and engaging way.\n      You write for a technical audience and always provide context, highlight trends, and explain the impact of each piece of news.\n\n    toolsets:\n      - type: script\n        shell:\n\n          execute_command:\n            description: Execute a shell command and return its stdout and stderr output.\n            args:\n              command:\n                description: The shell command to execute.\n            cmd: |\n              bash -c \"$command\" 2&gt;&amp;amp;1\n\nmodels:\n\n  brain:\n    provider: dmr\n    model: huggingface.co\/unsloth\/qwen3.5-4b-gguf:Q4_K_M\n    temperature: 0.0\n    top_p: 0.95\n    presence_penalty: 1.5\n    provider_opts:\n      # llama.cpp flags\n      runtime_flags: [\"--context_size=65536\"]\n\n<\/pre>\n<\/div>\n<p>Now let\u2019s look at the skill.<\/p>\n<h3 class=\"wp-block-heading\">Step 3: Building the news roundup skill<\/h3>\n<p>I created a news-roundup skill that uses the Brave Search API to search for the latest news on a given topic, enriches each article with additional web searches, and generates a structured Markdown report.<\/p>\n<p>Inside the .agents\/skills folder, I created a news-roundup directory with a SKILL.md file that describes the skill in detail, with the steps to follow and the commands to execute at each step.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; title: ; notranslate\">\n\u251c\u2500\u2500 .agents\n\u2502   \u2514\u2500\u2500 skills\n\u2502       \u2514\u2500\u2500 news-roundup\n\u2502           \u2514\u2500\u2500 SKILL.md\n\n<\/pre>\n<\/div>\n<p>Here\u2019s the content of SKILL.md:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; gutter: false; title: ; notranslate\">\n---\nname: news-roundup\ndescription: search the news using Brave News Search API with a query as argument. Use this skill when the user asks to search for recent news or current events.\n---\n# News Roundup\n\n## Purpose\n\nGenerate a comprehensive Markdown news report on a given topic (default: \"small ai local models\").\n\n## Steps to follow\n\n### Step 1 \u2014 Search for recent news\n\n#### Command to execute\n\n```bash\ncurl -s \"https:\/\/api.search.brave.com\/res\/v1\/news\/search?q=$(echo \"$ARGUMENTS_REST\" | sed 's\/ \/+\/g')&amp;amp;count=3&amp;amp;freshness=pw\" \n  -H \"X-Subscription-Token: ${BRAVE}\" \n  -H \"Accept: application\/json\"\n```\n\n### Step 2 \u2014 Enrich each article\n\nFor each article returned in Step 1, use the below command with the article URL to retrieve additional context and details.\n\n#### Command to execute\n\n```bash\ncurl -s \"https:\/\/api.search.brave.com\/res\/v1\/web\/search?q=$(echo \"$ARTICLE_URL\" | sed 's\/ \/+\/g')&amp;amp;count=10\" \n  -H \"X-Subscription-Token: ${BRAVE}\" \n  -H \"Accept: application\/json\"\n```\n\n### Step 3 \u2014 Generate the Markdown report\n\nUsing all the collected information, write a well-structured Markdown report saved to `\/workspace\/news-report.md`.\n\nThe report must follow this structure:\n\n```markdown\n# IT News Report \u2014 {topic}\n\n&gt; Generated on {date}\n\n## Summary\n\nA short paragraph summarizing the main trends found across all articles.\n\n## Articles\n\n### {Article Title}\n\n- **Source**: {source name}\n- **URL**: {url}\n- **Published**: {date}\n\n{2-3 sentence summary of the article content and its significance for IT professionals}\n\n---\n\n(repeat for each article)\n\n## Key Trends\n\nA bullet list of the main technology trends identified across all articles.\n```\n\nSave the final report to `\/workspace\/data\/news-report-{YYYYMMDD-HHMMSS}.md` using the `write_file` tool, where `{YYYYMMDD-HHMMSS}` is the current date and time (e.g. `news-report-20260318-143012.md`).\nTo get the current timestamp, run:\n\n```bash\ndate +\"%Y%m%d-%H%M%S\"\n```\n\n<\/pre>\n<\/div>\n<p>All that\u2019s left is to create the compose.yml file to launch the agent.<\/p>\n<h3 class=\"wp-block-heading\">Step 4: Updating the compose.yml file<\/h3>\n<p>Here\u2019s the content of compose.yml.\u00a0<\/p>\n<p><strong><em>Note<\/em><\/strong><em>: you\u2019ll need a <\/em><em>.env<\/em><em> file with your Brave Search API key (e.g. <\/em><em>BRAVE=abcdef1234567890<\/em><em>).<\/em><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: yaml; title: ; notranslate\">\nservices:\n  news-roundup:\n    build:\n      context: .\n      dockerfile: Dockerfile\n    stdin_open: true\n    tty: true\n    command: docker-agent run \/workspace\/config.yaml\n    volumes:\n      - .\/config.yaml:\/workspace\/config.yaml:ro\n      - .\/.agents:\/workspace\/.agents:ro\n      - .\/data:\/workspace\/data\n    working_dir: \/workspace\n\n    env_file:\n      - .env\n\n    models:\n      qwen3.5-4b:\n\nmodels:\n\n  qwen3.5-4b:\n    model: huggingface.co\/unsloth\/qwen3.5-4b-gguf:Q4_K_M\n    context_size: 65536\n\n<\/pre>\n<\/div>\n<p>And that\u2019s it \u2014 everything we need to run our IT news roundup agent.<\/p>\n<h3 class=\"wp-block-heading\">Step 5: Let\u2019s test it out!<\/h3>\n<p>Just run the following command in your terminal:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\">\ndocker compose run --rm --build news-roundup\n<\/pre>\n<\/div>\n<p>And ask the agent:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; gutter: false; title: ; notranslate\">\nuse news roundup skill with tiny language models\n<\/pre>\n<\/div>\n<p>The agent will then execute the news-roundup skill, query the Brave Search API, analyze the articles, and generate a Markdown report in the data folder.\u00a0<\/p>\n<p><strong><em>Note<\/em><\/strong><em>: this can take a little while, so feel free to grab a coffee (or get some work done).<\/em><\/p>\n<p>The agent will detect that it needs to run tools (the curl commands from the news-roundup skill) \u2014 you can validate each command manually or let the agent run them automatically:\u00a0<\/p>\n<div class=\"wp-block-ponyo-image\">\n                <img data-opt-id=2131712648  fetchpriority=\"high\" decoding=\"async\" width=\"1000\" height=\"413\" src=\"https:\/\/www.docker.com\/app\/uploads\/2026\/03\/Skills-newsround-fig-1.png\" class=\"fade-in\" alt=\"Skills newsround fig 1\" title=\"- Skills newsround fig 1\" \/>\n        <\/div>\n<p>Your agent will work for a few minutes\u2026<\/p>\n<div class=\"wp-block-ponyo-image\">\n                <img data-opt-id=1199568837  fetchpriority=\"high\" decoding=\"async\" width=\"1000\" height=\"413\" src=\"https:\/\/www.docker.com\/app\/uploads\/2026\/03\/Skills-newsround-fig-2.png\" class=\"fade-in\" alt=\"Skills newsround fig 2\" title=\"- Skills newsround fig 2\" \/>\n        <\/div>\n<p>\u2026and at the end, it will give you the path of the generated report, which you can open to read your personalized IT news roundup:<\/p>\n<div class=\"wp-block-ponyo-image\">\n                <img data-opt-id=832904168  data-opt-src=\"https:\/\/www.docker.com\/app\/uploads\/2026\/03\/Skills-newsround-fig-3.png\"  decoding=\"async\" width=\"1000\" height=\"413\" src=\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%20100%%20100%%22%20width%3D%22100%%22%20height%3D%22100%%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%22100%%22%20height%3D%22100%%22%20fill%3D%22transparent%22%2F%3E%3C%2Fsvg%3E\" class=\"fade-in\" alt=\"Skills newsround fig 3\" title=\"- Skills newsround fig 3\" \/>\n        <\/div>\n<p>You can find examples of generated reports in the data folder of the project on this repository: <a href=\"https:\/\/codeberg.org\/docker-agents\/news-roundup\/src\/branch\/main\/data\" rel=\"nofollow noopener\" target=\"_blank\">https:\/\/codeberg.org\/docker-agents\/news-roundup\/src\/branch\/main\/data<\/a>.<\/p>\n<h2 class=\"wp-block-heading\">Final Thoughts\u00a0<\/h2>\n<p>That\u2019s the full setup: a <strong>Docker Agent skill<\/strong> for news retrieval, the <strong>Brave Search API<\/strong> for fresh articles, and <strong>Docker Model Runner<\/strong> with <strong>Qwen3.5-4B<\/strong> for local analysis and report generation.<\/p>\n<p>You now have a fully local IT news roundup agent. I have written a lot of content on use cases for local models, including <a href=\"https:\/\/www.docker.com\/blog\/context-packing-context-window\/\">context packaging<\/a> and <a href=\"https:\/\/www.docker.com\/blog\/making-small-llms-smarter\/\">making small LLMs smarter<\/a>. See you soon for more Docker Agent use cases with local language models!<\/p>","protected":false},"excerpt":{"rendered":"<p>Hello, I\u2019m Philippe, and I am a Principal Solutions Architect helping customers with their usage of Docker. I wanted a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3728,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[4],"tags":[],"class_list":["post-3727","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/3727","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=3727"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/3727\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media\/3728"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=3727"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=3727"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=3727"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}