<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[arconsis - Medium]]></title>
        <description><![CDATA[Software engineering enthusiasts I With great passion we develop high quality software solutions - Medium]]></description>
        <link>https://medium.com/arconsis?source=rss----c3dfaac5c9ee---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>arconsis - Medium</title>
            <link>https://medium.com/arconsis?source=rss----c3dfaac5c9ee---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 13 Nov 2026 19:24:01 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/arconsis" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[A week in Superset, a day in MotherDuck Dives]]></title>
            <link>https://medium.com/arconsis/a-week-in-superset-a-day-in-motherduck-dives-c9fd3f1f3267?source=rss----c3dfaac5c9ee---4</link>
            <guid isPermaLink="false">https://medium.com/p/c9fd3f1f3267</guid>
            <category><![CDATA[motherduck]]></category>
            <category><![CDATA[dive]]></category>
            <category><![CDATA[apache-superset]]></category>
            <category><![CDATA[bi-dashboards]]></category>
            <category><![CDATA[data-storytelling]]></category>
            <dc:creator><![CDATA[Ana Milutinovic]]></dc:creator>
            <pubDate>Thu, 05 Nov 2026 12:26:52 GMT</pubDate>
            <atom:updated>2026-11-05T12:26:51.485Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E3ULsHLmuzm0o8KB86Mv7g.png" /></figure><p>I recently built the same kind of dashboard twice, once as custom Apache Superset plugins and once as a MotherDuck Dive. This article compares the effort and shows how I built the Dive. The numbers come from one test, so read them as my results, not as a benchmark.</p><p><strong>TL;DR</strong></p><ul><li>Superset needed five custom plugins, 30+ prompt revisions, 8+ hours to a first working plugin, and a Kubernetes redeployment for every change.</li><li>The Dive needed 2 prompt revisions and half an hour to a first working version. The finished dashboard took about a day, including learning the tool.</li><li>The result depends on the data: mine was a golden layer, one flat table with joins and metrics already done. Multiple raw tables are untested.</li><li>For customer proposals, a Dive on anonymized data can turn an idea into a clickable demo within a day.</li></ul><h3>Where I’m coming from</h3><p>I’m a Data Visualisation Specialist at <a href="https://www.arconsis.com/">arconsis</a>. I build dashboards for customers, in the tools they already have, the tools they ask for, or the tool I believe fits their needs best.</p><p>I started in Tableau and have also worked with Power BI and GoodData. I tested Metabase, Lightdash, and Fastero. For an internal project, I built custom React visualization plugins for Apache Superset, because the existing charts did not cover what we needed.</p><p>I found MotherDuck by accident. I wanted a quick way to load a test CSV and explore it in Lightdash. Then I saw Dives and the prompt library behind them (<a href="https://motherduck.com/dive-gallery/">MotherDuck Dives</a>). My first reaction was “what the heck?” A few days later I tried it.</p><p>Others have already tested MotherDuck’s speed. Artefact’s benchmark, for example, compares query and dashboard performance on Superset against BigQuery and PostgreSQL (<a href="https://medium.com/artefact-engineering-and-data-science/motherduck-explained-how-it-fits-into-your-data-stack-with-benchmarks-e41c308ebbd4">MotherDuck Explained</a>). Artefact is a MotherDuck launch partner in Europe, so read it as partner content. I looked at something different: how much effort it takes to build the dashboard.</p><h3>The starting point</h3><p>The data was one flat table: a CSV exported from PostgreSQL, with all joins and metrics already calculated. In other words, a golden layer, which is the best case for an agent. This matters for the comparison. The agent did not have to find join paths or decide how a metric is defined.</p><h3>What Dives are</h3><p>Dives are interactive visualizations you create with natural language, directly on top of your data in MotherDuck. You ask an AI agent, and it generates a persistent component that lives in your workspace next to your SQL.</p><p>Technically, a Dive is a React component. It uses a hook called useSQLQuery to run SQL against your MotherDuck databases, Recharts for the charts, and Tailwind CSS for styling. The component queries live data, so a reload always shows current numbers.</p><p>That is the same React and SQL stack I already use for Superset plugins, without the plugin plumbing.</p><h3>The Superset way: one week</h3><p><strong>The goal:</strong> two tables with four-level dropdowns, plus a pivot table where users add columns interactively and pick them from dropdowns.</p><p><strong>Why custom plugins:</strong> the existing Superset charts did not cover three things:</p><ul><li><strong>Drill-down:</strong> the existing table options did not offer it.</li><li><strong>A flexible pivot:</strong> the existing pivot table did not let users freely add columns and rows, so they could not adjust the report on the go.</li><li><strong>A branded header and footer:</strong> I wanted a page with the company branding, showing the customer name and the date range selected in the filters. A chart that pulls both from a dataset that includes the company branding is not something the existing charts offer, so I built one.</li></ul><p><strong>What it took:</strong> five custom React plugins, built with five agents:</p><ul><li><strong>Analytics:</strong> clarifies the data and the questions the dashboard must answer</li><li><strong>Design:</strong> knows all of the company’s design rules and constraints, from logo usage to colors, typography, and tone</li><li><strong>UI:</strong> writes the React plugin</li><li><strong>Grill:</strong> challenges the result and looks for weaknesses</li><li><strong>Judge:</strong> decides whether it is ready to ship</li></ul><p><strong>The numbers:</strong></p><ul><li>30+ revisions of the Superset prompt</li><li>8+ hours until the first plugin ran</li><li>one week until the tables and the pivot were usable</li></ul><p>After that came the manual work:</p><ul><li>add the plugin to the dashboard by hand</li><li>set up every filter</li><li>find a workaround for the date filter</li><li>apply the company design and logo in Superset itself</li><li>choose the right chart type</li></ul><p>On production, every change and every new plugin meant redeploying Superset on Kubernetes. That is part of working with open source: you control everything, and you also run everything. I’m not complaining, I’m showing what it takes to build something like this.</p><p><strong>Why it matters:</strong> each change cost a round of build, deploy, and manual testing. For a small request like an additional button, that is a lot of overhead.</p><h3>The Dives way: two revisions</h3><h4>Setup</h4><p>Connect an AI client to the MotherDuck MCP server. With Claude Code, it is one command:</p><pre>claude mcp add MotherDuck --transport http https://api.motherduck.com/mcp</pre><p>Ask explicitly for a Dive, for example “create a Dive” or “save this as a Dive in MotherDuck”. Otherwise the agent may create a chart without saving it as one.</p><h4>The prompt</h4><p>I wrote one prompt in plain English, using a sample prompt with eight sections as the structure.</p><p>The design rules I had given a whole agent in Superset became two sections in this prompt: Visual design and Wording.</p><p>Here is the full sample prompt. Copy it, fill in what applies, and skip the rest.</p><pre>DIVE: &lt;name&gt;<br>DATA<br>- Source: &lt;database.schema.table, or several tables and how they join&gt;<br>- One row is: &lt;what a single record represents&gt;<br>- Key columns:<br>  - &lt;column&gt;: &lt;meaning, unit, allowed values&gt;<br>  - &lt;value with special meaning&gt;: &lt;how to treat it&gt;<br>- Leave out: &lt;columns, values or records to ignore&gt;<br>- Sensitive data: &lt;fields to hide, aggregate or never show&gt;<br>- Data quirks: &lt;known gaps, duplicates, odd formats, update frequency&gt;</pre><pre>AUDIENCE AND PURPOSE<br>- Who uses it: &lt;role, device, how often&gt;<br>- Questions it must answer:<br>  - &lt;question 1&gt;<br>  - &lt;question 2&gt;<br>  - &lt;question 3&gt;<br>- Level of detail: &lt;aggregate only | individual records allowed&gt;</pre><pre>STRUCTURE<br>- Tabs (about 3, split bigger ideas into separate Dives):<br>  - &lt;tab 1&gt;: &lt;metrics, charts, tables&gt;<br>  - &lt;tab 2&gt;: &lt;metrics, charts, tables&gt;<br>- Default state: &lt;time range, preselected filters, landing tab&gt;</pre><pre>FILTERS AND INTERACTION<br>- Filters: &lt;dimensions, single or multi-select, with search&gt;<br>- Click behavior: &lt;drill down or cross-filter, what happens&gt;<br>- Filters in shared link: &lt;yes | no&gt;<br>- Other: &lt;search, sorting, keyboard shortcuts, detail panels&gt;</pre><pre>VISUAL DESIGN<br>- Theme: &lt;light | dark | both | special style&gt;<br>- Colors (hex): primary &lt;...&gt;, accent &lt;...&gt;, neutrals &lt;...&gt;<br>- Fonts: &lt;...&gt;<br>- Icons: &lt;style, e.g. line icons only&gt;<br>- Logo: &lt;file or none&gt;<br>- Accessibility: &lt;e.g. contrast at least 4.5:1, respect reduced motion&gt;</pre><pre>WORDING<br>- Tone: &lt;e.g. neutral, friendly, formal&gt;<br>- Rules: &lt;style rules, terms to use or avoid&gt;<br>- Empty and loading states: &lt;what they should say&gt;</pre><pre>EXPORTS<br>- Format: &lt;format, or none&gt;<br>- File naming: &lt;e.g. include active filters&gt;</pre><pre>OUT OF SCOPE<br>- &lt;what not to build or show&gt;</pre><p>The sample prompt does the thinking up front. The more the agent knows about the people and the questions, the more it gets right on its own.</p><h4>The result</h4><p>The Dive had three tabs, working filters, and the fun facts and notes in the style I defined under Wording.</p><p>It also had something I never asked for: a clickable pop-up with the details behind each number. The prompt described the audience and their questions, and the Dive added drill-down on its own. That is the request I have heard in every BI tool I have used, and here it was already there.</p><p><strong>The numbers:</strong></p><ul><li>2 revisions of the prompt</li><li>0.5 hours until the first working version</li><li>about a day until the finished dashboard, including learning the tool</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BS71CFB8ZaJnKHAd-ow_ug.png" /><figcaption>Mission Control</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ly4FGOwmXd7Iy-SJqrYP3Q.png" /></figure><h4>Adjusting the code</h4><p>A Dive is plain React and SQL, so I could open it and change it. There is also a Git-based workflow for developing, previewing, and deploying Dives as code. In my test, a change showed up as soon as I saved it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aDBDZ51H8ew1xWu4C0Nebg.png" /></figure><h4>Restyling</h4><p>For fun, I asked for a terminal theme. I wrote a detailed prompt, but a sentence like “make it terminal style” also works. It took around 3 minutes. The prompt changed only the look and wording. The data and structure stayed the same.</p><p>My prompt uses the same structure as the sample above:</p><pre>THEME: Terminal mode for this Dive<br>TASK<br>- Add a theme toggle with two options: &quot;Standard&quot; and &quot;Terminal mode&quot;<br>- Store the selected theme in useDiveState<br>- Keep data and filters the same, change only the look and wording</pre><pre>DATA CHECK<br>- Inspect the Dive&#39;s data and identify:<br>  - measure: &lt;main metric, e.g. hours, revenue, orders&gt;<br>  - dimensions: &lt;main filters, e.g. customer, region, product&gt;<br>  - date: &lt;date column&gt;<br>  - detail: &lt;detail or text column, if any&gt;<br>- Use the real column names in lowercase snake_case</pre><pre>VISUAL DESIGN<br>- Fonts: JetBrains Mono or IBM Plex Mono (Google Fonts), everywhere<br>- Colors (hex): background #000000, primary text &lt;default #5e7dff&gt;,<br>  secondary text #88898c, highlights #FFFFFF<br>- Accent: &lt;default #fc3e46&gt;, used for one highlight badge only<br>- Effects: subtle CRT scanlines, slight text glow, blinking block<br>  cursor after the last line of each panel<br>- Panels: terminal windows with a thin border and a title bar<br>  e.g. &quot;● ● ●  user@&lt;dive-name&gt;:~/&lt;measure&gt;&quot;<br>- Shape: no rounded corners, no shadows, 1px borders #404044</pre><pre>BOOT SEQUENCE<br>- Show on first load for about 1.5 seconds, skippable on click:<br>    &gt; booting &lt;dive-name&gt; v1.0 ...<br>    &gt; connecting to motherduck ........ [ OK ]<br>    &gt; loading &lt;table&gt; ................. [ OK ] &lt;row count&gt; rows<br>    &gt; agents online ................... [ OK ]<br>    &gt; welcome. &lt;optional tagline&gt;</pre><pre>FILTERS AS COMMANDS<br>- Show active filters as a live command line that updates with the dropdowns:<br>    $ &lt;measure&gt; --&lt;dimension_1&gt;=&quot;Value A&quot; --&lt;date&gt;=2026-01..2026-06<br>- Allow typing: one flag per filter, applied on enter<br>- Unknown flags: friendly &quot;command not found&quot;, hint &quot;try: help&quot;<br>- help: print the available flags<br>- clear: reset all filters</pre><pre>OVERVIEW<br>- KPIs as aligned key/value lines:<br>    &lt;measure&gt;_total ..... 1,240.0<br>    records ............. 3,412<br>- ASCII bar charts for the top 2 dimensions:<br>    Value A  ████████████████░░░░  42%  520.5<br>- Summary as a log line:<br>    [INFO] &lt;period&gt; · &lt;total&gt; &lt;measure&gt; across &lt;n&gt; &lt;dimension_1&gt;s<br>- Fun translations as [FUN] lines, if they fit the measure<br>  e.g. hours to working weeks, revenue to coffees</pre><pre>LOGS<br>- Detail rows as log lines, newest at the bottom, auto-scroll:<br>    &lt;date&gt;  &lt;dimension_1&gt;  &lt;dimension_2&gt;  &lt;measure&gt;  &quot;&lt;detail&gt;&quot;<br>- Search box styled as &quot;grep: ▌&quot;, matches highlighted<br>- Click on a line: expand the full record</pre><pre>TABLES AND PIVOTS<br>- Section title as a command e.g. &quot;$ pivot&quot;<br>- Controls as CLI flags: --rows=... --cols=... --values=...<br>- Monospace table with aligned columns, totals row separated by &quot;────&quot;<br>- Download button labelled &quot;$ export --format=csv&quot;</pre><pre>EASTER EGGS<br>- sudo coffee: prints &quot;☕ permission granted.&quot;<br>- whoami: prints &quot;operator of &lt;dive-name&gt;&quot;<br>- matrix: brief falling characters in the primary color, then back to normal</pre><pre>EMPTY STATES<br>- No results: &quot;[WARN] 0 results for this filter.&quot;<br>- No search match: &quot;grep: no matches. try a broader search.&quot;</pre><pre>WORDING<br>- Tone: short, neutral, slightly informal<br>- Rules: aggregates only, no rankings of individual people</pre><pre>ACCESSIBILITY<br>- Contrast at least 4.5:1<br>- Respect prefers-reduced-motion: skip boot animation, glow and matrix effect</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LEiYPsbkfQ-Rl7b-dfAMJg.png" /><figcaption>Terminal Style Mission Control</figcaption></figure><p>In Superset, a restyle means CSS work or a rebuild. Here it was one prompt.</p><h4>A fair comparison</h4><p>These numbers are not a lab test. Superset needed custom plugins and a deployment pipeline. The Dive came with a sample prompt and a prepared data layer. The Superset week covered two drill-down tables, an interactive pivot, and a branded header and footer. Both are honest timelines of what I actually spent.</p><h3>Why a golden layer matters</h3><p>Everything I read pointed in the same direction: Dives work best on a golden layer, meaning data that is already cleaned, joined, and defined before the agent sees it. My own result fits that. With one flat table where joins and metrics were already done, the first working version took half an hour, and the quality surprised me.</p><p>The reason is simple. The agent does not have to guess join paths or decide how a metric is defined, so there is less room for wrong numbers. MotherDuck’s own tests on a small question set point the same way: agents with good context make far fewer query errors. That is the vendor’s benchmark, not independent proof, so treat it as a hint.</p><p><strong>What this means in practice:</strong> put the effort into the data layer first, and the prompt second.</p><h3>What my test did not cover</h3><p>My data was a single flat CSV, uploaded by hand. That is the easy case for an agent.</p><p><strong>Flights.</strong> Flights are scheduled Python jobs that run inside MotherDuck. An agent connected to the MCP server can write the pipeline, create the Flight, and schedule it. I did not need them for this test. If the data has to refresh on a schedule, that is where Flights would come in. They are in public preview, so check their status first.</p><p><strong>Guides and the semantic layer.</strong> MotherDuck’s answer to the semantic layer question is Guides: versioned markdown documents stored in the warehouse that give agents business context, such as what a column means and how tables relate. With a pre-joined table, I had no need for them. How a Dive behaves across several raw tables is still untested.</p><p><strong>Why it matters:</strong> a golden layer made my result possible. Multiple raw tables will be the real test, and I plan to try that next.</p><h3>Where Dives fit, and where they don’t</h3><ul><li><strong>Cloud only.</strong> MotherDuck is cloud infrastructure. It runs in AWS regions across the US, Europe, and Asia Pacific, including Frankfurt and Dublin in Europe. You choose the region when you create the organization, and you cannot change it afterward. If data must stay on premises, it is not an option.</li><li><strong>Access control.</strong> MotherDuck has role-based access control. I only looked at it briefly, so check the documentation for how it applies to Dives. MotherDuck is SOC 2 Type II and GDPR compliant, with HIPAA BAAs available on request for Business plan customers.</li><li><strong>Cost.</strong> Pricing is pay-as-you-go. The Lite plan has no platform fee and includes 10 compute unit hours and 10 GB of storage per month. It is limited to the smallest instance type and 3 users. The Business plan costs $250 per month plus usage. Dives are available on all plans at no extra charge, while embedding needs Business.</li><li><strong>Workflow.</strong> You switch between your AI client and the browser, which does not match the otherwise integrated workspace.</li><li><strong>Verification.</strong> A generated dashboard can still be wrong. Check the SQL behind every number.</li></ul><h3>When I would still pick Superset</h3><p>Superset is open source, self-hosted, and gives you full control over code, deployment, and where your data lives. I would still choose it when data has to stay on premises, when a project needs deep customization that you want to own, or when open source is a requirement. I would reach for a Dive when I want a fast, good-looking dashboard on a prepared data layer in the cloud.</p><h3>Where this helps at arconsis: demos and proposals</h3><p>Many of our customers work in regulated industries and have strict rules about their data. That limits what we can show them before a project starts. With anonymized or synthetic data, a Dive turns an idea into a working, branded dashboard within a day. In a proposal or a presentation, customers can click through an idea instead of reading a description.</p><p>Data location is one of the first questions customers ask. If you choose a European region when you create the organization, the data stays in the EU. Two cautions: the AI client you connect also sees your prompts and query results, so check that setup with the same care, and for demos I use anonymized data only.</p><h3>Why this matters</h3><p>Generated output only helps if you can check it. A dashboard still needs correct numbers, traceable logic, and controlled access. Dives give you the SQL and the code, so a review is possible. Whether the setup is enough for your data depends on your requirements, so test it with a small project first.</p><h3>Takeaway</h3><p>Superset and Tableau are not going away, and I still build custom plugins when a project needs full control. But the work that cost me a week, wiring tables, pivots, filters, and drill-downs, took me about a day in Dives, with two prompt revisions, including learning the tool. The result depends heavily on the data layer: with a golden layer behind it, a Dive worked very well for me.</p><p>The right tool depends on the customer: what they already run, where their data must live, and how much control they need. A Dive is one more option I can offer for quick, good-looking dashboards on a prepared data layer, and a fast way to turn an idea into something a customer can click through before a project starts. That leaves more time for the part that matters: checking that the numbers are right.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c9fd3f1f3267" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arconsis/a-week-in-superset-a-day-in-motherduck-dives-c9fd3f1f3267">A week in Superset, a day in MotherDuck Dives</a> was originally published in <a href="https://medium.com/arconsis">arconsis</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Give your agent a map: why your codebase needs a knowledge graph]]></title>
            <link>https://medium.com/arconsis/give-your-agent-a-map-why-your-codebase-needs-a-knowledge-graph-f47c8d3ede5c?source=rss----c3dfaac5c9ee---4</link>
            <guid isPermaLink="false">https://medium.com/p/f47c8d3ede5c</guid>
            <category><![CDATA[graphify]]></category>
            <category><![CDATA[claude-code]]></category>
            <category><![CDATA[knowledge-graph]]></category>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[rags]]></category>
            <dc:creator><![CDATA[Thimo Bess]]></dc:creator>
            <pubDate>Wed, 15 Jul 2026 07:31:01 GMT</pubDate>
            <atom:updated>2026-07-15T07:31:00.963Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Graphify Graph of one of my projects" src="https://cdn-images-1.medium.com/max/1024/1*zvvl5LZg3bB02u2_ZvdqyA.png" /><figcaption>Graphify Knowledge Graph</figcaption></figure><p>Watch a coding agent work on an unfamiliar repo and you see the same loop every time. It greps for a symbol. It reads a file, that file points somewhere else, so it reads that one too. Then it guesses, reads a third file to check the guess, backtracks. Four tool calls and twenty thousand tokens later it finally has enough context to make a one-line change.</p><p>That loop works fine until the repo gets big, and then you pay for it on every single task.</p><p>I’ve been running Graphify as a default on my projects for a while, and here’s the pitch I’d make to anyone still pasting files into context: your agent is redoing search work that a graph could have done once, ahead of time. A bigger context window doesn’t help with that. A map does.</p><h3>The problem is the search, not the model</h3><p>The standard way an agent gathers context is naive injection. Find the files that look relevant, dump them in, hope the answer is in there. On a small repo that’s fine. On anything real it falls apart for three reasons at once: you hit hard token limits, long contexts measurably degrade the model’s output, and cost and latency climb with every file you stuff in.</p><p>Retrieval-Augmented Generation (RAG) was the first answer. Instead of injecting everything, you chunk the codebase, embed the chunks, and retrieve only what’s semantically close to the question. That helps, but pure vector search has a blind spot that matters enormously for code: it finds things that look similar, when what you usually need is the things that are connected.</p><p>That distinction does most of the work here. When I ask “what breaks if I change this function,” I don’t want the five functions that read like it. I want the callers, the things it depends on, and where it sits in the architecture. Embeddings can’t give me that, because the relationship I care about is a call edge, an import, a dataflow. None of those has anything to do with surface similarity.</p><h3>What a graph gives you that a vector store can’t</h3><p>A code knowledge graph models the repo as typed nodes (symbols, files, modules, docs) joined by typed edges (calls, imports, depends-on, defines, uses). This is the code graphRAG pattern, and once the graph exists, questions that used to be a cascade of reads collapse into a single traversal.</p><p>“What depends on this, directly and indirectly?” becomes a reverse walk instead of a dozen greps. “How do these two modules connect?” is a shortest-path query. “Where’s the architectural heart of this system?” falls out of degree counting, the high-connection “god nodes” that usually mark your coupling problems.</p><p>The payoff is concrete, and it lands on the context window, the one resource you can’t buy more of. The agent’s blind exploration loop (search, read, read, guess, read) collapses to a query or two. Every token the agent spends finding the code is a token it can’t spend changing it, and a graph moves that finding cost out of the hot path and pays it once.</p><p>There’s a measured number behind this. On a mixed corpus of code and papers, Graphify gets a 71.5× reduction in query-time tokens versus injecting whole files: a subgraph query that costs around 1.7k tokens replaces around 123k tokens of naive context. Even if you discount the exact figure, the win is one to two orders of magnitude. A change that size reorganizes how you work; it isn’t a 10% tuning tweak you’d squint at on a dashboard.</p><h3>How I actually use Graphify</h3><p>Graphify is a Python tool (MIT-licensed, Tree-sitter parsing across 19+ languages, NetworkX under the hood) that ships as a Claude Code skill. You point it at a repo and it runs a single pipeline: detect files, extract nodes and edges, build the graph, cluster it with the Leiden algorithm, analyze for hubs and surprise edges, write a report, and export.</p><p>You get back three artifacts, and they’re the reason I like it:</p><ul><li>graph.json: the queryable graph itself. It&#39;s portable, so you can commit it, ship it to a remote agent, or grep it.</li><li>GRAPH_REPORT.md: a human-readable map of the god nodes, the surprising edges, and suggested questions to ask the codebase.</li><li>graph.html: an interactive visualization for when I want to eyeball the structure myself.</li></ul><p>Day to day I’m mostly in the query commands: graphify query &quot;what connects auth to the database?&quot;, graphify explain &quot;SomeSymbol&quot;, graphify path &quot;A&quot; &quot;B&quot;. On a new repo, reading GRAPH_REPORT.md first does more for my orientation in two minutes than half an hour of clicking through folders.</p><p>One design choice is what makes this usable at work: only semantic descriptions ever leave the machine, and the raw source stays local. If you’re somewhere you can’t ship proprietary code upstream, that constraint is the whole reason you’d be allowed to use a tool like this at all.</p><h3>The fork in the road: a map or an oracle</h3><p>Graphify isn’t the only way to do this, and the main alternative is worth looking at because it comes from a genuinely different philosophy. CodeGraph (Rust, SurrealDB for a fast vector index, exposed as an MCP server) doesn’t hand you a graph. It hands you four questions (agentic_context, agentic_impact, agentic_architecture, agentic_quality) and runs its own reasoning agent inside the indexer to answer them with citations.</p><p>The split is worth deciding on deliberately:</p><p>Graphify CodeGraph What you get back an inspectable graph a synthesized answer Where the reasoning lives your outer agent inside the indexer Strength portability, token cost, privacy answer quality, low caller load Operating cost lightweight, local a service to run (DB + reasoning LLM)</p><p>Graphify treats the graph as a portable artifact and keeps your agent the smart one. CodeGraph absorbs the search-and-synthesis work and hands back “what depends on UserService and why,” file and line included. Reach for the first when you want to inspect and ship the graph, when privacy is non-negotiable, or when your agent already reasons well and just needs a smaller haystack. Reach for the second when your outer agent is context-constrained, or when you want boundary enforcement and architectural fitness signals as first-class features.</p><p>I default to Graphify. The portability and privacy posture line up with how I work, and unless your outer agent is too context-constrained to do the reasoning itself, it’s where I’d tell you to start.</p><h3>Where it’s worth it, and where it isn’t</h3><p>I won’t pretend this is free or universal. On a small repo the agent can hold in its head, the graph is overhead for no gain, so skip it. And the honest caveats stack up: nobody’s published a head-to-head benchmark on answer correctness, indexing a 500k-LOC monorepo isn’t instant, and CodeGraph’s promise to hand back synthesized answers instead of search results leans on a capable reasoning LLM, so a weak local model collapses it back into fancy search.</p><p>Where it earns its place: large or unfamiliar codebases, onboarding, impact analysis before a risky change, and any workflow where you’re feeding one well-scoped prompt to a remote or context-limited agent. That covers most of what I do on a serious project, which is why I leave it on by default.</p><h3>Where this leaves you</h3><p>If you run agents on a large codebase, the missing graph layer is a line item you’re already paying in latency, token spend, and the answers a bloated context quietly degrades. You just haven’t named it yet. The bottleneck was never model size. It’s the blind search your agent runs before it touches a line of code, and a graph pays that cost once instead of on every task.</p><p>The map-or-oracle choice is cheaper to make now than to unwind after your first agent-driven feature ships, so make it deliberately: a portable graph you inspect and ship (Graphify), or a reasoning service that answers questions (CodeGraph). But either one beats the real default, which is no graph at all.</p><p>Your agent is already mapping your codebase on every task you hand it, one grep at a time, badly. Hand it a real one.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f47c8d3ede5c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arconsis/give-your-agent-a-map-why-your-codebase-needs-a-knowledge-graph-f47c8d3ede5c">Give your agent a map: why your codebase needs a knowledge graph</a> was originally published in <a href="https://medium.com/arconsis">arconsis</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Claude Code skills don’t do subfolders — here’s what to do instead]]></title>
            <link>https://medium.com/arconsis/claude-code-skills-dont-do-subfolders-here-s-what-to-do-instead-aa98cdbc4b95?source=rss----c3dfaac5c9ee---4</link>
            <guid isPermaLink="false">https://medium.com/p/aa98cdbc4b95</guid>
            <category><![CDATA[claude-code]]></category>
            <category><![CDATA[skill-mangement]]></category>
            <category><![CDATA[claude-plugin]]></category>
            <category><![CDATA[skills]]></category>
            <dc:creator><![CDATA[Thimo Bess]]></dc:creator>
            <pubDate>Mon, 13 Jul 2026 08:17:01 GMT</pubDate>
            <atom:updated>2026-07-13T08:17:00.025Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4-FPfcmR0lno58HbiaS25w.png" /></figure><p>I had 34 Claude Code skills sitting in one flat folder. They were symlinked into ~/.claude/skills straight out of my dotfiles repo, so editing a skill meant editing the repo and the change went live on the next session. Nice and simple.</p><p>The names had grown ugly, though. coding-conventions, coding-tdd, second-brain-ingest, swiftui-pro, swift-testing-pro. The prefixes were the only grouping I had. They weren&#39;t categories, just a naming convention I&#39;d talked myself into.</p><p>So I asked what felt like an obvious question: can I just make subfolders? Drop tdd into a coding/ folder, ingest into second-brain/, and let the folder be the category?</p><p>The answer is no. And chasing <em>why</em> it’s no led me somewhere much better.</p><p>A quick note on scope. This is written for people who manage their own Claude Code setup out of a dotfiles repo and want their skills grouped without giving up live edits. If you’re a team packaging skills for other people to install, you want a marketplace and most of what follows won’t apply to you. And because plugin specifics move fast: everything here was verified on Claude Code 2.1.170, so check your own version as you read.</p><h3>The dead end</h3><p>Claude Code discovers skills flat. It walks the skills directory, and for each folder that holds a SKILL.md, the folder name becomes the invocation name. That&#39;s it. There&#39;s no recursion into category subfolders, no notion of a parent group.</p><p>So skills/coding/tdd/SKILL.md does not give you a coding category with a tdd skill inside it. At best the discovery just doesn&#39;t find it. My naive mental model (folders are categories) simply isn&#39;t the model the tool uses.</p><p>That’s annoying, but it’s also a useful forcing function. If the filesystem won’t carry the category, something else has to. The question becomes: what’s the actual mechanism for grouping skills, and does it survive a symlinked dotfiles setup?</p><h3>Three ways Claude Code loads skills</h3><p>It turns out there are three, and they’re easy to conflate. Here’s the whole picture:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IFLurmjyykCvr_ClpZ3uVA.png" /></figure><p>Why the marketplace is a trap for personal setups</p><p>This is the counterintuitive part, so it’s worth being concrete about it.</p><p>When you install a plugin from a marketplace, Claude Code copies it into ~/.claude/plugins/cache/. Your repo is no longer the live source. Edit a skill in your dotfiles and nothing happens until you run /plugin marketplace update. For a collection I tweak constantly, that copy step quietly kills the one property I cared about most.</p><p>It gets worse for a dotfiles bootstrap. Adding a marketplace and installing from it trigger interactive trust prompts. On a fresh machine, where I want a non-interactive script to lay everything down, those prompts block the whole thing.</p><p>And none of that ceremony buys me anything. Marketplaces exist to <em>distribute to other people</em> and to <em>pin versions</em>. I’m distributing to exactly one person, me, across machines I already trust. I’m paying for publishing infrastructure I don’t use.</p><h3>The skills-directory plugin, concretely</h3><p>Here’s the mechanism that does what I want.</p><p>Any folder directly under a skills directory that contains a .claude-plugin/plugin.json loads as a plugin on the next session. No install, no registration, no trust prompt. (claude plugin init &lt;name&gt; scaffolds the manifest if you don&#39;t want to write it by hand.)</p><p>The namespace comes from the name field in plugin.json. A plugin named coding exposes its skills as coding:tdd, coding:conventions, and so on. Same for agents: coding:pr-reviewer.</p><p>And it’s a <em>full</em> plugin, not a skills-only thing. One bucket can carry skills and agents and commands and hooks, all namespaced together. That last part matters more than I expected. My agents could move inside the same bucket as the skills they relate to.</p><p>Because discovery happens in place rather than by copying, the symlink workflow survives intact. Symlink the bucket into ~/.claude/skills/, and Claude Code follows the link and reads the files where they really live. Live edits work.</p><h3>The dotfiles change is one line</h3><pre># before: one symlink for everything, flat, no namespaces<br>ln -sfn &quot;$DOTFILES/DragonAgents/skills&quot; ~/.claude/skills<br>ln -sfn &quot;$DOTFILES/DragonAgents/agents&quot; ~/.claude/agents</pre><pre># after: point at the buckets&#39; parent; each bucket auto-loads, namespaced.<br># agents now live inside their buckets, so the agents symlink goes away.<br>ln -sfn &quot;$DOTFILES/DragonAgents/plugins&quot; ~/.claude/skills</pre><p>Two symlinks become one. The agents symlink disappears entirely because agents are part of the buckets now.</p><h3>I didn’t trust the docs, so I ran a smoke test</h3><p>The behaviour above is the kind of thing that’s easy to get subtly wrong, especially the “agents load too” and “symlinks are followed” claims. Before migrating 34 skills, I built a throwaway bucket and checked.</p><pre># bucket layout:<br>#   coding/.claude-plugin/plugin.json<br>#   coding/skills/hello/SKILL.md<br>#   coding/agents/echo-bot.md</pre><pre>ln -sfn /tmp/.../coding ~/.claude/skills/smoketest-coding</pre><pre>claude plugin list<br>#   -&gt; smoketest-coding@skills-dir, enabled, installPath = the symlink</pre><pre>claude plugin details &#39;smoketest-coding@skills-dir&#39;<br>#   Component inventory: Skills (1) hello | Agents (1) echo-bot<br>#   Projected token cost: always-on ~78 tok</pre><p>That confirmed all three things at once: discovery works through a symlink, it reads in place rather than copying, and agents load from a skills-directory plugin, not just skills.</p><p>Two things I learned here are worth keeping:</p><p>First, claude plugin list and claude plugin details run as fresh processes. They trigger discovery on their own, so you can verify a newly-dropped plugin without restarting your running session.</p><p>Second, claude plugin details reports a projected token cost per component: always-on versus on-invoke. That&#39;s a real budgeting tool. It tells you how much context each bucket costs you just by existing, before you&#39;ve invoked anything.</p><h3>Migrate less: the dedup pass</h3><p>Here’s the part I almost skipped, and I’m glad I didn’t. Before moving anything, I shrank the surface area.</p><p>The repo had the same capability expressed three different ways. Take code review: there was a review <em>skill</em>, a pr-review <em>command</em>, and a pr-reviewer <em>agent</em>. The skill and the agent carried near-identical bodies. They&#39;d already drifted apart, so they didn&#39;t even agree with each other anymore.</p><p>That’s the teachable moment, because it forces you to be honest about what each of these things is actually for:</p><ul><li>A <strong>skill</strong> is a reusable procedure or piece of expertise. It runs inline in your context, and it auto-triggers from its description.</li><li>An <strong>agent</strong> (subagent) is a separate context window with its own tool sandbox. You reach for it when you need isolation (its file-reading doesn’t bloat your main context, only its summary comes back), tool restriction (read-only, say), or parallel fan-out.</li><li>A <strong>command</strong> is a saved prompt behind a typed trigger. Pure glue. And it’s largely superseded by skills, which can both auto-trigger <em>and</em> be invoked as /name.</li></ul><p>Commands and agents predate skills. That’s why old setups like mine accumulate redundant pairs: I built the agent before the skill existed, then built the skill and never deleted the agent.</p><p>The fix is a clean, reusable pattern. Keep the procedure in the skill, and make the agent a thin wrapper that loads the skill and adds only what’s genuinely its own: the isolation, the tool limits, an output override. My oss-scout agent is the example of this done right: about 20 lines that just run the oss-research skill in a subagent. The procedure lives in one place.</p><p>I went through and deleted:</p><ul><li>4 slash commands, thin launchers I never actually typed.</li><li>1 agent (pr-prepper) that nothing invoked.</li><li>2 skills (second-brain-lookup, second-brain-propose) that were orphaned. The three agents they&#39;d been built for had been removed in an earlier migration, so nothing called them anymore.</li></ul><p>That last cut is the one I want to underline. Those two skills weren’t <em>obsolete</em>. The audit found nothing technically wrong with them. They were just dead by usage: no agent invoked them, so they were weight with no lever. A well-designed skill you never call is still dead weight. Trim by usage, not only by obsolescence.</p><p>The net: ~34 skills, 6 agents, 4 commands became 32 skills, 5 thin agents, 0 commands, with each capability’s procedure living in exactly one place.</p><h3>The payoff</h3><p>What I ended up with is six namespaced buckets, each a skills-directory plugin: coding, swift, planning, writing, obsidian, second-brain.</p><p>Here&#39;s the shape of it on disk:</p><pre>DragonAgents/plugins/                    # ← the one symlink, into ~/.claude/skills<br>├── coding/<br>│   ├── .claude-plugin/plugin.json       #   name: &quot;coding&quot;  → coding:*<br>│   ├── skills/<br>│   │   ├── tdd/SKILL.md                 #   → coding:tdd<br>│   │   ├── conventions/SKILL.md         #   → coding:conventions<br>│   │   └── review/SKILL.md              #   → coding:review<br>│   └── agents/<br>│       ├── pr-reviewer.md               #   → coding:pr-reviewer<br>│       └── oss-scout.md                 #   thin wrapper over oss-research<br>├── swift/<br>│   ├── .claude-plugin/plugin.json       #   name: &quot;swift&quot;   → swift:*<br>│   └── skills/<br>│       ├── ui/SKILL.md                  #   → swift:ui      (was swiftui-pro)<br>│       └── testing/SKILL.md             #   → swift:testing (was swift-testing-pro)<br>├── planning/<br>├── writing/<br>├── obsidian/<br>└── second-brain/<br>```</pre><p>Invocation now reads the way I always wanted it to. coding:tdd. second-brain:ingest. swift:ui. The namespace carries the category, so the old prefixes just fall away (coding-conventions becomes coding:conventions), and the Swift skills get normalized along the way: swiftui-pro to swift:ui, swift-testing-pro to swift:testing.</p><p>The grouping <em>is</em> a namespace now, instead of a naming convention I was enforcing by hand. That’s the whole difference. The category used to be a string I prepended and hoped everyone respected. Now it’s structural, and the tool enforces it for me.</p><p>I wrote the decision down as an ADR in the repo, so future-me doesn’t re-litigate the marketplace question from scratch in six months.</p><h3>A few honest caveats</h3><ul><li>Plugin specifics move fast (I verified against 2.1.170, noted up top). Date your post and check your own version before trusting the exact command output.</li><li>Skills-directory plugins are the right call for <em>personal</em> use. If you’re genuinely distributing to other people, a marketplace is correct. That’s what the versioning, trust, and discovery machinery is <em>for</em>.</li><li>Renames have a cost. Agents reference skills by name, so when you rename a skill you have to update those references in lockstep or you’ll break the wiring. Do them together.</li></ul><p>If you’ve got a flat pile of skills and you’ve felt that prefix-naming itch, this is the way out. You don’t need a marketplace. You need a manifest and one changed symlink.</p><p>I hope this saves you the dead end I walked into 😉</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aa98cdbc4b95" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arconsis/claude-code-skills-dont-do-subfolders-here-s-what-to-do-instead-aa98cdbc4b95">Claude Code skills don’t do subfolders — here’s what to do instead</a> was originally published in <a href="https://medium.com/arconsis">arconsis</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Spend tokens to buy time: the parallel agent pattern]]></title>
            <link>https://medium.com/arconsis/spend-tokens-to-buy-time-the-parallel-agent-pattern-4e86c876b0f7?source=rss----c3dfaac5c9ee---4</link>
            <guid isPermaLink="false">https://medium.com/p/4e86c876b0f7</guid>
            <category><![CDATA[agentic-patterns]]></category>
            <category><![CDATA[multi-agent-ai]]></category>
            <category><![CDATA[agentic-ai-architecture]]></category>
            <dc:creator><![CDATA[Thimo Bess]]></dc:creator>
            <pubDate>Fri, 10 Jul 2026 07:56:13 GMT</pubDate>
            <atom:updated>2026-07-10T07:56:12.538Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gNGxMl_C73JAHhM3LCwKbA.png" /></figure><p>You ask a hard question that wants more than one kind of expert. Should we adopt Rust for our backend? A good answer needs an engineer on feasibility, someone on cost and ROI, someone on the market, someone on the failure modes. The obvious way to get those four takes from a model isb to ask for them one prompt at a time, or to cram them into a single mega-prompt and hope the model wears four hats at once.</p><p>Both are wrong. Asked one at a time, you wait four times as long for no reason; none of those analyses needs another to start. Asked all at once, you get a flattened, hedged answer where every perspective bleeds into the next. The fix is the oldest trick in distributed systems, pointed at LLMs: fan the work out, run it concurrently, fan the results back in. That’s the <strong>parallel / concurrent multi-agent pattern</strong>, and the Rust question above is the example I’ll build out as we go. This is the pitch for when to reach for it, and the honest account of when it’ll hurt you.</p><h3>What the pattern actually is</h3><p>Strip it to the shape and it’s two moves: <strong>fan-out</strong> and <strong>aggregate</strong>. You take one input and hand it to N specialist <em>agents</em> (each just one LLM doing one job) that run at the same time. Then you feed all their outputs to one <em>coordinator</em>: a final LLM call that reads everything and writes a single answer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IF4l6p3H0ZG93xEO1N5_Zg.png" /><figcaption><em>Fan-out to N specialists, fan-in to one coordinator. The agents never see each other’s work.</em></figcaption></figure><p>The specialists don’t have to be different models — they can be, but they don’t need to be, and often aren’t. What actually differentiates them is the <em>system prompt</em> (the standing instruction that fixes each agent’s role before it ever sees the question), not the model underneath; run all five on the same model and the pattern holds just fine. That one choice is the whole engine. For the Rust decision, you stand up five agents, each pinned by its system prompt to a single lens: technical feasibility, cost and ROI, market, risk, and UX. None of them is a general “analyst.” Each is told what to cover and, just as important, what to leave alone.</p><p>Here’s the whole input, so it’s concrete. One question fans out to all five agents, unchanged:</p><blockquote>Should we adopt Rust for our backend services?</blockquote><p>and each agent carries a one-line system prompt that fixes its lane:</p><ul><li><strong>technical-feasibility</strong> — can our stack and team actually ship and run it? Leave cost and market alone.</li><li><strong>cost-ROI</strong> — migration effort, hiring, long-run savings. Leave the technical merits alone.</li><li><strong>market</strong> — who else has adopted it, what it signals, how deep the talent pool runs.</li><li><strong>risk</strong> — what breaks, what’s irreversible, the worst cases. Failure modes only.</li><li><strong>UX</strong> — what users actually feel: latency, reliability, stability.</li></ul><p>No agent sees another’s prompt or answer; every one of them sees only that single question. That’s the whole worked example — the rest of this piece is what happens to those five answers.</p><p>That role-per-agent split is deliberate, and it’s worth being concrete about why it beats one prompt asking for “a thorough analysis.” A lens that owns its own system prompt and its own <em>context window</em> (the limited span of text a model can hold in mind at once) spends all of that budget on one thing: the risk assessor hunts failure modes for its entire run instead of giving them one balanced paragraph and moving on. You also get coverage you can name and audit. With five named seats at the table, you can check at a glance that every angle is actually covered — and if you’d forgotten to give UX a seat, that gap stares back at you, instead of hoping UX surfaced somewhere in a single agent’s wall of text. And because each agent is sealed off, seeing only the original question and never another agent’s output, the five reads stay genuinely independent. The coordinator is the only place the threads ever meet.</p><p>That isolation is the whole point, and it’s worth saying out loud because it’s counterintuitive: the agents are <em>better</em> for not communicating. Diversity of thought is the product here. Five experts who can’t see each other’s notes give you five independent reads; five who can immediately start converging on the loudest one. On the Rust question that independence is exactly what surfaces the real tension: technical-feasibility comes back enthusiastic, cost-ROI comes back wary of the migration bill, and risk flags the thing neither of them was looking at — the hiring pool for Rust engineers is thin. Let them confer first and the loudest voice sands that disagreement down; keep them apart and the coordinator gets all three and has to reconcile them out loud.</p><h3>Why not just run them in sequence</h3><p>Because nothing forces you to. Running them in sequence (agent one finishes, then agent two starts) is the right call when step B needs step A’s output. Here it doesn’t. Each analysis stands alone, so paying for them one after another is pure dead waiting.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*J3894Vy0JKTD7u8gU-qWdg.png" /><figcaption><em>Parallel multi-agent is the only approach that gets all three: multiple perspectives, run concurrently, then synthesized.</em></figcaption></figure><p>Single-agent-broad-prompt is fast but shallow; it’s the mega-prompt that hedges. Sequential gives you depth but makes you wait. Parallel is the only row that gets all three, and the speedup is real but bounded: in practice it lands around 2–4× versus sequential, because your total time is set by <em>the slowest single agent plus the coordinator</em>, not the sum of all of them. One slow specialist caps the whole run. It’s the old rule from parallel computing in miniature: the one step you can’t split up, the final synthesis, sets your floor no matter how many agents you add.</p><h3>How it’s wired</h3><p><em>This section is for whoever builds it. If you don’t write code, the three headers below (stateless agents, resilient fan-out, event-driven streaming) are the whole takeaway; skip the snippets and meet me at “The economics.”</em></p><p>A minimal version of this wires up on LangGraph (a library for connecting LLM steps into a graph) as a static fan-out/fan-in shape, the same diagram you’d draw on a whiteboard:</p><pre>START ──┬── technical-analyst ──┐<br>        ├── financial-analyst ──┤<br>        ├── market-researcher ──┼── synthesize ── END<br>        ├── risk-assessor ──────┤<br>        └── ux-strategist ──────┘</pre><p>The start fans out to every agent at once, every agent feeds into synthesize, and synthesize runs only once all of them have finished. Three design decisions are what make it hold up in practice, and they&#39;re the parts worth stealing even if you never touch LangGraph:</p><h4>Stateless agents</h4><p>Each agent receives only the question and its own system prompt. No shared scratchpad, no cross-talk. That’s what makes the thing trivially parallel: there’s no shared state to fight over, so adding a sixth specialist is one more system prompt and zero coordination changes. This is the same statelessness-per-step discipline that shows up everywhere in reliable agent systems (the Ralph pattern takes it to the extreme: a fresh agent per task, with everything it needs written to disk instead of carried in memory).</p><h4>Resilient fan-out</h4><p>Every agent handles its own errors and returns a “failed” marker instead of crashing. A rate-limited or timed-out specialist doesn’t take the whole run down; the coordinator just synthesizes from the four that came back. One expert being out sick shouldn’t cancel the meeting. The mechanism is small: as each result lands it’s simply appended to the list of results, so a missing one is a normal, handled case rather than a crash.</p><h4>Event-driven streaming</h4><p>The orchestrator emits a stream of typed events (<em>agent started</em>, <em>agent produced a chunk of text</em>, <em>agent finished</em>, <em>synthesis started</em>, and so on) instead of going silent and returning one blob at the end. That separates the work from how you watch it: one engine can feed a web page, a terminal view, or a logging script without changing the core. You see each agent’s text appear live instead of staring at a spinner.</p><h3>The economics, stated honestly</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RP6ZVQm4xKFHsrKis-a4Yg.png" /><figcaption><em>Parallel’s wall-clock floor is the slowest agent plus the coordinator, but you pay for every agent.</em></figcaption></figure><p>This pattern is a way of spending money to buy time. Every call to a model is billed in <em>tokens</em> (the chunks of text it reads and writes), and the meter runs on both what you send in and what comes back. N specialists plus one coordinator is N+1 calls for what a single agent would do in one. You don’t get the answer cheaper; you get a <em>better, faster</em> answer for <em>more tokens</em>.</p><p>Anthropic’s own write-up of their multi-agent research system is the cleanest data point I’ve seen on the cost: their setup, with one lead agent directing several worker agents, outperformed a single agent by 90.2% on research tasks, and it burned roughly <strong>15× the tokens of a normal chat</strong>. They go further and credit about 80% of the performance difference to token usage alone. The architecture is, in their words, a way to throw more computation at the problem (<a href="https://www.anthropic.com/engineering/built-multi-agent-research-system">Anthropic, “How we built our multi-agent research system”</a>, accessed 2026–06–17).</p><p>So the rule I’d write on the wall: <strong>parallelism only pays off when the task genuinely breaks into independent pieces.</strong> If the pieces lean on each other, the 15× just buys you a pile of clashing assumptions.</p><h3>When it bites back</h3><p>Which is exactly the argument Cognition (the team behind the Devin coding agent) makes in their post “Don’t Build Multi-Agents,” and you should take it seriously before you fan anything out. The claim is sharp: <strong>every action an agent takes carries a hidden decision, and agents working in parallel make conflicting ones.</strong> Agents with no view of each other’s work each quietly assume things: about scope, about what the question means, about what “the system” even is. Stitch their outputs together and those assumptions clash. Their recommendation is to keep things to a single agent that sees the full history (compressing it when it gets too long), on the principle that every step should ideally see everything else (<a href="https://cognition.ai/blog/dont-build-multi-agents">Cognition, “Don’t Build Multi-Agents”</a>, accessed 2026–06–17).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wRn9L-hCEoruRLlkEaXb8w.png" /><figcaption>The dividing line: parallel agents are safe for read-only work, dangerous the moment they write shared state.</figcaption></figure><p>This is the dividing line for using the pattern. It’s safe precisely where the work is <strong>read-only and independent</strong>: analysis, review, assessment, research. Five agents reading the same proposal and reporting back can’t conflict, because none of them is changing anything; the coordinator reconciles their <em>opinions</em>, and disagreement there is a feature. The danger zone is write-heavy, interdependent work, coding being the obvious one, where two agents editing in parallel make incompatible changes to the same file and there’s no clean way to merge them. Anthropic landed in the same place from the opposite direction: their system shines on research that splits into parallel strands and is <em>less</em> effective for tightly coupled work like coding.</p><p>So: parallel agents to <em>think</em>, not to <em>act</em>. The moment your pieces have to agree on a single changing thing, you want them in sequence, or one agent with the full picture instead. One internal orchestrator we run draws the line in exactly this spot. It runs four reviewers (security, performance, correctness, architecture) in parallel, because reviewing is independent, then funnels them through a single synthesizer and a final check before anything is trusted. Read concurrently, decide centrally.</p><p>Even inside the safe zone, the pattern has failure modes worth designing against:</p><ul><li><strong>Redundant analyses.</strong> Specialists with fuzzy, overlapping instructions produce near-identical takes. Fix it by making each one explicit about its lane and what it must <em>not</em> cover.</li><li><strong>Coordinator bias.</strong> The synthesizer over-weights the longest or most confident analysis. Make it address each perspective in turn, and consider trimming everyone to a similar length.</li><li><strong>Silent partial failure.</strong> An agent dies and the coordinator never mentions the missing perspective. Tell the coordinator which agents succeeded, and have it flag reduced confidence when one is absent.</li></ul><h3>Where it earns its place</h3><p>Reach for the parallel pattern when three things are true at once: the task wants multiple independent perspectives, the pieces don’t depend on each other, and wall-clock time matters. Decision support, multi-lens document review, due-diligence assessments, anything where you’d otherwise convene a panel of humans. That’s the sweet spot, and both the speedup and the diversity of thought are real.</p><p>Skip it when the task is inherently step-by-step, when the agents need to debate and converge (a different pattern), or when one agent already suffices. And the big one: skip it when the pieces have to change the same shared thing, where the 15× cost premium buys you conflict, not coverage.</p><p>Mechanically, the pattern is simple: kick off all the agents at once, wait for them to finish, and hand the pile to a synthesizer. The work is in the discipline around it. Keep the specialists independent, make the run survive a dropped agent, give the coordinator enough to flag what’s missing, and fan out only the work that’s genuinely independent. Get that right and one slow, hedged answer becomes several sharp ones, reconciled into a single verdict. Build it once, point it at a decision that deserves five expert opinions, and let them argue in parallel.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4e86c876b0f7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arconsis/spend-tokens-to-buy-time-the-parallel-agent-pattern-4e86c876b0f7">Spend tokens to buy time: the parallel agent pattern</a> was originally published in <a href="https://medium.com/arconsis">arconsis</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[We Didn’t Ask an AI to Build a Feature. We Gave It a Delivery Pipeline.]]></title>
            <link>https://medium.com/arconsis/we-didnt-ask-an-ai-to-build-a-feature-we-gave-it-a-delivery-pipeline-7d33bda824c5?source=rss----c3dfaac5c9ee---4</link>
            <guid isPermaLink="false">https://medium.com/p/7d33bda824c5</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Evangelos Gkountouras]]></dc:creator>
            <pubDate>Mon, 15 Jun 2026 07:29:05 GMT</pubDate>
            <atom:updated>2026-06-25T10:53:38.235Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6TJBJPtrunKKVbpAB0qwEA.jpeg" /></figure><p><em>Part 2: A Real Feature, End to End: the Trending Badge.</em></p><p>In <a href="https://medium.com/arconsis/we-didnt-ask-an-ai-to-build-a-feature-we-gave-it-a-delivery-pipeline-4293c59b7a0f"><strong>Part 1</strong></a>, we described the Agent Orchestration Framework we built for arconsis Eats: the agents, the lifecycle, the file-based state, and the safety rails. Here we let it run. The feature is a Trending Badge on restaurant feed cards. The pipeline is the same one we just described. Everything below is what actually happened.</p><h3>A Real-Life Example: The Trending Badge</h3><p>The feature itself is simple to describe: a &quot;Trending&quot; pill appears on a restaurant&#39;s feed card when it has seen a burst of recent review activity. The user-facing surface is small. The cross-module work is not.</p><h3>How the architect planned it</h3><p>The architect produced plan.md, 153 lines of file paths, function signatures, and acceptance criteria, along with the corresponding state.json. There were no open questions: the product decisions were all resolvable by sensible defaults. A 7-day window, a 3-review threshold, both tunable via application.properties:</p><pre>eats.trending.window-days=7<br>eats.trending.min-reviews=3</pre><p>The slice graph it came up with had six steps, each depending on the one before:</p><ul><li><strong>backend-domain</strong>: backend-author implements the server-side trending logic</li><li><strong>backend-tests</strong>: qa-tester adds test coverage for the new backend behavior</li><li><strong>shared-contracts</strong>: kmp-shared-author updates the shared DTO layer</li><li><strong>api-client-data</strong>: api-client-author propagates the field through the client cache and repository</li><li><strong>frontend-ui</strong>: frontend-author renders the badge in the Compose UI</li><li><strong>final-integration</strong>: code-reviewer reviews the full branch as one integrated system</li></ul><p>Two things stood out in the plan.</p><p>First, <strong>no migration</strong>. The architect figured out the trending flag is derivable from the existing reviews table through a GROUP BY place_id HAVING count(*) &gt;= :minReviews query scoped to the window. The plan explicitly forbids creating a new migration file. If a reviewer sees one, that&#39;s a defect.</p><p>Second, it flagged a <strong>cross-caller risk</strong> ahead of time. The trending flag would be computed in the home feed, but the profile screen renders the same reviews through a different code path. If that second path wasn’t updated, the same restaurant could show as “Trending” on the feed and not trending on your profile, for the exact same review data. The architect explicitly noted this in the reviewer instructions before any code existed. That’s the kind of seam that’s invisible when you’re reviewing one slice at a time.</p><p>The plan reviewer caught an issue on the first pass. The command ./gradlew :shared:compileKotlinMetadata is a SKIPPED no-op task on this project. The architect re-ran, swapped it for :shared:compileCommonMainKotlinMetadata, and the second pass got APPROVE_PLAN.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Bp5wyQVzg5tf3g4QAaMY0A.png" /><figcaption><em>The architect’s plan approved — one human decision away from writing code</em></figcaption></figure><h3>What each agent committed</h3><p>The branch history tells the story. Each agent’s work is one or two commits: a feat: commit with the production change, and a chore(infra): checkpoint that records the slice&#39;s state transition. 13 commits total, every slice checkpointed, every verdict preserved.</p><pre>695c6aa chore(infra): complete frontend-ui layer for trending-badge<br>fff2b69 feat(frontend): add trending badge to home feed cards<br>7a7fadf chore(infra): complete api-client-data layer for trending-badge<br>e049c5c feat(api-client): propagate isTrending through client cache layer<br>36f1305 chore(infra): complete shared-contracts layer for trending-badge<br>a003958 feat(kmp-shared): add isTrending field to ReviewResponse DTO<br>d80ba57 chore(infra): complete test layer for trending-badge backend<br>33bdd57 chore(deps): move MockK to version catalog and record review state<br>c0efe61 test(server): fix reviewer-rejected test issues for trending-badge<br>f8b0d40 fixup(server): replace @QuarkusTest with pure MockK unit tests<br>c0dc778 test(server): add trending-badge test coverage for FeedService<br>1e82dfb chore(state): update trending-badge progress for backend-author<br>c578d7d feat(server): add trending badge flag to feed responses</pre><p>A quick note on those commit messages. Every one follows the commit-messages skill we built: conventional-commit prefixes, subject under 72 characters, body that explains <em>why</em>, plus Slice: and Agent: footers. This isn&#39;t cosmetic. Six months from now, when someone runs git blame on ReviewResponse.isTrending, the commit message will explain the backward-compatibility reasoning.</p><h3>🔴 backend-author</h3><p>The first slice extended the backend API to support trending places. The agent added a query to identify places with a spike in recent review activity, wired the result into the feed response, and made sure the trending flag flowed through every path that returns review data to a client. No migration needed; the data was already there. Server compiles clean.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yjSZbzma39tEfe6BzIky-g.png" /><figcaption>The backend-author picks up its slice — state transitions from PENDING to IN_PROGRESS</figcaption></figure><h3>🟡 qa-tester and the retry loop that earned its keep</h3><p>This is the slice where the framework proved its value.</p><p><strong>Attempt 1.</strong> The qa-tester wrote integration tests per the plan, but hit an environment issue: Docker wasn’t running, so the database-backed test setup couldn’t start. Fair enough. The agent pivoted to unit tests with a mocking library, but introduced two problems in doing so: it added the new test dependency by hardcoding a version directly in the build script, bypassing the project’s pinned dependency catalog, and it quietly dropped the test that was supposed to verify feed/profile parity, the exact cross-layer seam the architect had flagged as the highest-risk integration point.</p><p>The code-reviewer rejected it. Both findings were BLOCKING.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XAUZ76yhA3JnTCHmhx4pEQ.png" /><figcaption>The reviewer rejects the QA slice — Request Changes</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dL0JDKJ3zge5KXEUnOWkwQ.png" /><figcaption>Inside the review md file for the QA tester — two blocking findings</figcaption></figure><p><strong>Attempt 2.</strong> The agent fixed both: the dependency was moved into the version catalog where it belonged, and the missing parity test was written properly, covering the scenario where the same restaurant shows up on both the home feed and a user’s profile, and verifying they agree on its trending status. 21 tests, 0 failures. Re-review → APPROVE.</p><blockquote><em>The honest take: the agent got it wrong the first time, and that’s fine. The framework caught it. The findings were specific enough to fix without a human round-trip. The retry cost about $3 on top of the original $2.37, versus a human catching it in PR review three days later, or worse, it landing on main and silently degrading coverage.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*K62bl-Yf5KlevSzeVACyzQ.png" /><figcaption>Retry approved — both blocking issues resolved, critical seam coverage restored</figcaption></figure><h3>🟦 kmp-shared-author</h3><p>The smallest slice in the branch was a single new field added to the shared DTO that both server and clients rely on. The code was trivial. The reasoning in the commit message was the point: the field needed a default value not for convenience, but for backward compatibility. Older installed app builds receiving a payload that doesn’t yet include the field must not crash. They should just silently treat the place as non-trending. The agent got this right and explained why in the commit, which matters more than it sounds six<br>months from now when someone wonders if the default is safe to remove.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YB58BiPHY4KEHWqLY3M2Ww.png" /><figcaption><em>The kmp-shared-author completes its slice — 15 tool uses, one new DTO field</em></figcaption></figure><h3>🟢 api-client-author</h3><p>The client slice threaded the trending flag through the offline cache layer and up to the repository that the UI reads from. The key concern here was the same backward-compatibility one: the cached data model also needed a default so that older locally-stored payloads wouldn’t break on app update. No new infrastructure, no new dependencies. Just making sure the new field traveled all the way from the network response to the UI without getting dropped.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RV4k8jtUuHja3XYohGN22A.png" /><figcaption>The api-client-author propagates the flag through the cache layer — build passes, slice CHECKED</figcaption></figure><h3>🟠 frontend-author</h3><p>The final slice rendered the badge in the Compose UI. The agent overlaid a “Trending” pill on the place photo in the feed card, and handled accessibility correctly. The badge is announced as a single unit by screen readers rather than reading the icon and label separately.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*e7C5zFV3TQNplHtEQNSbLw.png" /><figcaption>The frontend-author commits the Trending Badge to the home feed</figcaption></figure><p>One deliberate choice: the trending field was added to the UI model <strong>without</strong> a default value, which forces the compiler to catch any mapping function that forgets to pass it through. Defaults are convenient; their absence is a contract.</p><h3>What the final integration review caught</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*niCqz0D12mXJyKjKb3oVWg.png" /><figcaption>Final integration review — the full branch reviewed as one system before the CI gate</figcaption></figure><p>The code-reviewer’s review.md ran the whole branch against origin/develop. Verdict: <strong>APPROVE</strong>, no critical or major issues. Six nits, three worth mentioning.</p><p>It caught a minor issue where a service function was accepting a parameter it never actually used. Small thing, but it creates real cognitive overhead: anyone reading that code later would naturally assume the function’s behavior depends on what you pass in, when it doesn’t.</p><p>There’s no empty-feed short-circuit. A user with zero reviews still triggers a JPQL round-trip to compute trending places. One-line fix, but the kind of thing that adds up at scale.</p><p>And the finding that points back at usω: the MockK catalog edit straddles the automation boundary. The framework handled it eventually, but the architect should have anticipated the missing test dependency in the first place. That’s a prompt update for next time, not a framework limitation.</p><h3>The numbers</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gBYSOugAyKjaJi0V4iyu8A.png" /><figcaption>Cost Report</figcaption></figure><p>The full feature, from /feature trending-badge to integration-review approval:</p><p>Wall time was about 4.5 hours, of which maybe 30 minutes required a human present. Total tokens: 24.2 million (22M cache-read, 2M cache-write, 192k output). Total cost: <strong>$22.33</strong>, roughly $13.50 on Opus for the architect and reviewer, $8.83 on Sonnet for the authors and tester. There were 5 retries across the whole pipeline (the plan got revised twice, the backend-tests slice took three attempts). The feature touched 10 production files and added 3 test files.</p><p>The retries move the cost. A first-pass slice runs $0.30–$0.70. A reviewer rejection adds $1.50–$2.00. The MockK round-trip alone (plan-review retry, qa-tester retry, re-review) was about $7 of the $22.</p><p>We’d take that trade. The alternative, a human catching the catalog-edit issue in PR review three days later, isn’t free either.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2AzNME3F9PNq7bxLd_VOqQ.png" /><figcaption>Cost breakdown per agent</figcaption></figure><h3>What the framework still doesn’t do</h3><p>iOS-native code is out of scope. Swift, SwiftUI, signing, provisioning: the architect emits OPEN QUESTION: and stops. Platform-specific Compose (androidMain / iosMain / jvmMain), like cameras, file pickers, push notifications, anything needing expect/actual, is a human job. Gradle and version-catalog edits straddle the boundary, as the MockK incident demonstrated. CI/CD workflow edits are out of scope entirely.</p><p>And the agents still make mistakes. The qa-tester missed the cross-caller test. The reviewer missed the unused computeTrendingFlags parameter on the first per-slice pass and only caught it in the final integration review. The framework&#39;s value is <em>catching</em> mistakes through layered review, not <em>preventing</em> all of them.</p><p>The framing we keep coming back to: <strong>this is a delivery pipeline, not an autonomous engineer.</strong> The pipeline does planning, sequencing, writing, verifying, reviewing, checkpointing. The human does the judgement calls: approving the plan, adjudicating two-strikes rejections, pushing the branch, opening the PR. That’s a much smaller surface than “build me a feature,” and a much bigger lever than “autocomplete my next function.”</p><p>What we got out of this wasn’t a snippet or a half-built prototype. It was a working feature across every layer of a real Kotlin Multiplatform system: backend logic, shared contracts, client integration, and the UI. Think of it as a marathon. The pipeline carries you through the first 41 kilometers: design, implementation, and the cross-module coordination that usually eats the most time. The last kilometer is still yours. You review with fresh eyes, fix the edge cases, fight over naming, and decide whether the result clears the bar you’d actually ship against. The framework doesn’t remove that work. It makes sure that’s the only work left.</p><p>The trending badge took five slices, one retry loop, about five hours of mostly-unattended runtime, and $22 of API cost. The branch was green on /verify the first time we ran it. The next morning we opened the PR.</p><p>We didn’t ask an AI to build it. We gave it a pipeline.</p><p>Stay tuned!!</p><p>Special thanks to my colleague <a href="https://medium.com/@akoufa">Alex Koufatzis</a> for co-authoring this series.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7d33bda824c5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arconsis/we-didnt-ask-an-ai-to-build-a-feature-we-gave-it-a-delivery-pipeline-7d33bda824c5">We Didn’t Ask an AI to Build a Feature. We Gave It a Delivery Pipeline.</a> was originally published in <a href="https://medium.com/arconsis">arconsis</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[We Didn’t Ask an AI to Build a Feature. We Gave It a Delivery Pipeline.]]></title>
            <link>https://medium.com/arconsis/we-didnt-ask-an-ai-to-build-a-feature-we-gave-it-a-delivery-pipeline-4293c59b7a0f?source=rss----c3dfaac5c9ee---4</link>
            <guid isPermaLink="false">https://medium.com/p/4293c59b7a0f</guid>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Evangelos Gkountouras]]></dc:creator>
            <pubDate>Fri, 12 Jun 2026 07:01:04 GMT</pubDate>
            <atom:updated>2026-06-23T12:16:54.139Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6TJBJPtrunKKVbpAB0qwEA.jpeg" /></figure><p><em>Part 1: The Framework: seven AI agents, file-based state, and one human gate.</em></p><p>At <a href="https://www.arconsis.com/">arconsis</a>, we spend a lot of time thinking about the tools, frameworks, and practices that shape how software actually gets built, across very different customer contexts: e-commerce, automotive, finance, healthcare. The question we keep coming back to, regardless of the stack, is always the same: <em>what does it take to deliver software that is reliable, maintainable, and honest about its trade-offs?</em></p><p>AI-assisted development is the latest thing forcing that question into the open. And honestly, we’re not interested in it for the novelty. “An LLM wrote a function” stopped being interesting around the time autocomplete grew a brain. The real question, the one our customers will eventually ask us about, is whether AI agents can meaningfully contribute to a <strong>real production codebase</strong>. One with multiple modules, strict migration discipline, cross-platform targets, conventions that took years to settle, and a definition of “done” that includes things like backward compatibility for already-installed builds. That’s a very different problem from generating a snippet.</p><p>So this article isn’t a model benchmark or a tool comparison. It’s about <strong>process</strong>: how we structured agent collaboration so that the output is reviewable, auditable, and recognisable as code our team would have written by hand. To make any of that concrete, we did the obvious thing: we built the framework against one of our own Kotlin Multiplatform projects and let it ship a real feature end to end. Everything below comes from that exercise.</p><h3>The arconsis eats App</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/161/1*yl150dnobmNyeZSLA7BY6w.jpeg" /></figure><p>is one of our internal apps, a restaurant-discovery product we also use as a sandbox for tooling questions like this one. The shape of the codebase is what makes it useful for the experiment, not the product itself.</p><p>It’s a Kotlin Multiplatform monorepo with three layers. server/ is a Quarkus backend with a Flyway-managed database. Migrations are forward-only, no exceptions. shared/ is a module with the serializable DTOs that both server and clients use. composeApp/ is a Compose Multiplatform UI targeting Android, iOS, and Desktop, with an offline cache layer in between.</p><p>Those three layers have a strict dependency order: server → shared → client → UI. A single feature can require changes at every level, and each layer has to be correct before the next one can build against it.</p><p>This is exactly the kind of codebase where unsupervised AI coding (vibe-coding) falls apart. <br>If a client-side field name drifts from what the server actually emits, nothing fails at build time. The server emits isTrending, the client deserializes is_trending, everything compiles green. You find out in production.</p><blockquote><em>A model allowed to “just keep coding” through a stack like this leaves you with a green build and a broken product. The question isn’t “can it write Kotlin?” </em>It’s whether it can ship a feature without you watching every keystroke.</blockquote><h3>The Agent Orchestration Framework</h3><h3>A pipeline, not a prompt</h3><p>We didn’t build an AI that writes features. We built a <strong>delivery pipeline</strong> that uses AI agents as a team:</p><blockquote>architect → author → verify → review → fix → checkpoint → integrate → CI gate.</blockquote><p>Each step has a defined input, a defined output, a verification command, and a place to write its findings. None of the steps are “an LLM decides what to do next.” Routing is a deterministic Markdown state machine. LLMs do the work. They never decide <em>what</em> work happens.</p><h3>The agents</h3><p>The roster lives in .claude/agents/. Each agent is one Markdown file with a role description, allowed tools, and the prompt the model loads when invoked.</p><p>The 🔵 <strong>architect</strong> (Opus) reads the codebase and produces the plan and the slice graph. It understands the system, decides what needs to change, and never touches production code.<br>The 🔴 <strong>backend-author</strong> (Sonnet) owns the server layer: database schema, business logic, and API endpoints.<br>The 🟡 <strong>qa-tester</strong> (Sonnet) writes unit and integration tests.<br>The 🟦 <strong>kmp-shared-author</strong> (Sonnet) owns the client-server contract, making sure field names match the server JSON exactly.<br>The 🟢 <strong>api-client-author</strong> (Sonnet) takes those contracts and wires them through the client data layer: network calls, local cache, and the repository the UI reads from.<br>The 🟠 <strong>frontend-author</strong> (Sonnet) builds the screens and view logic that the user actually sees.<br>And the 🟣 <strong>code-reviewer</strong> (Opus) reviews the plan, every per-slice diff, and the final integration diff, but never writes a line of code.</p><p>The Opus/Sonnet split is deliberate. Opus does <em>judgement</em>: planning and reviewing. Sonnet does <em>throughput</em>: writing code against a clear spec. The cost breakdown below shows it paying off: about 60% of the spend goes to Opus on the architect and reviewer, 40% to Sonnet on the actual code.</p><h3>The lifecycle of a feature</h3><p>One command starts the whole thing:</p><pre>/feature trending-badge &quot;Show a Trending badge on feed cards for popular places&quot;</pre><p>That looks like a prompt.</p><p>It isn’t.</p><figure><img alt="Inside the feature command" src="https://cdn-images-1.medium.com/max/1024/1*6PZlKie-eBG6GYvJKPCKGA.png" /><figcaption>Inside the /feature command</figcaption></figure><p>In our framework, /feature is not a request for an LLM to “go build something.” It is the entry point into a deterministic delivery pipeline. The command validates the repository state, creates the feature branch, and immediately kicks off the first three steps of the workflow: the architect reads the codebase and produces the plan, the reviewer sanity-checks that plan before a single line of code is written, and then the pipeline pauses for human approval. Only after that gate does implementation begin, dispatching the right author agents in dependency order, enforcing verification at every slice, recording checkpoints, and finishing with a full integration review.</p><p>The important part isn’t that an AI writes code. It’s that the AI operates inside a workflow that looks much closer to CI/CD than chat.</p><p>Here’s what happens, end to end.</p><p><strong>Start clean.</strong> Before any model is invoked, the framework checks the basics: clean working tree, branch cut from develop, no uncommitted changes for an agent to accidentally overwrite. If any of that isn&#39;t true, the workflow stops. A surprising amount of &quot;AI went off the rails&quot; behavior starts with an ambiguous workspace. We decided the framework should remove that ambiguity rather than ask an agent to reason about it.</p><p><strong>The architect plans, but never codes.</strong> The first agent reads the codebase and decides what needs to happen: which layers, which files, whether a migration is actually necessary, where the integration risks are. It produces two files: plan.md (human-readable blueprint with file paths, strategy, acceptance criteria, and reviewer notes) and state.json (machine-readable slice graph with dependency edges, owning agents, verification commands, retry state, and completion status). That second file is what makes the whole pipeline resumable. If the session dies midway, /implement trending-badge reads state.json, finds the first incomplete slice, and picks up from there. No reconstructing state from conversation history.</p><p><strong>The plan is reviewed before any code exists.</strong> The code-reviewer checks whether the workflow is actually executable: slices in the right order, file paths plausible, verification commands valid, migration rules respected, integration risks visible. Findings land in reviews/00-plan.review.md. For Trending Badge, the reviewer caught a real problem before a single line was written. The architect had selected a Gradle task that was a skipped no-op on this project. The plan was revised and corrected before implementation was allowed to proceed. The reviewer wasn&#39;t checking code quality. It was checking whether the pipeline itself was safe to run.</p><p><strong>One human gate, before coding starts.</strong> After the reviewer approves, the pipeline pauses. You read the architecture, check the slice decomposition, answer any OPEN QUESTION: markers the architect couldn&#39;t safely resolve. This is the last mandatory stop before multiple agents start changing a multi-module codebase. Once you approve, the state machine takes over.</p><p><strong>The state-machine loop.</strong> One slice at a time, in dependency order. Each slice has one owner, one scope, one verification command, and one review step. Backend compiles before shared contracts are touched. Shared DTOs compile before client code depends on them. Client propagation works before the UI renders the new field. The verification command isn’t improvised by the agent. It’s in the plan, stored in state.json. After verification, the reviewer inspects only the current slice diff ($pre_sha..HEAD), keeping findings focused. One retry on rejection; two rejections surfaces the issue to you. No unbounded autonomous repair loops.</p><p><strong>Final integration review, then </strong><strong>/verify.</strong> Once all slices are done, the reviewer sees the whole branch against origin/develop, checking the seams that per-slice review can&#39;t see: does the server emit the field the client expects, do DTO defaults preserve backward compatibility, is anything locally correct but globally wrong? After that comes the CI gate: five Gradle tasks, all must pass. No auto-fixing at this stage. Auto-fix at the final gate is how you ship something that&#39;s technically green but no longer the thing that was reviewed. /verify passing is the only definition of done.</p><h3>The key design decision: agents communicate through files</h3><p>Most multi-agent systems try to pass context through conversation history. That’s expensive, unbounded, and impossible to audit after the fact. We went the other direction entirely: <strong>agents don’t share conversation history. At all.</strong> Every agent communicates through files on disk.</p><p>plan.md says what to build. state.json tracks where we are in the build. progress.md records what&#39;s been done. reviews/&lt;agent&gt;.md contains what the reviewer found for each slice. review.md holds the final integration review. One agent writes, the next one reads. The orchestrator never asks an agent &quot;what did you do?&quot; It reads progress.md. The reviewer never asks an author &quot;why?&quot; It reads the diff.</p><p>Three things fall out of this almost for free.</p><p><strong>Auditability.</strong> Every decision is a file sitting in git history. No black box. You can reconstruct any feature’s entire AI-assisted development story from the files on the branch.</p><p><strong>Resumability.</strong> If your laptop dies mid-feature, /implement trending-badge reads state.json, finds the first not-done slice, and picks up exactly where it left off. It&#39;s a query against a file, not a vibe check.</p><p><strong>Clean separation of state from model memory.</strong> The framework’s state is the file tree. The model’s memory is a single agent’s invocation context. These are different things and they should live in different places.</p><h3>Safety rails (the parts that can’t be talked out of)</h3><p>LLM agents are remarkably good at finding the direct path to “this looks done.” Some of that creativity is how you end up editing a released Flyway migration. For the non-negotiables we use <strong>harness-level hooks</strong>, not prompts you can talk your way around. They live in scripts/claude/ and are wired in .claude/settings.json.</p><p>guard-migrations.sh is the most critical one. It fires on every file edit or write. If the target is a Flyway migration that already exists on origin/main or origin/develop, the hook blocks it outright. There&#39;s an escape hatch (ALLOW_MIGRATION_EDIT=1), but a human has to set it. No agent can flip it on its own. The second hook, record-subagent-cost.sh, fires on every subagent exit, reads the transcript, aggregates token usage, prices it, and appends one line to costs.jsonl. That&#39;s how we got the cost breakdown later in this article.</p><p>These hooks run <strong>automatically and outside the agents’ control.</strong> They can’t be argued with, prompt-engineered around, or skipped.</p><p>The rest of the safety surface lives in settings.json and the state machine itself. On the permissions side: git push, git reset, git rebase, gh pr create, and gh pr merge all require explicit human approval. Gradle compile/test, read-only git, and read-only gh are auto-allowed. The bottom line: <strong>no agent can push or open a PR.</strong> The branch is yours to inspect first.</p><p>On the process side: a plan-level human gate means no code gets written until you’ve read and approved the architecture. A 1-retry cap per review finding prevents infinite fix loops. Two rejections and it’s surfaced to you. Per-slice diffs are scoped so the reviewer only sees $pre_sha..HEAD for the current slice, not the entire branch. And a BLOCKED: signal lets agents flag problems instead of silently skipping them. The qa-tester used this twice on the worked example below.</p><h3>Things we deliberately left out</h3><p>No parallel agents: the dependency graph (server → shared → client → UI) is sequential by nature, and trying to parallelize it buys you deserialization crashes. No meta-planner: an LLM picking which agent runs next would make the whole system non-reproducible, and frankly we don’t trust that. No shared memory across agents. Each one gets the plan, its task, and the artifacts. Nothing else. Boring is reliable.</p><p>That’s the framework. In <a href="https://medium.com/p/7d33bda824c5">Part 2</a>, we put it to work on a real feature: a Trending Badge that spans every layer of the stack, from backend query to Compose UI. We walk through what each agent did, where the retry loop earned its keep, and what the whole thing actually cost.</p><p>Stay tuned!!</p><p>Special thanks to my colleague <a href="https://medium.com/@akoufa">Alex Koufatzis</a> for co-authoring this series.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4293c59b7a0f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arconsis/we-didnt-ask-an-ai-to-build-a-feature-we-gave-it-a-delivery-pipeline-4293c59b7a0f">We Didn’t Ask an AI to Build a Feature. We Gave It a Delivery Pipeline.</a> was originally published in <a href="https://medium.com/arconsis">arconsis</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Part 5: SpecKit. Turning GitHub Copilot Into a Specification-Driven Teammate]]></title>
            <link>https://medium.com/arconsis/part-5-speckit-turning-github-copilot-into-a-specification-driven-teammate-c84c3cfc2ca4?source=rss----c3dfaac5c9ee---4</link>
            <guid isPermaLink="false">https://medium.com/p/c84c3cfc2ca4</guid>
            <category><![CDATA[spec-kit]]></category>
            <category><![CDATA[spec-driven-development]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[github-spec-kit]]></category>
            <category><![CDATA[ai-agent]]></category>
            <dc:creator><![CDATA[Jonas Stubenrauch]]></dc:creator>
            <pubDate>Fri, 20 Mar 2026 10:58:01 GMT</pubDate>
            <atom:updated>2026-03-22T13:57:14.715Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*dowtOXXfftxczrjrBXdYtg.png" /></figure><p>So far in this series, we’ve mostly treated GitHub Copilot as a very smart pair-programmer: it understands your code, your repo, your instructions, and your agents and it helps you write and review code faster.</p><p>But there’s still a big problem in most AI-assisted workflows:</p><blockquote><em>We often start coding before we’ve really agreed on </em><strong><em>what</em></strong><em> we’re building.</em></blockquote><p>Vibe-driven coding (“let’s see what Copilot comes up with”) is fun for prototypes, but risky for real products. Specs are written late or not at all. AI suggestions drift. Requirements move in people’s heads instead of in one shared place.</p><p><strong>SpecKit</strong> is GitHub’s open-source answer to that. It’s a toolkit for <strong>spec-driven development</strong> that sits on top of your AI coding assistants and forces a bit of structure into the chaos.</p><p>Instead of “ask Copilot and pray,” you build from a shared, living spec that both humans and AI can follow.</p><h3>What SpecKit Actually Is</h3><p>SpecKit is:</p><ul><li>a <strong>CLI tool</strong> (specify) you run in your project simplifying the setup process</li><li>a set of <strong>files and prompts</strong> added to your repo</li><li>a <strong>workflow</strong> built around specs instead of ad-hoc prompts</li></ul><p>It doesn’t replace GitHub Copilot. It <strong>wraps</strong> Copilot (and other agents like Claude Code, Gemini CLI, Cursor) in a structured process so that all the code it generates is grounded in a single source of truth: your spec.</p><p>At a high level, SpecKit organizes work into phases:</p><ol><li>define project principles (the “constitution”)</li><li>write a clear specification</li><li>clarify gaps</li><li>create a plan</li><li>break it into tasks</li><li>implement with an AI assistant</li><li>analyze for gaps and inconsistencies</li></ol><h3>Spec-Driven Development in a Nutshell</h3><p>Spec-driven development means:</p><ul><li><strong>You start with a spec</strong>, not a prompt.</li><li>The spec is written in a structured way and lives in your repo.</li><li>AI agents read this spec (plus your code) to plan, generate, and validate changes.</li></ul><p>Instead of “Copilot, build me a dashboard,” you first write down:</p><ul><li>what the dashboard must show</li><li>how it should behave</li><li>how it fits into the system</li><li>constraints, edge cases, success criteria</li></ul><p>SpecKit then turns that into a repeatable flow your AI assistant can follow. You get less guesswork and more predictable outcomes.</p><h3>The SpecKit Workflow: From Idea to Code</h3><p>You can install SpecKit on your machine first or simply run:</p><pre>uvx --from git+https://github.com/github/spec-kit.git specify init my-project</pre><p>This bootstraps your project with SpecKit’s structure. During the setup steps you can select your preferred coding agent.</p><p>From there, SpecKit gives you a set of structured commands (usually exposed as slash-commands in the agent’s chat) such as:</p><ul><li><strong>/constitution </strong>— define your project’s governing principles (quality, testing, UX, performance).</li><li><strong>/specify </strong>— describe what you want to build and why (requirements, scenarios, user stories).</li><li><strong>/clarify</strong> — have the agent ask you targeted questions about missing or ambiguous details.</li><li><strong>/plan</strong> — turn the spec into an implementation plan with architecture and technology choices.</li><li><strong>/tasks</strong> — break the plan into concrete, actionable tasks.</li><li><strong>/analyze</strong> — check consistency between spec, plan, and tasks.</li><li><strong>/implement </strong>— let the agent execute the tasks and generate code according to the plan.</li></ul><p>The phases are simple, but powerful:</p><ol><li><strong>Foundation</strong> — /constitution, /specify, /clarify</li><li><strong>Design</strong> — /plan</li><li><strong>Execution</strong> — /tasks, /implement</li><li><strong>Verification</strong> — /analyze</li></ol><p>You’re always working against an explicit, versioned artifact.</p><h3>How SpecKit Works With GitHub Copilot</h3><p>SpecKit is deliberately <strong>agent-agnostic</strong>: it supports GitHub Copilot, Claude Code, Gemini CLI, Cursor, and others. But the GitHub story is especially nice.</p><p>When you run <em>specify init</em> and select copilot, SpecKit adds a <em>.github</em> folde<strong>r</strong> with prompt definitions and custom agents for Copilot. This wires up the slash-commands so they’re available inside Copilot Chat in your project but also usable on GitHub.com. It gives Copilot a structured way to walk through specify → plan → tasks → implement</p><p>From your point of view as a developer you open the repo in VS Code with GitHub Copilot enabled. You see commands like <em>/speckit.specify</em>, <em>/speckit.plan</em>, <em>/speckit.tasks</em> in Copilot’s chat and it also suggests the next step automatically.</p><p>Copilot then uses the spec and plan artifacts SpecKit created as context when generating or editing code. Over time, the spec becomes the <strong>source of truth</strong> for your AI-assisted development.</p><h3>A Day in the Life With SpecKit + Copilot</h3><p>Picture this as a dev or tech lead:</p><p>You want to add a new <strong>“Team Reports”</strong> feature to your internal dashboard. Instead of opening the editor and immediately typing “build a reporting view” into Copilot, you start in SpecKit.</p><p>You run <strong>/constitution</strong> once for the project and encode rules like “always write tests for data access,” “prefer accessibility-friendly UI patterns,” and “error messages must be actionable.”</p><p>Then for this feature:</p><ol><li><strong>/specify</strong> — you describe what Team Reports should do: which metrics, which filters, who uses it, performance requirements, empty state behavior, export options.</li><li><strong>/clarify </strong>— SpecKit (via Copilot) asks clarifying questions:<br>- Do reports need to be exportable to CSV?<br>- How should permissions work?<br>- What’s the time range we must support?</li><li><strong>/plan</strong> — based on the clarified spec, SpecKit and Copilot propose architecture choices: where to put the API, which existing components to reuse, which database access patterns to follow.</li><li><strong>/tasks</strong> — the plan is broken into tasks: backend endpoint, data aggregation layer, UI components, tests, documentation.</li><li><strong>/implement</strong> — Copilot starts implementing tasks in your repo, guided by the spec and the plan instead of one giant prompt.</li></ol><p>At each step, you can inspect and edit the generated spec, plan, and tasks. They live as files in your project, under version control. Copilot’s job is to fill in code and details that align with those documents.</p><p>You end up with:</p><ul><li>a written, reviewable spec</li><li>a traceable plan</li><li>a set of tasks you could assign to humans or to Copilot</li><li>code that reflects the agreed-upon design</li></ul><p>This is the kind of workflow that makes AI coding feel less like gambling and more like engineering.</p><h3>Where SpecKit Really Helps</h3><p>SpecKit is especially useful when:</p><p><strong>The problem is non-trivial.</strong> If a change touches multiple services, involves real business rules, or has long-term impact, investing in a spec up front saves you from speculative coding and rewrites.</p><p><strong>Multiple people and agents are involved.</strong> A shared spec gives both humans and agents the same reference point. It reduces misunderstandings, and makes code reviews easier because there’s a “contract” to review against.</p><p><strong>You care about repeatability.</strong> Instead of each prompt being a unique snowflake, you follow a reproducible pattern: constitution → spec → plan → tasks → implement. This is appealing for teams that want to standardize how they use AI.</p><p><strong>You’re sick of vibe-coding.</strong> If you’ve ever thought “I don’t trust AI to touch this part of the code,” SpecKit is one way to tighten the guardrails so that both you and Copilot have a clear, shared understanding first.</p><p>For team leads, the big win is transparency: you can read the spec and plan, give feedback there, and only then let Copilot loose on the implementation.</p><h3>Limitations and Gotchas</h3><p>SpecKit isn’t magic, and it’s not a good fit for everything.</p><p>A few practical limitations:</p><p><strong>You pay an up-front cost.</strong> Writing specs, clarifying them, and reviewing plans takes time. For very small one-off changes, this overhead may not be worth it.</p><p><strong>Quality depends on the spec.</strong> Garbage in, garbage out still applies. If the spec is vague or contradictory, AI-generated code will be too. SpecKit helps you structure your thinking but it can’t make decisions for you.</p><p><strong>It doesn’t replace design or reviews.</strong> SpecKit supports good engineering; it doesn’t replace architectural thinking or human oversight. You still need to decide what’s right for your system and review what the agent produces.</p><p>Used thoughtfully, though, SpecKit is one of the more promising ways to make AI coding less chaotic and more trustworthy.</p><h3>Takeaway</h3><p>SpecKit shifts the focus from “prompting harder” to <strong>planning better</strong>.</p><p>Instead of throwing vague tasks at coding agents and hoping for the best, you:</p><ul><li>capture your intent as a structured spec</li><li>refine it until it’s unambiguous</li><li>turn it into a plan and tasks</li><li>let Copilot implement within that frame</li></ul><p>For developers and leads who care about reliability, traceability, and long-term maintainability, SpecKit + Copilot is a compelling combination: AI as an accelerator, but anchored in an explicit specification you can read, review, and evolve.</p><h3>Other articles of this GitHub Copilot series:</h3><p><a href="https://medium.com/arconsis/part-1-copilot-coding-review-agents-copilot-as-an-active-contributor-5431eb402d1e"><strong>Part 1: Coding &amp; Review Agents</strong></a><strong><br></strong>What the new Copilot agents do, how they open PRs, and how they fit into your day-to-day workflow.</p><p><a href="https://medium.com/arconsis/part-2-custom-instructions-how-to-make-github-copilot-work-the-way-you-work-7886fc771283"><strong>Part 2: Custom Instructions</strong></a><strong><br></strong>How to teach Copilot your team’s conventions, from repo-wide rules to path-specific instruction files.</p><p><a href="https://medium.com/arconsis/part-3-custom-agents-turning-github-copilot-into-a-team-of-specialists-a3af2ddba508"><strong>Part 3: Custom Agents</strong></a><strong><br></strong>Creating specialized AI teammates (like a Testing Coach or Docs Agent) that act on your code and open PRs.</p><p><a href="https://medium.com/arconsis/part-4-github-copilot-spaces-giving-copilot-real-understanding-of-your-project-a5dca2d5d97d"><strong>Part 4: Copilot Spaces</strong></a><strong><br></strong>Turning Copilot into a project-aware assistant by giving it curated context from your code and documentation.</p><p><a href="https://medium.com/arconsis/part-5-speckit-turning-github-copilot-into-a-specification-driven-teammate-c84c3cfc2ca4"><strong>Part 5: SpecKit</strong></a><strong><br></strong>Using spec-driven development with SpecKit so Copilot implements features based on a shared, versioned specification.</p><h3>Useful Links</h3><ul><li><a href="https://speckit.org/"><strong>SpecKit — Official site</strong></a><strong> — </strong>Overview, philosophy, usage guide, and examples for spec-driven development with AI.</li><li><a href="https://github.com/github/spec-kit"><strong>GitHub — SpecKit repository</strong></a><strong> — </strong>Source code, issues, docs, and CLI reference.</li><li><a href="https://github.blog/ai-and-ml/generative-ai/spec-driven-development-with-ai-get-started-with-a-new-open-source-toolkit/"><strong>GitHub Blog — Spec-driven development with AI</strong></a><strong> — </strong>Background on why SpecKit exists and how it fits into AI-assisted workflows.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c84c3cfc2ca4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arconsis/part-5-speckit-turning-github-copilot-into-a-specification-driven-teammate-c84c3cfc2ca4">Part 5: SpecKit. Turning GitHub Copilot Into a Specification-Driven Teammate</a> was originally published in <a href="https://medium.com/arconsis">arconsis</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Part 4: GitHub Copilot Spaces. Giving Copilot Real Understanding of Your Project]]></title>
            <link>https://medium.com/arconsis/part-4-github-copilot-spaces-giving-copilot-real-understanding-of-your-project-a5dca2d5d97d?source=rss----c3dfaac5c9ee---4</link>
            <guid isPermaLink="false">https://medium.com/p/a5dca2d5d97d</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[github-copilot]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Jonas Stubenrauch]]></dc:creator>
            <pubDate>Tue, 17 Feb 2026 08:35:11 GMT</pubDate>
            <atom:updated>2026-03-22T13:56:49.926Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*ar-6dZwkAQCyFNYrC-YmTA.png" /></figure><p>Copilot Spaces are dedicated workspaces in GitHub where you bundle the materials Copilot should use as context for a specific topic, project, or initiative. Think of a Space as a curated knowledge pack for Copilot. You decide which sources matter, and Copilot uses those sources when you chat inside that Space or when you work with agents connected to it.</p><p>A Space is not a new documentation system and it is not related to the older concept of “GitHub Spaces.” It is a Copilot feature that lives directly on GitHub and allows you to assemble a stable, reusable context. That context stays the same across conversations and can be shared with others, which makes it useful for ongoing work rather than one-off questions.</p><h3>What is a Copilot Space?</h3><p>A Copilot Space is a workspace tied to your GitHub account or organization that contains all the important context for a particular project, domain, or feature area.</p><p>Inside a Space you can bring together:</p><ul><li>code files or entire repositories</li><li>architecture and design documents</li><li>API specifications</li><li>onboarding guides and internal FAQs</li><li>additional supported files uploaded directly to the space</li><li>custom instructions that describe how Copilot should behave in that Space</li></ul><p>All of this becomes searchable context for Copilot. When you ask questions or request help inside the Space, Copilot answers based on these sources.</p><h3>Why Copilot Spaces Matter</h3><p>As projects grow, knowledge spreads across many places. Code lives in repositories, decisions live in pull requests and issues, requirements live in documents, and context often lives in people’s heads. Copilot Spaces matter because they provide a way to bring this information together in a form that can be reused consistently.</p><p>Spaces create a single, shared place where important project materials are collected. Instead of repeatedly gathering files, links, and documents for every conversation, you define the relevant sources once and reuse them. This makes it easier to work against the same references over time, whether you are exploring an unfamiliar part of the system or returning to a topic after a break.</p><p>They also reduce maintenance effort. When a Space includes repositories or files from GitHub, the content is always taken from the current state of the default branch. There is no separate copy to keep in sync and no manual updates required when the code changes. The Space naturally reflects how the project evolves.</p><p>Another important aspect is consistency. Because the same Space can be used across conversations and shared with others, Copilot’s answers are grounded in the same set of sources for everyone. This helps avoid situations where different people receive different explanations simply because they provided different context.</p><p>Finally, Spaces are designed for collaboration. A Space can be owned by an organization and shared with individuals or teams. That makes it possible to establish common reference points for onboarding, planning, or documentation work, and to ensure that everyone is working with the same curated context.</p><h3>What You Put Into a Space</h3><p>You don’t have to mirror your whole repository layout; it’s usually better to be deliberate. A Space works best when you select the materials that answer the most common questions.</p><p>For example, you might attach just the core modules of a service, the top-level architecture diagram, a couple of ADRs, and the main API spec. For a front-end project, you might include the design system, a style guide, and examples of “good” components. For onboarding, you might bring in the README, a “getting started” doc, and a few representative files.</p><p>On top of the sources themselves, each Space has a panel for <strong>custom instructions</strong>. Here you describe Copilot’s role in that Space. You might say:</p><blockquote><em>“You are an expert on our billing system. Use the attached docs and code to explain how it works, and prefer linking to files when you refer to implementation details. If something is unclear, indicate which source appears inconsistent.”</em></blockquote><p>This simple description gives Copilot a persona and a purpose. Combined with the attached sources, that persona becomes surprisingly effective.</p><h3>How You Use Copilot Spaces Day to Day</h3><p>Spaces change how you interact with Copilot, both in the browser and in your IDE.</p><p>On GitHub.com, each Space has its own chat. You open the Space, see the instructions and the list of attached sources, and then ask questions directly in that context. You might ask for an explanation of a subsystem, a summary of a spec, suggestions for how to extend an existing feature, or help locating the right place to implement a change. Copilot’s answers are drawn from the sources in the Space.</p><p>In the IDE, Copilot can be connected to a Space via MCP. That means when you’re working in VS Code or JetBrains, you can ask things like “Explain the architecture from the Copilot Space” or “How does the payment flow fit into this function?” and Copilot will reach into the Space, take its context, and respond based on your project.</p><h3>Typical Workflows Copilot Spaces Improve</h3><p>Spaces are useful in many situations, but a few stand out as especially impactful.</p><h4>Onboarding</h4><p>A dedicated onboarding Space can collect the core pieces of knowledge a new developer needs: where the important services live, how the system is deployed, what the main data flows look like, and how to run things locally. Instead of scheduling multiple “explain the system” meetings, you give new colleagues access to the Space and encourage them to ask Copilot questions there. If something is missing or unclear, you update the Space once and every future newcomer benefits.</p><h4>Project or Feature Spaces</h4><p>When you start a new project or major feature, you can create a Space just for that effort. You attach the product spec, the current implementation, any diagrams or prototype code, and maybe key issues or PRs. Then you use Copilot to break down the spec into tasks, to highlight possible risks, or to check whether the code matches the intent in the documents. As the feature evolves, the Space becomes the central place where its context lives.</p><h4>Troubleshooting and Incident Response</h4><p>For a tricky bug or incident, a temporary Space can be set up with logs, recent changes, and the relevant parts of the code. The team can ask Copilot to spot patterns, relate current logs to past issues, or suggest likely failure points. It doesn’t replace human debugging, but it can speed up pattern recognition and help correlate things that would take a while to triage manually.</p><h4>Documentation and Knowledge Extraction</h4><p>Spaces are a natural home for documentation work. If you collect specs, code comments, and configuration in a Space, Copilot can help you write or update user-facing docs, API references, or internal runbooks. You ask it to “draft a high-level description of this service for the onboarding guide” and it uses what you attached. People still review and edit the drafts, but they no longer start from a blank page.</p><h3>Sharing and Permissions</h3><p>Spaces are built to work in team environments.</p><p>You can create them for yourself or under an organization. Organization-owned Spaces can be shared with specific people or teams and have roles that roughly match what you’d expect: admins manage settings and sharing, editors curate the content, and viewers just use the Space.</p><p>For personal Spaces, you can still share with individual collaborators, and you can even make some Spaces public as read-only for documentation or open-source use cases. Public spaces are only useful if the underlying repos or docs are public, and GitHub still enforces all normal repository permissions: a Space never becomes a shortcut around access control.</p><p>The key idea is that once a Space is shared, everyone on the team has access to the same curated context, and Copilot gives them consistent, up-to-date answers based on that context.</p><h3>Takeaway</h3><p>A Copilot Space lets you:</p><ul><li>collect and curate the context that really matters</li><li>guide Copilot’s behavior with targeted instructions</li><li>share that context safely across your team</li><li>keep knowledge alive and accessible even as people and code change</li></ul><p>Combined with Custom Instructions and Custom Agents, Copilot Spaces turn Copilot from “smart autocomplete with chat” into a genuine collaborator that knows your systems, your standards, and your history.</p><p>If you’re already using Copilot, creating one or two carefully chosen Spaces is an easy next step that can noticeably improve how useful Copilot feels in everyday work.</p><h3>Other articles of this GitHub Copilot series:</h3><p><a href="https://medium.com/arconsis/part-1-copilot-coding-review-agents-copilot-as-an-active-contributor-5431eb402d1e"><strong>Part 1 — Coding &amp; Review Agents</strong></a><strong><br></strong>What the new Copilot agents do, how they open PRs, and how they fit into your day-to-day workflow.</p><p><a href="https://medium.com/arconsis/part-2-custom-instructions-how-to-make-github-copilot-work-the-way-you-work-7886fc771283"><strong>Part 2 — Custom Instructions</strong></a><strong><br></strong>How to teach Copilot your team’s conventions, from repo-wide rules to path-specific instruction files.</p><p><a href="https://medium.com/arconsis/part-3-custom-agents-turning-github-copilot-into-a-team-of-specialists-a3af2ddba508"><strong>Part 3 — Custom Agents</strong></a><strong><br></strong>Creating specialized AI teammates (like a Testing Coach or Docs Agent) that act on your code and open PRs.</p><p><a href="https://medium.com/arconsis/part-4-github-copilot-spaces-giving-copilot-real-understanding-of-your-project-a5dca2d5d97d"><strong>Part 4 — Copilot Spaces</strong></a><strong><br></strong>Turning Copilot into a project-aware assistant by giving it curated context from your code and documentation.</p><p><a href="https://medium.com/arconsis/part-5-speckit-turning-github-copilot-into-a-specification-driven-teammate-c84c3cfc2ca4"><strong>Part 5 — SpecKit</strong></a><strong><br></strong>Using spec-driven development with SpecKit so Copilot implements features based on a shared, versioned specification.</p><h3>Useful Links</h3><ul><li><a href="https://docs.github.com/en/copilot/concepts/context/spaces">About GitHub Copilot Spaces</a> — Copilot Spaces overview</li><li><a href="https://docs.github.com/en/copilot/how-tos/provide-context/use-copilot-spaces">GitHub Copilot Spaces</a> — How to create, use and share copilot spaces</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a5dca2d5d97d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arconsis/part-4-github-copilot-spaces-giving-copilot-real-understanding-of-your-project-a5dca2d5d97d">Part 4: GitHub Copilot Spaces. Giving Copilot Real Understanding of Your Project</a> was originally published in <a href="https://medium.com/arconsis">arconsis</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[AI-Powered Testing Automation with Appium MCP]]></title>
            <link>https://medium.com/arconsis/ai-powered-testing-automation-with-appium-mcp-0e6135cfe069?source=rss----c3dfaac5c9ee---4</link>
            <guid isPermaLink="false">https://medium.com/p/0e6135cfe069</guid>
            <category><![CDATA[mcps]]></category>
            <category><![CDATA[appium]]></category>
            <category><![CDATA[automated-testing]]></category>
            <dc:creator><![CDATA[Mario Walz]]></dc:creator>
            <pubDate>Thu, 12 Feb 2026 12:20:05 GMT</pubDate>
            <atom:updated>2026-02-12T12:20:04.282Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qV19EdDCUTTgLHPRyC2RWw.png" /><figcaption>Redefining Automated Testing with Appium MCP</figcaption></figure><p>Appium MCP is a <strong>Model Context Protocol (MCP) </strong>server that exposes the Appium mobile automation framework as a structured set of tools for AI assistants.</p><p>In practical terms, this means an agent, whether in an IDE, chat interface, or development environment, can control Android and iOS simulators, emulators, and real devices through Appium, without requiring you to manually write every imperative test step.</p><p>Instead of writing everything yourself, you describe what you want in natural language and the MCP server translates that into actual Appium commands executed on the device.</p><h3>The Reality of UI Testing</h3><p>From experience, across both small and large projects, UI tests are often:</p><ul><li>Missing entirely</li><li>Implemented with low coverage</li><li>Started with good intentions, but eventually abandoned</li></ul><p>The common pattern I’ve noticed: A team invests effort, writes tests, but over time they become brittle, outdated, and expensive to maintain. Eventually, they’re disabled. This is where AI can make the difference.</p><h3>What the MCP Provides</h3><p>The MCP server exposes structured tool categories such as:</p><ul><li>Platform &amp; Device Setup</li><li>Session Management</li><li>Context Management</li><li>Element Discovery &amp; Interaction</li><li>Screen &amp; Navigation</li><li>App Management</li><li>Test Generation &amp; Documentation</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cqZfFBzbFIKZnaesHPCIwg.png" /><figcaption>Part of the toolset exposed by the MCP</figcaption></figure><p>Instead of writing complex test scripts or knowing the mechanics of Apple’s XCUIAutomation (or Android equivalents), you simply describe your intent. The MCP server handles:</p><ul><li>Translating natural language into Appium commands</li><li>Executing actions on the device</li><li>Resolving platform-specific differences</li></ul><h3>Getting started</h3><p>My setup was straightforward and focused on iOS only, but the Android setup should look very similar.</p><ul><li>macOS with Xcode &amp; Command Line Tools installed</li><li>iOS Simulator set up</li><li>WebDriverIO installed (via npm), the CLI sets ups everything you need, e.g. the Appium Server</li></ul><p>After that, I configured the MCP server in VS Code:</p><pre>{<br>  &quot;servers&quot;: {<br>    &quot;appium-mcp&quot;: {<br>      &quot;command&quot;: &quot;npx&quot;,<br>      &quot;args&quot;: [&quot;appium-mcp@latest&quot;],<br>      &quot;env&quot;: {<br>        &quot;CAPABILITIES_CONFIG&quot;: &quot;capabilities.json&quot;<br>      },<br>      &quot;type&quot;: &quot;stdio&quot;<br>    }<br>  }<br>}</pre><p>And defined device capabilities in a capabilities.json file (iOS example):</p><pre>{<br>  &quot;ios&quot;: {<br>    &quot;appium:app&quot;: // Path to your app,<br>    &quot;appium:deviceName&quot;: &quot;iPhone 17 Pro&quot;,<br>    &quot;appium:platformVersion&quot;: &quot;26.1&quot;,<br>    &quot;appium:automationName&quot;: &quot;XCUITest&quot;,<br>    &quot;appium:udid&quot;: &quot;92964687-3100-4CD2-9207-51D7CB10D037&quot;<br>  }<br>}</pre><h3>First Results: Letting the Agent Explore</h3><p>To test its capabilities, I intentionally used vague prompts, such as:</p><blockquote><em>Open the app and go through all list items. Open the respective screens and try to interact with UI elements like toggles, sliders, and buttons. Make assumptions about expected behavior. Add tests for all screens in a file.</em></blockquote><p>Despite the lack of specificity, the results were surprisingly solid.</p><p><strong>The agent:</strong></p><ul><li>Navigated through screens</li><li>Identified interactive elements</li><li>Generated structured test files</li><li>Made reasonable assumptions about expected behavior</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Me3UBt8YjkA2kh8essi65w.png" /><figcaption>Interacting with the agent</figcaption></figure><p>Without any prior Appium experience, I ended up with a generated test file that was around 600 lines long, covering initial screens. With minor adjustments, the scripts were fully functional.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bYyS_bg1BqrrI_DOz2Emqg.png" /><figcaption>First test files I created with no Appium experience</figcaption></figure><h3>Lowering the Barrier to Entry</h3><p>It becomes clear very quickly: anyone can start contributing to UI test automation almost immediately. You no longer need deep expertise in Appium internals, platform-specific selectors or device-specific quirks to get started.</p><p>The AI analyzes the page source, suggests fixes intelligently, adapts to platform differences, and assists with debugging. Hours of manual effort, especially when it comes to identifying the correct selectors, are drastically reduced.</p><p>That said, platform knowledge does not become irrelevant. In more complex applications, unexpected action sheets may appear, permission dialogs may need to be dismissed, or platform-specific behaviors can interrupt flows in non-deterministic ways. Handling these edge cases still requires an understanding of how iOS, Android, or other platforms behave in real-world scenarios. However, the fundamentals and the majority of repetitive work are covered, which significantly lowers the entry barrier and accelerates productivity.</p><h3>Beyond Testing: Appium as a Structured App Crawler</h3><p>Writing UI tests is only one part of the story. Once you realize that the MCP has access to the full UI graph exposed by Appium, it becomes clear that this setup can be used for far more than test automation. In practice, it turns Appium into a structured, controllable crawler that can explore your app, understand what is rendered on screen, and generate meaningful output based on what it discovers.</p><h4>App Exploration &amp; Documentation</h4><p>One powerful use case is automated app exploration and documentation. Instead of manually maintaining feature documentation that inevitably drifts out of sync, the agent can traverse real user flows such as onboarding, checkout, or settings. While navigating through the app, it can capture screenshots, extract screen titles, and generate short descriptions of each view.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FAFyqZCOYod0%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DAFyqZCOYod0&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FAFyqZCOYod0%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/c1b242b48706648fa16175d5cd4e0494/href">https://medium.com/media/c1b242b48706648fa16175d5cd4e0494/href</a></iframe><p>Because this documentation is derived directly from the running application, it stays aligned with what is actually shipped. In addition, the agent can outline the full navigation hierarchy, which can serve as a foundation for UX reviews, stakeholder communication, or even as input for information architecture work. Over time, this approach can replace static documentation with continuously updated, living artifacts.</p><h4>Accessibility Reports</h4><p>Another compelling application is automated accessibility auditing, which becomes more and more important as accessibility requirements are increasingly enforced by law in many countries. Since the MCP can inspect every reachable screen, it can systematically analyze accessibility metadata such as labels, traits, focus behavior, and enabled states. This allows it to identify missing labels, ambiguous controls, or common accessibility anti-patterns.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/886/1*3SumBfLUGIVGJZLPMhtJxw.png" /><figcaption>Generated Accessibility Report with critical issues and recommendations</figcaption></figure><p>Instead of generic reports, the output can reference the exact screens and UI elements involved, making the findings directly actionable for developers and designers.</p><h4>Finding Dead Ends</h4><p>By building a navigation graph of the application, the agent can detect structural issues in user flows. It can identify screens where users have no valid next actions, encounter broken back navigation, face permanently disabled call-to-action buttons, or become trapped in navigation loops.</p><p>More importantly, it can provide reproducible paths that show exactly how to reach these problematic states. This transforms vague UX concerns into concrete, testable scenarios and makes it significantly easier to resolve navigation issues early.</p><h4>Detecting Runtime Issues</h4><p>Exploratory navigation on real devices and across different OS versions also helps uncover runtime issues that often remain invisible in CI pipelines. Certain problems, race conditions, permission prompt edge cases, or memory pressure crashes, may only surface under real-world conditions.</p><p>By automatically exploring flows and device context, the agent provides valuable debugging information. This shortens the feedback loop and makes it far easier to reproduce and fix issues that would otherwise be difficult to trace.</p><h3>The Other Side of the Coin</h3><p>Appium MCP is powerful, but it also comes with trade-offs. Because the agent needs to inspect the UI tree, reason about navigation flows, and generate or adjust code, it can consume a significant number of tokens, which may become costly for large applications or extended sessions. In addition, typical action latency ranges from two to four seconds. When testing a complex app with many screens and interactions, this can result in very long execution times.</p><p>Complex applications may also still require solid platform knowledge. If accessibility standards are not properly followed, for example, if identifiers are missing or inconsistent, automation becomes less reliable and more difficult to maintain. In those cases, human expertise is still necessary to stabilize and guide the system.</p><h3>Integrating into Day-to-Day Development</h3><p>Here’s how I would incorporate Appium MCP into a real-world workflow:</p><h4>Define AI Instructions</h4><p>Create an instruction file for the agent that defines:</p><ul><li>Test structure conventions</li><li>Naming patterns</li><li>Commenting guidelines</li><li>Development best practices</li></ul><p>This ensures consistency in AI-generated tests.</p><h4>Generate a Full Cross-Platform Test Suite</h4><p>Use the agent to generate:</p><ul><li>Feature-based test suites</li><li>Tests derived from structured feature documentation (in an ideal scenario, the AI is fed user stories)</li></ul><h4>Separate AI from CI Cost</h4><p>Running AI-powered tests on every commit may be too expensive. Instead:</p><ul><li>Use pure Appium for CI runs</li><li>Run the full suite nightly</li><li>Keep AI out of critical CI paths</li></ul><h4>Self-Healing Tests</h4><p>When nightly UI tests fail:</p><ul><li>Trigger MCP to analyze failures</li><li>Suggest fixes</li><li>Automatically create pull requests</li></ul><p>The next morning, developers review and merge. Maintenance overhead drops significantly and human interaction stays minimal.</p><h4>Automated Weekly Documentation</h4><p>Set up a weekly job that:</p><ul><li>Crawls the app</li><li>Generates a Markdown overview of main screens</li><li>Embeds screenshots</li><li>Updates feature descriptions</li></ul><p>This becomes the single source of truth for exports, PDFs, and internal documentation.</p><h3>Final Thoughts</h3><p>Appium MCP changes how we can think about UI automation. Instead of building brittle tests that gradually become outdated and unreliable, we can move toward AI-assisted automation that evolves alongside the product. It lowers the barrier to entry, reduces maintenance effort, and opens the door to capabilities that go beyond traditional testing.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0e6135cfe069" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arconsis/ai-powered-testing-automation-with-appium-mcp-0e6135cfe069">AI-Powered Testing Automation with Appium MCP</a> was originally published in <a href="https://medium.com/arconsis">arconsis</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Part 3: Custom Agents. Turning GitHub Copilot into a Team of Specialists]]></title>
            <link>https://medium.com/arconsis/part-3-custom-agents-turning-github-copilot-into-a-team-of-specialists-a3af2ddba508?source=rss----c3dfaac5c9ee---4</link>
            <guid isPermaLink="false">https://medium.com/p/a3af2ddba508</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[github-copilot]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[agentic-ai]]></category>
            <dc:creator><![CDATA[Jonas Stubenrauch]]></dc:creator>
            <pubDate>Thu, 29 Jan 2026 09:46:19 GMT</pubDate>
            <atom:updated>2026-03-22T13:56:23.206Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lHewq4aFZ76MwIcOsvMrrA.png" /></figure><p>If Custom Instructions teach Copilot <em>how your team works</em>, <strong>Custom Agents</strong> let you decide <em>who</em> Copilot is in a given moment.</p><p>Instead of one generic AI assistant, you can define specialized personas: a testing expert, a UI layout helper, a backend service guru, a documentation partner. Each Custom Agent has its own profile, scope, and behavior.</p><p>This article explains what Custom Agents are, how they differ from Custom Instructions, and how they can help with both code and recurring tasks.</p><h3>Why Custom Agents?</h3><p>Even with good repository instructions, you often need deeper specialization.</p><p>Maybe your tests follow strict patterns, your backend services have complex rules, or your UI must adhere to a design system. You can write all of that down, but a single global Copilot persona will always feel a bit average.</p><p>Custom Agents solve this by letting you define separate AI “teammates” for different concerns. Instead of “Copilot, please be good at everything,” you can say:</p><ul><li>“Use the Testing Coach for test design and coverage questions.”</li><li>“Use the UI Agent when working on layouts and design-system usage.”</li><li>“Use the Docs Agent for changelog updates and release notes.”</li></ul><p>Each agent gets a dedicated profile, so it can focus on one job and do it well.</p><h3>What a Custom Agent Actually Is</h3><p>Technically, a Custom Agent is just a configuration file in your repository (for example under .github/agents/) that describes a persona:</p><ul><li>who it is</li><li>what it knows</li><li>how it should behave</li><li>what it should avoid</li></ul><p>You can think of it as a “mini spec” for a role on your team.</p><h3>Conceptual example: the Testing Coach</h3><p>Imagine a file named: <em>.github/agents/testing-coach.agent.md</em></p><p>Inside, you describe the agent like you would brief a new team member:</p><pre>---<br>name: testing-coach<br>description: Agent specializing in helping developers design and improve automated tests<br>---<br><br>You are the Testing Coach for this repository.<br>You help developers design and improve automated tests.<br>You know our testing framework, naming conventions, and folder structure.<br>You prefer small, focused tests with clear Arrange/Act/Assert structure.<br><br>When asked to add or update code, you always think about test impact.<br>Propose missing edge cases. Highlight untested behavior.<br>Never remove tests unless explicitly requested.<br>Don&#39;t introduce new test frameworks without agreement.</pre><p>The optional name will be shown when selecting the custom agent, and the mandatory description helps Copilot to know when to use your agent.</p><p>There are also options to specify <em>handoffs</em> to other agents and configure the <em>tools</em> the agent is allowed to use</p><p>Once this is in place, you can explicitly pick the <strong>Testing Coach</strong> in Copilot’s UI when:</p><ul><li>writing or refactoring tests</li><li>reviewing test coverage on a PR</li><li>planning how to test a new feature</li></ul><p>Instead of a generic assistant, you get a focused test expert.</p><h3>How Developers Use Custom Agents</h3><p>Custom Agents show up in several places and workflows. When you assign an issue to Copilot, you can choose which agent should handle it. If you pick the Testing Coach for a “add tests for X” ticket, Copilot will:</p><ul><li>spin up a Coding Agent <strong>under that persona</strong>,</li><li>generate or refactor tests according to the profile,</li><li>and open a <strong>pull request</strong> with the changes.</li></ul><p>That PR behaves just like one created by a human: new branch, commits, and a summary. The difference is that the AI writing it is specialized in testing.</p><p>The same is true for other agents you define: a documentation agent can open a PR updating release notes; a backend agent can open a PR updating an API handler and its tests.</p><h3>Recurring tasks: documentation and information extraction</h3><p>Custom Agents are also useful for non-code tasks that repeat every week or sprint.</p><p>For example you could create agents like:</p><ul><li><strong>Docs Agent: </strong>writes changelog entries or update notes based on PRs or issues.</li><li><strong>Release Summary Agent: </strong>scans merged PRs and produces a human-readable release summary.</li><li><strong>Info Extraction Agent: </strong>reads code or docs and extracts specific information (feature flags, endpoints, database tables, public APIs).</li></ul><p>Because these agents have a defined role, they are better at producing consistent, predictable output.</p><h3>Custom Instructions vs Custom Agents</h3><p>Custom Instructions and Custom Agents complement each other, but they are not the same:</p><ul><li><strong>Custom Instructions</strong> describe the general rules of the repository: architecture boundaries, coding style, review expectations, testing basics. They apply broadly, often to everyone and everything.</li><li><strong>Custom Agents</strong> describe a specific role: the Testing Coach, the UI Helper, the Payment Service Expert, the Docs Agent. They are used when you explicitly select that persona.</li></ul><p>You usually want both. Instructions set the baseline; agents specialize.</p><h3>Where Custom Agents Really Shine</h3><p>Custom Agents are most useful when:</p><ul><li>the work is repetitive but non-trivial (tests, docs, summaries),</li><li>the architecture has strict patterns (e.g. Clean Architecture, MVVM, specific layering),</li><li>or you have parts of the codebase that constantly attract the same questions.</li></ul><p>The Docs Agent is a great example. It can reliably draft release notes or API docs every time a set of PRs merges, so engineers don’t have to start from a blank page.</p><h3>Designing a Useful Custom Agent</h3><p>When you design a Custom Agent, think like a tech lead onboarding a new colleague. The profile should make clear:</p><ul><li>What the agent is responsible for (e.g. tests, docs, a specific service).</li><li>Which parts of the codebase and docs it should focus on.</li><li>What “good” looks like (e.g. small focused tests, use of a specific test library, consistent tone in docs).</li><li>What it must not do (e.g. changing DB schemas, introducing new dependencies, ignoring existing patterns).</li></ul><h3>Limitations You Should Keep in Mind</h3><p>Custom Agents are powerful, but they have limits:</p><ul><li>They rely on your existing instructions, code, and docs. If those are weak, the agent will be too.</li><li>They don’t replace senior engineers. They assist; they don’t decide architecture.</li><li>They need maintenance. When your testing strategy or docs style changes, you should update the profiles.</li><li>They can still produce wrong or incomplete results, so human review and CI remain essential.</li></ul><h3>Takeaway</h3><p>Custom Agents turn GitHub Copilot from “one generic AI assistant” into a <strong>small team of specialists</strong> that you design:</p><ul><li>A Testing Coach that helps design and maintain tests, and can open PRs to add or improve them.</li><li>A Docs Agent that drafts changelogs and documentation updates.</li><li>Other agents tailored to your architecture, domain, or recurring workflows.</li></ul><p>Combined with Custom Instructions and path-specific rules, Custom Agents give you a way to embed your engineering culture and recurring processes directly into Copilot.</p><p>In the next article, we’ll look at <strong>Copilot Spaces. </strong>How to give Copilot rich context from your code, docs, and issues, so these agents can work with a more complete picture of your project.</p><h3>Other articles of this GitHub Copilot series:</h3><p><a href="https://medium.com/arconsis/part-1-copilot-coding-review-agents-copilot-as-an-active-contributor-5431eb402d1e"><strong>Part 1: Coding &amp; Review Agents</strong></a><strong><br></strong>What the new Copilot agents do, how they open PRs, and how they fit into your day-to-day workflow.</p><p><a href="https://medium.com/arconsis/part-2-custom-instructions-how-to-make-github-copilot-work-the-way-you-work-7886fc771283"><strong>Part 2: Custom Instructions</strong></a><strong><br></strong>How to teach Copilot your team’s conventions, from repo-wide rules to path-specific instruction files.</p><p><a href="https://medium.com/arconsis/part-3-custom-agents-turning-github-copilot-into-a-team-of-specialists-a3af2ddba508"><strong>Part 3: Custom Agents</strong></a><strong><br></strong>Creating specialized AI teammates (like a Testing Coach or Docs Agent) that act on your code and open PRs.</p><p><a href="https://medium.com/arconsis/part-4-github-copilot-spaces-giving-copilot-real-understanding-of-your-project-a5dca2d5d97d"><strong>Part 4: Copilot Spaces</strong></a><strong><br></strong>Turning Copilot into a project-aware assistant by giving it curated context from your code and documentation.</p><p><a href="https://medium.com/arconsis/part-5-speckit-turning-github-copilot-into-a-specification-driven-teammate-c84c3cfc2ca4"><strong>Part 5: SpecKit</strong></a><strong><br></strong>Using spec-driven development with SpecKit so Copilot implements features based on a shared, versioned specification.</p><h3>Useful Links &amp; References</h3><ul><li><a href="https://docs.github.com/en/copilot/concepts/agents/coding-agent/about-custom-agents"><strong>About Custom Agents</strong></a><strong> — </strong>official GitHub documentation describing what custom agents are and how they work</li><li><a href="https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents"><strong>Creating Custom Agents</strong></a> — guide showing how to create an agent profile in your repo</li><li><a href="https://docs.github.com/en/copilot/reference/custom-agents-configuration"><strong>Custom Agents Configuration</strong></a> — full documentation how to configure your custom agent</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a3af2ddba508" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arconsis/part-3-custom-agents-turning-github-copilot-into-a-team-of-specialists-a3af2ddba508">Part 3: Custom Agents. Turning GitHub Copilot into a Team of Specialists</a> was originally published in <a href="https://medium.com/arconsis">arconsis</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>