<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Microservice architecture</title>
        <description>A pattern language for microservices</description>
        <link>http://microservices.io</link>
        <atom:link href="http://microservices.io/feed.xml" rel="self" type="application/rss+xml" />
        
        <item>
            <title>Microservices Platforms - part 8: Getting started with platforms</title>
            <description>&lt;p&gt;This is the eighth article in a series based on my &lt;a href=&quot;/post/architecture/2025/11/23/qconsf-2025-microservices-platforms.html&quot;&gt;QCon San Francisco 2025 talk &lt;em&gt;Microservices Platforms: When Team Topologies Meets Microservices Patterns&lt;/em&gt;&lt;/a&gt;.
The articles in the series are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-when-team-topologies-meets-microservices-patterns-part-1/&quot;&gt;Microservices Platforms - part 1: Overview&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-2-service-foundation-platform/&quot;&gt;Microservices Platforms - part 2: Service foundation platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-3-security-platform/&quot;&gt;Microservices Platforms - part 3: Security platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-4-infrastructure-services-platform/&quot;&gt;Microservices Platforms - part 4: Infrastructure services platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-5-observability-platform/&quot;&gt;Microservices Platforms - part 5: Observability platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-6-build-platform/&quot;&gt;Microservices Platforms - part 6: Build platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-7-deployment-platform/&quot;&gt;Microservices Platforms - part 7: Deployment platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-8-getting-started-with-platforms/&quot;&gt;Microservices Platforms - part 8: Getting started with platforms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While creating the conference presentation, I came across a rather depressing article &lt;a href=&quot;https://thenewstack.io/why-up-to-70-of-platform-engineering-teams-fail-to-deliver-impact/&quot;&gt;Why Up to 70% of Platform Engineering Teams Fail to Deliver Impact&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It describes how most platform teams fail:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/i/qconsf-microservices-platforms-part-8/new-stack-platform-failiures.png&quot; alt=&quot;Slide 48&quot; style=&quot;width: 100%; margin-right: 1.5em; margin-bottom: 1em;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Based on my experiences over the years, I am not surprised.
In this article, I shall share a few thoughts about why platform engineering often fails and what can be done to increase the chances of success.&lt;/p&gt;

&lt;p style=&quot;font-size: 1.25em; font-weight: bold;&quot;&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-8-getting-started-with-platforms&quot;&gt;Read more (This post is for paying subscribers only)&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;need-help-with-modernizing-your-architecture&quot;&gt;Need help with modernizing your architecture?&lt;/h2&gt;

&lt;p&gt;I help organizations modernize safely and avoid creating a modern legacy system — a new architecture with the same old problems. If you’re planning or struggling with a modernization effort, I can help.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrisrichardson.net&quot;&gt;Learn more about my modernization and architecture advisory work →&lt;/a&gt;&lt;/p&gt;

</description>
            <pubDate>Wed, 03 Jun 2026 08:03:00 +0000</pubDate>
            <link>http://microservices.io//post/architecture/2026/06/03/qconsf-microservices-platforms-part-8.html</link>
            <guid isPermaLink="true">http://microservices.io//post/architecture/2026/06/03/qconsf-microservices-platforms-part-8.html</guid>
        </item>
        
        <item>
            <title>GenAI-based development platform - part 4: The coding agent sandwich pattern</title>
            <description>&lt;p&gt;This article describes the “coding agent sandwich” — an architecture pattern consisting of a tasty filling of LLM invocations sandwiched between two slices of plain old code (POC).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/i/genai/idea-to-code/coding-agent-sandwich-overview.png&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This article is part of a series about the GenAI-based development platform (a.k.a. harness) that I’ve been developing to make GenAI-based coding agents like Claude Code more productive, more secure and less frustrating.
The complete list of articles in the series is as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/01/29/about-idea-to-code.html&quot;&gt;Part 0 - My GenAI development workflow: Idea to Code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/09/genai-development-platform-part-1-development-guardrails.html&quot;&gt;Part 1 - Guardrails for GenAI coding agents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/17/overview-i2code-implement-agent-orchestrator.html&quot;&gt;Part 2 - How Idea to Code turns an idea into working, tested software&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/26/genai-development-platform-part-3-announcing-isolarium.html&quot;&gt;Part 3 - Announcing Isolarium, three flavors of secure sandboxes for GenAI-based coding agents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/05/19/genai-development-platform-part-4-coding-agent-sandwich-pattern.html&quot;&gt;Part 4 - The coding agent sandwich pattern&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The worked example is the &lt;a href=&quot;/post/architecture/2026/03/17/overview-i2code-implement-agent-orchestrator.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implement plan&lt;/code&gt; sub-workflow&lt;/a&gt;, which is the last step of &lt;a href=&quot;/post/architecture/2026/01/29/about-idea-to-code.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;idea-to-code&lt;/code&gt;, my open-source GenAI-based development workflow&lt;/a&gt;.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implement plan&lt;/code&gt; workflow uses test-driven development (TDD) to turn the generated plan into code.&lt;/p&gt;

&lt;p&gt;Before looking at the different parts of the sandwich, let’s start with an overview of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implement plan&lt;/code&gt; workflow.&lt;/p&gt;

&lt;h2 id=&quot;an-overview-of-the-implement-plan-workflow&quot;&gt;An overview of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implement plan&lt;/code&gt; workflow&lt;/h2&gt;

&lt;p&gt;The input to this workflow is the plan.
The plan consists of a set of tasks.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implement plan&lt;/code&gt; workflow turns each task into a Git commit on either trunk or a pull request branch.
The following diagram shows the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implement plan&lt;/code&gt; workflow:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/i/genai/idea-to-code/idea-to-code-workflow-implementation.png&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The workflow begins with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code&lt;/code&gt; cleaning up from a previously failed implementation by committing any uncommitted changes and pushing them to the remote repository.&lt;/p&gt;

&lt;p&gt;Once it has cleaned up, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code&lt;/code&gt; iteratively implements each task in the plan.
The plan implementation loop consists of the following steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;If there’s a running CI build, wait for it to complete.&lt;/li&gt;
  &lt;li&gt;If the CI build failed, fix it.&lt;/li&gt;
  &lt;li&gt;Respond to any comments on the pull request.&lt;/li&gt;
  &lt;li&gt;Get the next task from the plan.&lt;/li&gt;
  &lt;li&gt;If there are no more tasks, break the loop.&lt;/li&gt;
  &lt;li&gt;Implement the task.&lt;/li&gt;
  &lt;li&gt;Mark the task as complete in the plan.&lt;/li&gt;
  &lt;li&gt;Commit the changes to Git.&lt;/li&gt;
  &lt;li&gt;Push the commit to the remote repository.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;why-not-implement-the-implement-plan-workflow-using-a-coding-agent&quot;&gt;Why not implement the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implement plan&lt;/code&gt; workflow using a coding agent?&lt;/h2&gt;

&lt;p&gt;In theory, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code&lt;/code&gt; could simply implement the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implement plan&lt;/code&gt; workflow by invoking a coding agent (e.g. Claude Code) with a suitable prompt that tells it to implement the entire plan:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;claude -p &quot;Implement the following plan: ${plan_file} using the following workflow:

commitChanges()
pushCommits()
while True
    1. If there&apos;s a running CI build, wait for it to complete.
    2. If the CI build failed, fix it.
    3. Respond to any comments on the pull request.
    4. Get the next task from the plan.
    5. If there are no more tasks, break the loop.
    6. Implement the task.
    7. Mark the task as complete in the plan.
    8. Commit the changes to Git.
    9. Push the commit to the remote repository.
&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, in practice, this approach is often unreliable and it’s certainly inefficient.
The non-deterministic nature of LLMs means that it’s unlikely that the agent will successfully implement the entire plan in one go.
For example, I’ve found that it will simply stop partway through.
Also, LLMs are computationally expensive, so it’s wasteful to use an LLM when there is a far more efficient way to implement a function: plain old code (POC) - the top slice of the sandwich.&lt;/p&gt;

&lt;h2 id=&quot;the-top-slice-orchestrating-the-implement-plan-workflow-using-plain-old-code&quot;&gt;The top slice: orchestrating the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implement plan&lt;/code&gt; workflow using plain old code&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code&lt;/code&gt; implements the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implement plan&lt;/code&gt; workflow using plain old code.
The actual Python code is not that different from the pseudo-code in the workflow diagram above:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_loop_steps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commit_recovery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commit_if_needed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_git_repo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has_unpushed_commits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_push_and_ensure_pr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_loop_steps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;build_fixer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;check_and_fix_ci&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/i/genai/idea-to-code/idea-to-code-coding-agent-sandwich-01.png&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This code is deterministic, efficient and easy to develop and debug.
There’s no need to &lt;a href=&quot;/post/architecture/2026/03/01/using-genai-based-coding-agents-cynefin-complex-domain.html&quot;&gt;experiment&lt;/a&gt; with different prompts and hope that the agent will do the right thing only to find that it doesn’t.
Don’t &lt;a href=&quot;/post/architecture/2026/01/28/when-two-problems-becomes-four-genai-based-development.html&quot;&gt;waste your time trying to solve a problem with an LLM&lt;/a&gt; when there are far simpler solutions.&lt;/p&gt;

&lt;p&gt;Let’s now look at the sandwich’s filling: the coding agent.&lt;/p&gt;

&lt;h2 id=&quot;the-filling-invoking-the-coding-agent-for-narrowly-defined-actions&quot;&gt;The filling: invoking the coding agent for narrowly defined actions&lt;/h2&gt;

&lt;p&gt;Of course, there are some steps in the workflow that are not easily implemented using POC.
For those, the POC-based orchestrator invokes the coding agent for narrowly defined tasks that cannot be implemented deterministically.
Specifically, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; workflow invokes the coding agent for the following tasks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Committing changes - completing the &lt;a href=&quot;/post/architecture/2026/03/09/genai-development-platform-part-1-development-guardrails.html&quot;&gt;pre-commit checklist&lt;/a&gt;, generating a commit message and &lt;a href=&quot;/post/genaidevelopment/2025/09/10/allow-git-commit-considered-harmful.html&quot;&gt;committing the changes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Fixing a broken CI build - analyzing the CI failure, identifying the cause and creating a commit that fixes it&lt;/li&gt;
  &lt;li&gt;Responding to pull request comments - analyzing comments, grouping related comments, and generating commits&lt;/li&gt;
  &lt;li&gt;Implementing a task - analyzing the task, identifying the necessary code changes, making the changes that implement the task, marking the task as complete and creating a commit for the changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/i/genai/idea-to-code/idea-to-code-coding-agent-sandwich-02.png&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This approach allows us to leverage the strengths of both POC and the coding agent.
However, there’s still one more layer of the sandwich: the deterministic tools that the coding agent can use to implement the tasks.&lt;/p&gt;

&lt;h2 id=&quot;the-bottom-slice-deterministic-tools-used-by-the-coding-agent&quot;&gt;The bottom slice: deterministic tools used by the coding agent&lt;/h2&gt;

&lt;p&gt;To complete these tasks, the coding agent must be grounded in reality and perform various deterministic actions, such as running tests, verifying code quality, committing and pushing changes, and monitoring CI builds.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/i/genai/idea-to-code/idea-to-code-coding-agent-sandwich-03.png&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For example, during the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;implement plan&lt;/code&gt; workflow, the coding agent invokes various tools including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uv&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gradlew&lt;/code&gt; commands for running tests&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; commands&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gh&lt;/code&gt; commands for diagnosing a failed build&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code plan&lt;/code&gt; commands for marking a task in a plan file as complete, etc.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CodeScene MCP server&lt;/code&gt; for analyzing code quality and identifying problems&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gitleaks&lt;/code&gt; for checking for secrets in the code before committing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Claude Code has either built-in knowledge of these tools or is instructed to use them via skills or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; instructions.&lt;/p&gt;

&lt;p&gt;We’ve now seen all three slices. 
Let’s step back and look at what kind of pattern this is.&lt;/p&gt;

&lt;h2 id=&quot;functional-decomposition-layered-and-fractal&quot;&gt;Functional decomposition, layered and fractal&lt;/h2&gt;

&lt;p&gt;This approach of using a mixture of POC and LLMs is an example of functional decomposition - a general software design principle where a system is divided into components based on responsibility, and each function is implemented using the most appropriate technology.&lt;/p&gt;

&lt;p&gt;In this case:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;deterministic, well-defined logic is implemented using POC&lt;/li&gt;
  &lt;li&gt;ambiguous, language-oriented, or probabilistic tasks are implemented using LLMs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rather than treating the LLM as the entire application, the system decomposes responsibilities and uses the LLM only where its capabilities provide value.&lt;/p&gt;

&lt;p&gt;Functional decomposition can be applied recursively.
The tools that form the bottom slice are all deterministic, but in principle a tool could itself incorporate LLM-based technology - in which case the tool is its own sandwich of POC orchestrating LLM calls.
The architecture is fractal as well as layered.&lt;/p&gt;

&lt;h2 id=&quot;use-poc-whenever-you-can-llms-only-when-you-must&quot;&gt;Use POC whenever you can, LLMs only when you must&lt;/h2&gt;

&lt;p&gt;The practical rule: reach for POC first, fall back to an LLM only where determinism breaks down, and give the LLM deterministic tools so that it’s grounded in reality.&lt;/p&gt;

&lt;h2 id=&quot;need-help-with-modernizing-your-architecture&quot;&gt;Need help with modernizing your architecture?&lt;/h2&gt;

&lt;p&gt;I help organizations modernize safely and avoid creating a modern legacy system — a new architecture with the same old problems. If you’re planning or struggling with a modernization effort, I can help.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrisrichardson.net&quot;&gt;Learn more about my modernization and architecture advisory work →&lt;/a&gt;&lt;/p&gt;

</description>
            <pubDate>Tue, 19 May 2026 08:03:00 +0000</pubDate>
            <link>http://microservices.io//post/architecture/2026/05/19/genai-development-platform-part-4-coding-agent-sandwich-pattern.html</link>
            <guid isPermaLink="true">http://microservices.io//post/architecture/2026/05/19/genai-development-platform-part-4-coding-agent-sandwich-pattern.html</guid>
        </item>
        
        <item>
            <title>Microservices Platforms - part 7: Deployment platform</title>
            <description>&lt;p&gt;This is the seventh article in a series based on my &lt;a href=&quot;/post/architecture/2025/11/23/qconsf-2025-microservices-platforms.html&quot;&gt;QCon San Francisco 2025 talk &lt;em&gt;Microservices Platforms: When Team Topologies Meets Microservices Patterns&lt;/em&gt;&lt;/a&gt;.
The articles in the series are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-when-team-topologies-meets-microservices-patterns-part-1/&quot;&gt;Microservices Platforms - part 1: Overview&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-2-service-foundation-platform/&quot;&gt;Microservices Platforms - part 2: Service foundation platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-3-security-platform/&quot;&gt;Microservices Platforms - part 3: Security platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-4-infrastructure-services-platform/&quot;&gt;Microservices Platforms - part 4: Infrastructure services platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-5-observability-platform/&quot;&gt;Microservices Platforms - part 5: Observability platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-6-build-platform/&quot;&gt;Microservices Platforms - part 6: Build platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-7-deployment-platform/&quot;&gt;Microservices Platforms - part 7: Deployment platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-8-getting-started-with-platforms/&quot;&gt;Microservices Platforms - part 8: Getting started with platforms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article describes the &lt;strong&gt;Deployment platform&lt;/strong&gt;, which provides production and production-like environments that run the application’s services.
Together with the Build platform, it defines the path that changes take from laptop to production.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/i/qconsf-microservices-platforms-part-7/Microservices_Platforms_Deployment.png&quot; alt=&quot;Deployment platform&quot; style=&quot;float: left; width: 100%; margin-right: 1.5em; margin-bottom: 1em;&quot; /&gt;&lt;/p&gt;

&lt;p style=&quot;font-size: 1.25em; font-weight: bold;&quot;&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-7-deployment-platform/&quot;&gt;Read more (This post is for paying subscribers only)&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;need-help-with-modernizing-your-architecture&quot;&gt;Need help with modernizing your architecture?&lt;/h2&gt;

&lt;p&gt;I help organizations modernize safely and avoid creating a modern legacy system — a new architecture with the same old problems. If you’re planning or struggling with a modernization effort, I can help.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrisrichardson.net&quot;&gt;Learn more about my modernization and architecture advisory work →&lt;/a&gt;&lt;/p&gt;

</description>
            <pubDate>Thu, 23 Apr 2026 08:03:00 +0000</pubDate>
            <link>http://microservices.io//post/architecture/2026/04/23/qconsf-microservices-platforms-part-7.html</link>
            <guid isPermaLink="true">http://microservices.io//post/architecture/2026/04/23/qconsf-microservices-platforms-part-7.html</guid>
        </item>
        
        <item>
            <title>GenAI-based development platform - part 3: Announcing Isolarium, three flavors of secure sandboxes for GenAI-based coding agents</title>
            <description>&lt;p&gt;I’m pleased to announce that I’ve open-sourced &lt;a href=&quot;https://github.com/humansintheloop-dev/isolarium&quot;&gt;Isolarium&lt;/a&gt;, a companion project to &lt;a href=&quot;https://github.com/humansintheloop-dev/humansintheloop-dev-workflow-and-tools&quot;&gt;Idea to Code workflow&lt;/a&gt; that provides secure sandboxes for running GenAI-based coding agents like Claude Code.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/humansintheloop-dev/isolarium/raw/main/isolarium_logo.png&quot; alt=&quot;Isolarium logo consisting of an agent in a cicle representing the sandbox&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This article is part of a series about the GenAI-based development platform (a.k.a. harness) that I’ve been developing to make GenAI-based coding agents like Claude Code more productive, more secure and less frustrating.
The complete list of articles in the series is as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/01/29/about-idea-to-code.html&quot;&gt;Part 0 - My GenAI development workflow: Idea to Code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/09/genai-development-platform-part-1-development-guardrails.html&quot;&gt;Part 1 - Guardrails for GenAI coding agents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/17/overview-i2code-implement-agent-orchestrator.html&quot;&gt;Part 2 - How Idea to Code turns an idea into working, tested software&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/26/genai-development-platform-part-3-announcing-isolarium.html&quot;&gt;Part 3 - Announcing Isolarium, three flavors of secure sandboxes for GenAI-based coding agents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/05/19/genai-development-platform-part-4-coding-agent-sandwich-pattern.html&quot;&gt;Part 4 - The coding agent sandwich pattern&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, I first describe the risks of running coding agents on a developer workstation and why secure sandboxes are necessary.
I then briefly describe Isolarium and the three flavors of sandboxes that it offers.
Let’s start by looking at the motivation for Isolarium.&lt;/p&gt;

&lt;h2 id=&quot;why-coding-agents-need-secure-sandboxes&quot;&gt;Why coding agents need secure sandboxes&lt;/h2&gt;

&lt;p&gt;There are three reasons why coding agents need secure sandboxes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Coding agents are vulnerable to attacks that can compromise the developer’s machine&lt;/li&gt;
  &lt;li&gt;Container-based testing libraries such as Testcontainers introduce additional risks&lt;/li&gt;
  &lt;li&gt;Even well-intentioned coding agents can cause damage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s look at each one.&lt;/p&gt;

&lt;h3 id=&quot;coding-agent-security-risks&quot;&gt;Coding agent security risks&lt;/h3&gt;

&lt;p&gt;Coding agent security risks have been on my mind ever since I watched the excellent and deeply disturbing presentation &lt;a href=&quot;https://media.ccc.de/v/39c3-agentic-probllms-exploiting-ai-computer-use-and-coding-agents&quot;&gt;&lt;em&gt;Agentic ProbLLMs: Exploiting AI Computer-Use and Coding Agents&lt;/em&gt;&lt;/a&gt; by AI researcher &lt;a href=&quot;https://embracethered.com/blog/&quot;&gt;Johann Rehberger&lt;/a&gt;.
His &lt;em&gt;The Month of AI Bugs&lt;/em&gt; series - one post per day for the month of August 2025 - shows the risks that we face when we run coding agents.&lt;/p&gt;

&lt;p&gt;Coding agent security risks include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Exfiltration of developer credentials (SSH keys, GitHub tokens, cloud credentials)&lt;/li&gt;
  &lt;li&gt;Leakage of sensitive local files from the developer workstation&lt;/li&gt;
  &lt;li&gt;Unauthorized access to other repositories or organization resources&lt;/li&gt;
  &lt;li&gt;Execution of malicious commands on the developer’s machine&lt;/li&gt;
  &lt;li&gt;Malicious or unsafe dependency installation affecting the host environment&lt;/li&gt;
  &lt;li&gt;Persistence of compromise on the developer machine after an agent session ends&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;container-based-testing-libraries-introduce-additional-risks&quot;&gt;Container-based testing libraries introduce additional risks&lt;/h3&gt;

&lt;p&gt;Testing technologies such as the incredibly useful &lt;a href=&quot;https://testcontainers.com/&quot;&gt;Testcontainers library&lt;/a&gt; that allow tests to run arbitrary Docker containers introduce additional risks since they can be used to run malicious containers that attack the host machine.&lt;/p&gt;

&lt;h3 id=&quot;even-well-intentioned-coding-agents-can-cause-damage&quot;&gt;Even well-intentioned coding agents can cause damage&lt;/h3&gt;

&lt;p&gt;There’s also the risk of a well-intentioned coding agent causing damage by making unintended changes to the developer’s machine or code repository.
Coding agents, for example, attempt to run arbitrary Bash commands, or write code that runs Bash commands.&lt;/p&gt;

&lt;h2 id=&quot;secure-sandboxes-for-genai-based-coding-agents&quot;&gt;Secure sandboxes for GenAI-based coding agents&lt;/h2&gt;

&lt;p&gt;Isolarium is a command line tool intended to address these problems.
It runs coding agents in a secure, isolated and disposable environment.
For example, to run Claude Code:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;my-project
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;isolarium run &lt;span class=&quot;nt&quot;&gt;--create&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; claude &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This command creates an isolated environment for the coding agent to run in, and then runs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;claude&lt;/code&gt; inside that environment.&lt;/p&gt;

&lt;h2 id=&quot;three-flavors-of-isolation&quot;&gt;Three flavors of isolation&lt;/h2&gt;

&lt;p&gt;Isolarium offers three flavors of isolation that make different trade-offs between security and overhead:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://nono.sh/&quot;&gt;Nono&lt;/a&gt; - the most lightweight yet least secure option since the agent has access to some of the host’s filesystem.&lt;/li&gt;
  &lt;li&gt;Container - more overhead due to image and container creation yet more secure since only the working tree is shared with the host.&lt;/li&gt;
  &lt;li&gt;Virtual machine - slow to provision but provides the strongest isolation since the agent has no access to the host’s filesystem. 
What’s more the coding agent has more freedom: e.g., run tests that use Testcontainers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;isolarium-works-with-i2code-implement&quot;&gt;Isolarium works with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;/post/architecture/2026/03/17/overview-i2code-implement-agent-orchestrator.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; command&lt;/a&gt; described in the previous article implements the final step of the &lt;a href=&quot;/post/architecture/2026/01/29/about-idea-to-code.html&quot;&gt;Idea to Code workflow&lt;/a&gt;, which turns a plan derived from an idea into a pull request consisting of production code and tests.
It can now use Isolarium to run the coding agent in a secure, isolated environment:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;isolarium implement &lt;span class=&quot;nt&quot;&gt;--isolation-type&lt;/span&gt; &amp;lt;&lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This command runs the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; command inside an Isolarium environment with the specified isolation type.&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;

&lt;p&gt;To learn more about Isolarium and to get started, check out the &lt;a href=&quot;https://github.com/humansintheloop-dev/isolarium&quot;&gt;GitHub repository&lt;/a&gt;.
I welcome your questions, feedback, and contributions.&lt;/p&gt;

&lt;h2 id=&quot;need-help-with-modernizing-your-architecture&quot;&gt;Need help with modernizing your architecture?&lt;/h2&gt;

&lt;p&gt;I help organizations modernize safely and avoid creating a modern legacy system — a new architecture with the same old problems. If you’re planning or struggling with a modernization effort, I can help.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrisrichardson.net&quot;&gt;Learn more about my modernization and architecture advisory work →&lt;/a&gt;&lt;/p&gt;

</description>
            <pubDate>Thu, 26 Mar 2026 08:03:00 +0000</pubDate>
            <link>http://microservices.io//post/architecture/2026/03/26/genai-development-platform-part-3-announcing-isolarium.html</link>
            <guid isPermaLink="true">http://microservices.io//post/architecture/2026/03/26/genai-development-platform-part-3-announcing-isolarium.html</guid>
        </item>
        
        <item>
            <title>Microservices Platforms - part 6: Build platform</title>
            <description>&lt;p&gt;This is the sixth article in a series based on my &lt;a href=&quot;/post/architecture/2025/11/23/qconsf-2025-microservices-platforms.html&quot;&gt;QCon San Francisco 2025 talk &lt;em&gt;Microservices Platforms: When Team Topologies Meets Microservices Patterns&lt;/em&gt;&lt;/a&gt;.
The articles in the series are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-when-team-topologies-meets-microservices-patterns-part-1/&quot;&gt;Microservices Platforms - part 1: Overview&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-2-service-foundation-platform/&quot;&gt;Microservices Platforms - part 2: Service foundation platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-3-security-platform/&quot;&gt;Microservices Platforms - part 3: Security platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-4-infrastructure-services-platform/&quot;&gt;Microservices Platforms - part 4: Infrastructure services platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-5-observability-platform/&quot;&gt;Microservices Platforms - part 5: Observability platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-6-build-platform/&quot;&gt;Microservices Platforms - part 6: Build platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-7-deployment-platform/&quot;&gt;Microservices Platforms - part 7: Deployment platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-8-getting-started-with-platforms/&quot;&gt;Microservices Platforms - part 8: Getting started with platforms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article describes the &lt;strong&gt;Build platform&lt;/strong&gt;, which provides the infrastructure and templates for the deployment pipelines that build and test the application’s services.
Together with the &lt;strong&gt;Deployment platform&lt;/strong&gt;, it defines the path that changes take from laptop to production.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/i/qconsf-microservices-platforms-part-6/Microservices_Platforms_Build.png&quot; alt=&quot;Build platform&quot; style=&quot;float: left; width: 100%; margin-right: 1.5em; margin-bottom: 1em;&quot; /&gt;&lt;/p&gt;

&lt;p style=&quot;font-size: 1.25em; font-weight: bold;&quot;&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-6-build-platform/&quot;&gt;Read more (This post is for paying subscribers only)&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;need-help-with-modernizing-your-architecture&quot;&gt;Need help with modernizing your architecture?&lt;/h2&gt;

&lt;p&gt;I help organizations modernize safely and avoid creating a modern legacy system — a new architecture with the same old problems. If you’re planning or struggling with a modernization effort, I can help.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrisrichardson.net&quot;&gt;Learn more about my modernization and architecture advisory work →&lt;/a&gt;&lt;/p&gt;

</description>
            <pubDate>Fri, 20 Mar 2026 08:03:00 +0000</pubDate>
            <link>http://microservices.io//post/architecture/2026/03/20/qconsf-microservices-platforms-part-6.html</link>
            <guid isPermaLink="true">http://microservices.io//post/architecture/2026/03/20/qconsf-microservices-platforms-part-6.html</guid>
        </item>
        
        <item>
            <title>GenAI-based development platform - part 2: How Idea to Code turns an idea into working, tested software</title>
            <description>&lt;p&gt;This article is the third in a series about the GenAI-based development platform (aka. harness) that I’ve been developing to make GenAI-based coding agents like Claude Code more productive and less frustrating.
The platform is a set of tools, constraints and feedback loops that guide their behavior, catch mistakes and prevent them from generating large amounts of poor-quality code that is often incomplete and untested.&lt;/p&gt;

&lt;p&gt;The complete list of articles in the series is as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/01/29/about-idea-to-code.html&quot;&gt;Part 0 - My GenAI development workflow: Idea to Code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/09/genai-development-platform-part-1-development-guardrails.html&quot;&gt;Part 1 - Guardrails for GenAI coding agents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/17/overview-i2code-implement-agent-orchestrator.html&quot;&gt;Part 2 - How Idea to Code turns an idea into working, tested software&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/26/genai-development-platform-part-3-announcing-isolarium.html&quot;&gt;Part 3 - Announcing Isolarium, three flavors of secure sandboxes for GenAI-based coding agents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/05/19/genai-development-platform-part-4-coding-agent-sandwich-pattern.html&quot;&gt;Part 4 - The coding agent sandwich pattern&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article is about the last step in the &lt;a href=&quot;/post/architecture/2026/01/29/about-idea-to-code.html&quot;&gt;&lt;em&gt;Idea to Code&lt;/em&gt; workflow &lt;/a&gt; that turns a plan derived from the initial idea into a pull request consisting of production code and tests.
The actual development is performed by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; subcommand.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ i2code implement docs/ideas/amazing-idea
...
PR marked ready for review
PR: https://github.com/humansintheloop-dev/humansintheloop-dev-workflow-and-tools/pull/31
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docs/ideas/amazing-idea&lt;/code&gt; is a directory that contains the idea along with a specification and implementation plan that were derived from the idea.&lt;/p&gt;

&lt;p&gt;Let’s explore the implementation of this coding agent orchestrator.&lt;/p&gt;

&lt;h2 id=&quot;how-i2code-implement-orchestrates-claude-code-to-implement-a-plan&quot;&gt;How &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; orchestrates Claude Code to implement a plan&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; command combines deterministic Python code and Claude Code invocations.&lt;/p&gt;

&lt;p&gt;The following diagram shows how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; works:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/i/posts/genai/worktree-mode-overview.png&quot; style=&quot;width: 100%&quot; alt=&quot;Diagram of the Idea to Code workflow in worktree mode&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The input to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; is a plan derived from the idea and consists of a series of small tasks.
The output is a GitHub pull request consisting of roughly one commit per task.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; command uses TDD, so each commit contains both production code and tests.&lt;/p&gt;

&lt;p&gt;Let’s look at how this works in more detail.&lt;/p&gt;

&lt;h2 id=&quot;setup-phase&quot;&gt;Setup phase&lt;/h2&gt;

&lt;p&gt;The first phase is a one-time setup that, among other things, creates a Git working tree for the branch that will be used to implement the plan.
Subsequent runs of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; for the same plan will reuse the same working tree, so the setup phase is only needed once per branch.
This step is entirely deterministic, implemented in Python.&lt;/p&gt;

&lt;h2 id=&quot;recovery-phase&quot;&gt;Recovery phase&lt;/h2&gt;

&lt;p&gt;The second phase is the recovery phase, which attempts to recover incomplete work from previous runs of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; for the same plan.
If there are uncommitted changes that complete a task, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; invokes Claude Code to generate a commit message and commit the changes.
Next, if there are commits in the local repository that haven’t been pushed to the remote, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; pushes them.
It then enters the main implementation loop.&lt;/p&gt;

&lt;h2 id=&quot;main-implementation-loop&quot;&gt;Main implementation loop&lt;/h2&gt;

&lt;p&gt;The implement loop iteratively executes the tasks in the plan until all tasks are completed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/i/posts/genai/task-implementation-loop.png&quot; class=&quot;img-responsive&quot; alt=&quot;Diagram of the task implementation loop&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The loop consists of the following steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Fix any failed GitHub actions workflow for the current HEAD&lt;/strong&gt;, waiting for the build to complete if necessary.
If the build is broken, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; invokes Claude Code to diagnose the failure, and commit a fix.
It then pushes the fix and waits for the build to complete again.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Respond to comments and reviews of the pull request.&lt;/strong&gt;
If there are any comments or reviews requesting changes, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; first invokes Claude Code to triage the feedback and determine what changes, if any, are needed to address it.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; command invokes Claude Code one or more times to generate commits that address the feedback and pushes the changes.
It also responds to the comments and review with an explanation of the changes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Implement the next task in the plan.&lt;/strong&gt;
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; then takes the next task in the plan, and invokes Claude Code to implement it using TDD, creating a commit.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Push the commit and, if necessary, create a pull request.&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Wait for the build to complete and repeat.&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Mark the pull request as ready for review.&lt;/strong&gt;
Once all the tasks in the plan have been implemented, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; marks the pull request as ready for review.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Wait for the comments or reviews.&lt;/strong&gt;
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; command can wait for comments or reviews on the pull request, and respond to them as described in step 2.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;trunk-mode&quot;&gt;Trunk mode&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; command also supports a trunk-based development mode, where instead of creating a pull request, it commits directly to the current branch.&lt;/p&gt;

&lt;h2 id=&quot;to-learn-more&quot;&gt;To learn more&lt;/h2&gt;

&lt;p&gt;Take a look at the &lt;a href=&quot;https://github.com/humansintheloop-dev/humansintheloop-dev-workflow-and-tools/blob/master/docs/design/implement-steps.md&quot;&gt;design document for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt;&lt;/a&gt; in the &lt;a href=&quot;https://github.com/humansintheloop-dev/humansintheloop-dev-workflow-and-tools&quot;&gt;Humans in the Loop Dev repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;

&lt;p&gt;In the next post, I’ll describe how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i2code implement&lt;/code&gt; can execute Claude Code within a sandbox environment, which minimizes the security risks of using coding agents.&lt;/p&gt;

&lt;h2 id=&quot;need-help-with-modernizing-your-architecture&quot;&gt;Need help with modernizing your architecture?&lt;/h2&gt;

&lt;p&gt;I help organizations modernize safely and avoid creating a modern legacy system — a new architecture with the same old problems. If you’re planning or struggling with a modernization effort, I can help.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrisrichardson.net&quot;&gt;Learn more about my modernization and architecture advisory work →&lt;/a&gt;&lt;/p&gt;

</description>
            <pubDate>Tue, 17 Mar 2026 08:03:00 +0000</pubDate>
            <link>http://microservices.io//post/architecture/2026/03/17/overview-i2code-implement-agent-orchestrator.html</link>
            <guid isPermaLink="true">http://microservices.io//post/architecture/2026/03/17/overview-i2code-implement-agent-orchestrator.html</guid>
        </item>
        
        <item>
            <title>GenAI-based development platform - part 1: guardrails</title>
            <description>&lt;p&gt;This article is the second in a series about the GenAI-based development platform (aka. harness) that I’ve been developing to make GenAI-based coding agents like Claude Code more productive and less frustrating.
The platform is a set of tools, constraints and feedback loops that guide their behavior, catch mistakes and prevent them from generating large amounts of poor-quality code that is often incomplete and untested.&lt;/p&gt;

&lt;p&gt;The complete list of articles in the series is as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/01/29/about-idea-to-code.html&quot;&gt;Part 0 - My GenAI development workflow: Idea to Code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/09/genai-development-platform-part-1-development-guardrails.html&quot;&gt;Part 1 - Guardrails for GenAI coding agents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/17/overview-i2code-implement-agent-orchestrator.html&quot;&gt;Part 2 - How Idea to Code turns an idea into working, tested software&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/03/26/genai-development-platform-part-3-announcing-isolarium.html&quot;&gt;Part 3 - Announcing Isolarium, three flavors of secure sandboxes for GenAI-based coding agents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/post/architecture/2026/05/19/genai-development-platform-part-4-coding-agent-sandwich-pattern.html&quot;&gt;Part 4 - The coding agent sandwich pattern&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because coding agents cannot be relied on to consistently follow instructions, they must operate within deterministic guardrails that catch mistakes and enforce quality. 
Guardrails are therefore a central part of the platform.
This article describes some of these guardrails.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/i/posts/genai/genai-guardrails.png&quot; alt=&quot;GenAI-based development platform guardrails&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Specifically, there are four guardrails that I want to cover:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Pre-commit checklist skill&lt;/li&gt;
  &lt;li&gt;Pre-commit Git hook&lt;/li&gt;
  &lt;li&gt;GitHub Actions workflow jobs&lt;/li&gt;
  &lt;li&gt;Automated pull request reviews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first guardrail relies on the coding agent following instructions, while the others are deterministic mechanisms that enforce quality regardless of the agent’s behavior.
Together, they provide defense in depth: if one guardrail is bypassed or ignored, the others still catch problems.&lt;/p&gt;

&lt;p&gt;Let’s dive into each guardrail in turn, starting with the pre-commit checklist.&lt;/p&gt;

&lt;h2 id=&quot;pre-commit-checklist-skill&quot;&gt;Pre-commit checklist skill&lt;/h2&gt;

&lt;p&gt;The first guardrail is the pre-commit checklist provided by the &lt;a href=&quot;https://github.com/humansintheloop-dev/humansintheloop-dev-workflow-and-tools/blob/master/skills/commit-guidelines/SKILL.md#pre-commit-checklist&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit-guidelines&lt;/code&gt; skill&lt;/a&gt; that is part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;idea-to-code&lt;/code&gt; plugin in the &lt;a href=&quot;https://github.com/humansintheloop-dev/humansintheloop-dev-workflow-and-tools/&quot;&gt;Humans in the Loop workflow and tools repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This pre-commit checklist instructs the coding agent to run several quality and safety checks before creating a Git commit, including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Dead code detection (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vulture&lt;/code&gt; for Python)&lt;/li&gt;
  &lt;li&gt;Linting with auto-fix (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ruff&lt;/code&gt;) to enforce coding standards&lt;/li&gt;
  &lt;li&gt;Static type checking for Python (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyright&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;Shell script linting for new or modified &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.sh&lt;/code&gt; files (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shellcheck&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;Code health analysis using CodeScene, requiring a score of 10 for all modified files&lt;/li&gt;
  &lt;li&gt;Test coverage verification to ensure tests cover new or changed production code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any quality gates fail, the agent must stop and fix the issues before committing.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://codescene.io/&quot;&gt;CodeScene&lt;/a&gt; provides incredibly valuable feedback that has significantly improved the quality of the code generated by Claude Code. 
For example, requiring a CodeScene score of 10 for all modified files - in other words, the boy scout rule - has significantly improved the maintainability of the &lt;a href=&quot;https://codescene.io/projects/76822/jobs/5831141/results?scope=month&amp;amp;aspect=#code-health&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Idea To Code&lt;/code&gt; code base&lt;/a&gt;.
One challenge, however, is that Claude Code often tries to justify not addressing code smells identified by CodeScene, such as claiming they are “pre-existing” or otherwise “acceptable”.
This is one of the motivations for implementing the next guardrail.&lt;/p&gt;

&lt;h2 id=&quot;pre-commit-git-hook&quot;&gt;Pre-commit Git hook&lt;/h2&gt;

&lt;p&gt;The second guardrail is a &lt;a href=&quot;https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks&quot;&gt;pre-commit Git hook&lt;/a&gt; that automatically runs quality and security checks before allowing commits to be made.
It’s implemented using the &lt;a href=&quot;https://pre-commit.com/&quot;&gt;pre-commit framework&lt;/a&gt;, which is configured by a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pre-commit-config.yaml&lt;/code&gt; file.
See, for example, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pre-commit-config.yaml&lt;/code&gt; files for the &lt;a href=&quot;https://github.com/humansintheloop-dev/humansintheloop-dev-workflow-and-tools/blob/master/.pre-commit-config.yaml&quot;&gt;Idea to Code&lt;/a&gt;, and &lt;a href=&quot;https://github.com/eventuate-examples/eventuate-examples-realguardio/blob/development/.pre-commit-config.yaml&quot;&gt;Eventuate RealGuardIO&lt;/a&gt; repositories.&lt;/p&gt;

&lt;p&gt;In addition to running the tests, the pre-commit hook largely repeats the pre-commit checklist.
The pre-commit hook does not run the dead code detection tool since its output needs to be interpreted and acted upon by the coding agent, which is not something a pre-commit hook can do.
The hook also runs &lt;a href=&quot;https://github.com/gitleaks/gitleaks&quot;&gt;gitleaks&lt;/a&gt; to prevent secrets from being committed.&lt;/p&gt;

&lt;p&gt;The pre-commit hook is essential because, unlike a Claude Code skill, it is deterministic.
Its checks don’t rely on the GenAI-based coding agent following the checklist, which is often not the case.
Fortunately, Claude Code hasn’t tried to &lt;a href=&quot;/post/genaidevelopment/2025/09/10/allow-git-commit-considered-harmful.html&quot;&gt;bypass this pre-commit hook like I described previously&lt;/a&gt;.
And even if it did, there are two more guardrails.&lt;/p&gt;

&lt;h2 id=&quot;github-actions-workflow&quot;&gt;GitHub Actions workflow&lt;/h2&gt;

&lt;p&gt;The third guardrail is the set of checks performed by the GitHub Actions workflow that runs on every push or merge.
A GitHub Actions workflow runs the tests.
It also has one or more &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lint&lt;/code&gt; jobs.&lt;/p&gt;

&lt;p&gt;For example, the Eventuate RealGuardIO repository’s workflow has a &lt;a href=&quot;https://github.com/eventuate-examples/eventuate-examples-realguardio/blob/development/.github/workflows/test.yml#L18&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lint&lt;/code&gt; job&lt;/a&gt; that performs various quality and security checks on the codebase, including shell script linting and secret scanning using gitleaks.
So does the &lt;a href=&quot;https://github.com/humansintheloop-dev/humansintheloop-dev-workflow-and-tools/blob/master/.github/workflows/ci.yml&quot;&gt;Idea To Code repository’s GitHub Action’s workflow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These checks will be performed even if the GenAI-based coding agent bypasses the pre-commit hook.
In a later post, I will describe how to block a GenAI-based coding agent from modifying the GitHub Actions workflow files, which provides an additional layer of protection.&lt;/p&gt;

&lt;h2 id=&quot;automated-github-status-checks-codescene-pull-request-review&quot;&gt;Automated GitHub status checks: CodeScene pull request review&lt;/h2&gt;

&lt;p&gt;The fourth and final guardrail is a set of automated checks that are performed when a pull request is created or a new commit is added.
The failure of one of these GitHub status checks can prevent the pull request from being merged until the issues are addressed.&lt;/p&gt;

&lt;p&gt;For example, I’ve configured CodeScene to automatically review all pull requests for the Eventuate RealGuardIO and Idea to Code repositories and provide feedback on code health.
The GitHub status check will fail if the CodeScene score is below 10.
It can also trigger a coding agent to respond to the CodeScene review and push a new commit that addresses the issues.
However, these days CodeScene issues are almost always detected earlier by the Git pre-commit hook, and so the pull request reviews rarely fail.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;

&lt;p&gt;In future articles, I’ll describe other elements of the GenAI-based development (aka. Harness) platform that I’m developing.&lt;/p&gt;

&lt;h2 id=&quot;need-help-with-modernizing-your-architecture&quot;&gt;Need help with modernizing your architecture?&lt;/h2&gt;

&lt;p&gt;I help organizations modernize safely and avoid creating a modern legacy system — a new architecture with the same old problems. If you’re planning or struggling with a modernization effort, I can help.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrisrichardson.net&quot;&gt;Learn more about my modernization and architecture advisory work →&lt;/a&gt;&lt;/p&gt;

</description>
            <pubDate>Mon, 09 Mar 2026 08:03:00 +0000</pubDate>
            <link>http://microservices.io//post/architecture/2026/03/09/genai-development-platform-part-1-development-guardrails.html</link>
            <guid isPermaLink="true">http://microservices.io//post/architecture/2026/03/09/genai-development-platform-part-1-development-guardrails.html</guid>
        </item>
        
        <item>
            <title>Why GenAI-based coding agents are a complex domain in Cynefin - and what that means for adoption</title>
            <description>&lt;p&gt;These days, tremendous energy is being poured into software delivery using GenAI-based coding agents.
A key part of using coding agents successfully is context engineering - carefully crafting prompts, skills, AGENT.md files, guardrails, etc. - to guide agent behavior.
This typically requires significant experimentation and iteration.
A prompt that works for one model version may fail with another.&lt;/p&gt;

&lt;p&gt;This difficulty is not accidental.
Using GenAI-based coding agents to reliably create high-quality software is fundamentally different from using traditional developer tools.
The relationship between prompt and outcome cannot be fully predicted in advance.
Effective practices evolve as teams experiment and learn.&lt;/p&gt;

&lt;p&gt;As a result, organizations cannot treat coding agents like conventional technologies that can be standardized through a single “one true way.”
Instead, they must adopt a mindset that prioritizes safe experimentation, rapid feedback, and continuous adaptation.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/i/posts/genai/genai-coding-agent-cynefin.png&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This article introduces the Cynefin framework - a model for understanding different types of problem domains - and explains why using GenAI-based coding agents belongs in the complex category and what that means for platform strategy and adoption.&lt;/p&gt;

&lt;h2 id=&quot;about-cynefin&quot;&gt;About Cynefin&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Cynefin_framework&quot;&gt;Cynefin&lt;/a&gt; is a framework that helps us understand the nature of the problem we’re facing and how we should respond to it. 
It characterizes problems as either clear, complicated, complex, or chaotic, and for each category, it prescribes a different approach to problem-solving.
Cynefin distinguishes between situations where cause and effect are obvious, where they require expert analysis, where they can only be understood in retrospect, and where no perceivable order exists.&lt;/p&gt;

&lt;p&gt;The framework is typically visualized as follows:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/a/ab/Cynefin_framework_2022.jpg&quot; class=&quot;img-responsive&quot; style=&quot;max-width: 450px&quot; /&gt;
&lt;figcaption&gt;The Cynefin framework — image from &lt;a href=&quot;https://en.wikipedia.org/wiki/Cynefin_framework&quot;&gt;Wikipedia&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Let’s look at the clear, complicated, and complex domains in more detail and then see how they relate to software development in general and GenAI-based coding agents in particular.&lt;/p&gt;

&lt;h2 id=&quot;about-clear-domains&quot;&gt;About Clear domains&lt;/h2&gt;

&lt;p&gt;In clear domains, the relationship between cause and effect is obvious.
You simply need to recognize the situation and apply the established rule or best practice.&lt;/p&gt;

&lt;p&gt;In a clear domain, effective problem-solving requires:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Sense - observe and establish facts&lt;/li&gt;
  &lt;li&gt;Categorize - match it to a known pattern&lt;/li&gt;
  &lt;li&gt;Respond - apply the established best practice&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A simple CRUD-style &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User Profile Management&lt;/code&gt; subdomain can be considered a clear domain.&lt;/p&gt;

&lt;h3 id=&quot;about-complicated-domains&quot;&gt;About complicated domains&lt;/h3&gt;

&lt;p&gt;In complicated domains, the relationship between cause and effect is knowable but not obvious.
Determining the correct response requires analysis and expertise.&lt;/p&gt;

&lt;p&gt;In a complicated domain, effective problem-solving requires:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Sense - gather data&lt;/li&gt;
  &lt;li&gt;Analyze - use expertise to determine cause&lt;/li&gt;
  &lt;li&gt;Respond - apply a good practice&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Income tax calculation&lt;/code&gt; is an example of a complicated domain: the rules are deterministic, but applying them correctly requires careful analysis and expert knowledge, due to the large number of interdependent rules, exceptions, and conditional thresholds.&lt;/p&gt;

&lt;h3 id=&quot;about-cynefin-complex-domains&quot;&gt;About Cynefin complex domains&lt;/h3&gt;

&lt;p&gt;In a complex domain, the relationship between cause and effect can only be understood in retrospect and may not be repeated reliably.
Progress requires safe-to-fail experiments rather than upfront analysis.
There may not be a single optimal solution - only solutions that work better or worse in a given context.&lt;/p&gt;

&lt;p&gt;In a complex domain, effective problem solving requires:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Probe - run safe experiments&lt;/li&gt;
  &lt;li&gt;Sense - observe what happens&lt;/li&gt;
  &lt;li&gt;Respond - amplify what works, dampen what doesn’t&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Urban delivery routing and scheduling is an example of a complex domain. 
Traffic patterns, demand fluctuations, and human behavior create emergent outcomes that cannot be fully predicted in advance, which means effective solutions require experimentation and adaptation.&lt;/p&gt;

&lt;h2 id=&quot;why-software-development-is-complex&quot;&gt;Why software development is complex&lt;/h2&gt;

&lt;p&gt;Software development - the activity of building and evolving non-trivial software systems - is complex in Cynefin terms.
Some individual development tasks are clear or complicated - for example, applying a framework API, configuring infrastructure, or implementing a well-understood algorithm.
But architectural and design decisions must be made under uncertainty before their full consequences can be known.
Defining service boundaries, choosing abstractions, and modeling the domain are therefore complex activities in their own right, since the “right” decision cannot be determined through analysis alone.
Quite often the consequences of these decisions only become visible through testing, deployment, and real-world use rather than through upfront analysis.
As a result, effective software development requires iterative experimentation, rapid feedback, and continuous adaptation.
Except when building trivial applications, it also requires expert architectural judgment - in other words, experienced developers.&lt;/p&gt;

&lt;h2 id=&quot;developer-tools-are-clear-or-complicated&quot;&gt;Developer tools are clear or complicated&lt;/h2&gt;

&lt;p&gt;Although software development as a whole is complex, typical developer technologies - programming languages, frameworks, build tools, databases - are usually clear or complicated domains.
The relationship between cause and effect is stable and knowable.
You learn the rules, the APIs, and the configuration options, and then apply them.&lt;/p&gt;

&lt;p&gt;When problems arise, they can usually be resolved through analysis, debugging, or consulting documentation.
Even when experimentation is required, the underlying behavior is governed by defined rules and produces consistent results.
And, while systems built with these tools can exhibit complex behavior, the tools themselves operate according to stable and analyzable rules.
What’s more, when the tools themselves are changing rapidly, they might feel even chaotic, but that’s an emotional response to change rather than an inherent property of the domain.
In other words, most developer tools require expertise and analysis rather than safe-to-fail experimentation.&lt;/p&gt;

&lt;h2 id=&quot;using-an-llm-based-coding-agent-is-a-complex-domain&quot;&gt;Using an LLM-based coding agent is a complex domain&lt;/h2&gt;

&lt;p&gt;What makes LLMs so powerful is that they can tackle tasks within complex domains - including software development.
Yet this power comes with important differences.
LLM-based coding agents are fundamentally different from traditional developer tools.
Using such agents to reliably create high-quality software is a complex domain because the relationship between prompt and outcome cannot be fully predicted in advance.
A prompt that works in one context may fail in another.
Small changes in wording, context, or model version can produce disproportionately different results.&lt;/p&gt;

&lt;h3 id=&quot;cause-and-effect-can-only-be-understood-in-retrospect&quot;&gt;Cause and effect can only be understood in retrospect&lt;/h3&gt;

&lt;p&gt;The system does not expose a stable, fully understandable set of rules that can be exhaustively learned and applied.
Because outcomes depend on the interaction between prompt wording, model configuration, tool calls, retrieved context, and the surrounding codebase, behavior arises from the system as a whole rather than from a single predictable rule set.
Instead, progress requires iterative prompting, experimentation, and rapid feedback.
Effective use of a coding agent therefore resembles safe-to-fail experimentation more than traditional tool usage driven by analysis and expertise.&lt;/p&gt;

&lt;h3 id=&quot;probabilistic-nature-of-llms&quot;&gt;Probabilistic nature of LLMs&lt;/h3&gt;

&lt;p&gt;This unpredictability stems from the nature of LLMs themselves.
LLMs are probabilistic models that generate tokens by sampling from a probability distribution conditioned on the context.
Depending on the sampling strategy and model configuration, the same prompt can yield different outputs.
This probabilistic behavior helps explain why using an LLM-based coding agent is a complex domain, where cause and effect cannot be reduced to fixed, analyzable rules.&lt;/p&gt;

&lt;p&gt;Organizations must manage the complexity of the software system and the complexity of using coding agents at the same time.
Adoption therefore requires a thoughtful and deliberate approach.&lt;/p&gt;

&lt;h2 id=&quot;organizations-must-adopt-a-complex-domain-mindset-for-coding-agents&quot;&gt;Organizations must adopt a complex-domain mindset for coding agents&lt;/h2&gt;

&lt;p&gt;When an organization adopts GenAI-based coding agents, it cannot treat them like traditional developer tools.
First, it must shift engineering practices toward fast feedback and disciplined experimentation.
Second, the organization must define a GenAI-based development platform - the platform that supports the use of coding agents - as a learning amplifier, not as a vehicle for enforcing a rigid “one true way.” 
Let’s first look at the implications for engineering practices and then explore how this complexity shapes platform strategy and governance.&lt;/p&gt;

&lt;h3 id=&quot;engineering-practices-must-shift&quot;&gt;Engineering practices must shift&lt;/h3&gt;

&lt;p&gt;First, if coding agents are treated instead as a merely complicated domain - essentially as more advanced automation - organizations are likely to overtrust their outputs and underinvest in feedback loops, guardrails, and human-in-the-loop checkpoints. 
In such a complex environment, automated testing and real-time observability must explicitly replace manual policy as the primary mechanism for governance. 
This, in turn, requires a &lt;a href=&quot;/post/architecture/2026/02/08/architecting-for-genai-based-software-delivery.html&quot;&gt;fast-flow development model&lt;/a&gt; designed for experimentation and rapid feedback - without it, large-scale adoption of coding agents will stall.&lt;/p&gt;

&lt;h3 id=&quot;managing-the-unpredictability-of-outcomes&quot;&gt;Managing the unpredictability of outcomes&lt;/h3&gt;

&lt;p&gt;Second, the inherent unpredictability of GenAI-based coding agents requires a profound leadership mindset shift: moving away from the illusion of top-down control and toward a culture of continuous discovery. 
Because adoption is non-linear and success emerges through iteration rather than upfront analysis, leaders cannot rely on traditional rollout schedules or standardized mandates. 
Instead of attempting to eliminate variance, leaders must embrace an agile mindset that prioritizes enablement and evolutionary progress.&lt;/p&gt;

&lt;h3 id=&quot;the-platform-must-not-act-as-a-policy-factory&quot;&gt;The platform must not act as a policy factory&lt;/h3&gt;

&lt;p&gt;Third, this complexity also shapes platform strategy and governance.
In clear or complicated domains, a platform group that’s responsible for an internal development platform can act as a policy factory.
It defines standards, publishes the one true way, and measures success through consistency and compliance.
That approach works when cause and effect are stable and the best practices are knowable.&lt;/p&gt;

&lt;p&gt;Because developing software with GenAI-based coding agents is a complex domain, practices do not converge on a single, fixed best practice.
Prompting strategies, context engineering patterns, guardrails, and workflows evolve as teams experiment and learn.
What works today may need refinement tomorrow as models, tooling, and organizational context change.
The “one true way” is neither fully knowable nor stable.
Although certain patterns may stabilize over time, model evolution, changing tooling, and shifting organizational context ensure that practices remain sensitive to change.&lt;/p&gt;

&lt;h3 id=&quot;the-genai-based-development-platform-must-amplify-learning&quot;&gt;The GenAI-based development platform must amplify learning&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/i/posts/genai/genai-development-platform.png&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Because reliably using coding agents operates in the Cynefin complex domain, a policy factory approach freezes learning too early.
Instead, the GenAI-based development platform - the platform that supports the use of coding agents - must function as a learning amplifier.
It should enable safe-to-fail experimentation, share emerging patterns, and provide guardrails.
The goal of the platform and its team shifts from prescribing correctness to accelerating collective learning.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://domainanalysis.io/&quot;&gt;Indu Alagarsamy&lt;/a&gt; for reviewing this article and providing valuable feedback.&lt;/p&gt;

&lt;h2 id=&quot;need-help-with-modernizing-your-architecture&quot;&gt;Need help with modernizing your architecture?&lt;/h2&gt;

&lt;p&gt;I help organizations modernize safely and avoid creating a modern legacy system — a new architecture with the same old problems. If you’re planning or struggling with a modernization effort, I can help.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrisrichardson.net&quot;&gt;Learn more about my modernization and architecture advisory work →&lt;/a&gt;&lt;/p&gt;

</description>
            <pubDate>Sun, 01 Mar 2026 08:03:00 +0000</pubDate>
            <link>http://microservices.io//post/architecture/2026/03/01/using-genai-based-coding-agents-cynefin-complex-domain.html</link>
            <guid isPermaLink="true">http://microservices.io//post/architecture/2026/03/01/using-genai-based-coding-agents-cynefin-complex-domain.html</guid>
        </item>
        
        <item>
            <title>Microservices Platforms - part 5: Observability platform</title>
            <description>&lt;p&gt;This is the fifth article in a series based on my &lt;a href=&quot;/post/architecture/2025/11/23/qconsf-2025-microservices-platforms.html&quot;&gt;QCon San Francisco 2025 talk &lt;em&gt;Microservices Platforms: When Team Topologies Meets Microservices Patterns&lt;/em&gt;&lt;/a&gt;.
The articles in the series are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-when-team-topologies-meets-microservices-patterns-part-1/&quot;&gt;Microservices Platforms - part 1: Overview&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-2-service-foundation-platform/&quot;&gt;Microservices Platforms - part 2: Service foundation platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-3-security-platform/&quot;&gt;Microservices Platforms - part 3: Security platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-4-infrastructure-services-platform/&quot;&gt;Microservices Platforms - part 4: Infrastructure services platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-5-observability-platform/&quot;&gt;Microservices Platforms - part 5: Observability platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-6-build-platform/&quot;&gt;Microservices Platforms - part 6: Build platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-7-deployment-platform/&quot;&gt;Microservices Platforms - part 7: Deployment platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-8-getting-started-with-platforms/&quot;&gt;Microservices Platforms - part 8: Getting started with platforms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article describes the &lt;strong&gt;Observability platform&lt;/strong&gt;, which simplifies the development of &lt;a href=&quot;https://premium.microservices.io/microservices-rules-9-develop-observable-services/&quot;&gt;observable microservices&lt;/a&gt; - services whose behavior and usage can be understood by their teams.
It explains how a platform group provides shared observability capabilities that enable service teams to focus on their core domain responsibilities.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/i/qconsf-microservices-platforms-part-5/Microservices_Platforms_Observability.png&quot; alt=&quot;Microservices platform architecture diagram with the Observability component highlighted, showing its relationship to the Service, Service Foundation, Build, Security, Deployment, and Infrastructure Services components&quot; style=&quot;float: left; width: 100%; margin-right: 1.5em; margin-bottom: 1em;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://premium.microservices.io/microservices-platforms-part-5-observability-platform/&quot;&gt;Read more (This post is for paying subscribers only)&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;need-help-with-modernizing-your-architecture&quot;&gt;Need help with modernizing your architecture?&lt;/h2&gt;

&lt;p&gt;I help organizations modernize safely and avoid creating a modern legacy system — a new architecture with the same old problems. If you’re planning or struggling with a modernization effort, I can help.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrisrichardson.net&quot;&gt;Learn more about my modernization and architecture advisory work →&lt;/a&gt;&lt;/p&gt;

</description>
            <pubDate>Tue, 24 Feb 2026 08:03:00 +0000</pubDate>
            <link>http://microservices.io//post/architecture/2026/02/24/qconsf-microservices-platforms-part-5.html</link>
            <guid isPermaLink="true">http://microservices.io//post/architecture/2026/02/24/qconsf-microservices-platforms-part-5.html</guid>
        </item>
        
        <item>
            <title>Authentication and authorization in a microservice architecture: Part 6 - implementing complex authorization using Oso Cloud local authorization</title>
            <description>&lt;p&gt;This article is the sixth in a series of articles about authentication and authorization in a microservice architecture.
The complete series is:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://microservices.io/post/architecture/2025/04/25/microservices-authn-authz-part-1-introduction.html&quot;&gt;Overview of authentication and authorization in a microservice architecture&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://microservices.io/post/architecture/2025/05/28/microservices-authn-authz-part-2-authentication.html&quot;&gt;Implementing authentication&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://microservices.io/post/architecture/2025/07/22/microservices-authn-authz-part-3-jwt-authorization.html&quot;&gt;Implementing JWT-based authorization&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://microservices.io/post/architecture/2025/09/16/microservices-authn-authz-part-4-authorization-using-fetch-and-replicate.html&quot;&gt;Implementing authorization using fetch and replicate&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://microservices.io/post/architecture/2025/12/09/microservices-authn-authz-part-5-using-an-authorization-service.html&quot;&gt;Implementing complex authorization using Oso Cloud&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://microservices.io/post/architecture/2026/02/13/microservices-authn-authz-part-6-oso-local-authorization.html&quot;&gt;Implementing complex authorization using Oso Cloud local authorization&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the &lt;a href=&quot;https://microservices.io/post/architecture/2025/12/09/microservices-authn-authz-part-5-using-an-authorization-service.html&quot;&gt;previous article&lt;/a&gt;, I described how a microservices-based application can use an authorization service, such as Oso Cloud, to make authorization decisions.
Once the application’s authorization policy is defined declaratively in Oso, the application populates Oso with facts which correspond to relationships between entities.
Then, when handling a request, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;disarmSecuritySystem()&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Security System Service&lt;/code&gt; invokes Oso passing the user’s identity, the operation to authorize (“disarm”), and the security system ID.
Oso decides whether the operation is authorized by evaluating the authorization policy using its stored facts and the authorization request’s parameters.&lt;/p&gt;

&lt;p&gt;This approach works well for operations that act on a single entity.
Potentially complicated authorization logic is replaced by much simpler calls to Oso Cloud.
But invoking Oso repeatedly for bulk operations that act on large collections of entities is likely to be inefficient due to the communication overhead.
This article starts by exploring a more efficient way to authorize bulk query operations using a combination of local facts and facts stored in Oso Cloud.
After that, it revisits how to authorize single-entity operations using locally stored facts.
Let’s begin by looking at a simple example of a bulk query operation.&lt;/p&gt;

&lt;h2 id=&quot;problem-implementing-findsecuritysystems&quot;&gt;Problem: Implementing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;findSecuritySystems()&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;findSecuritySystems()&lt;/code&gt; system operation returns a list of the security systems that the user is authorized to access.
This data is used to populate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View Security Systems&lt;/code&gt; page of the RealGuardIO application’s UI.
Let’s first look at why such a bulk query is challenging to implement.&lt;/p&gt;

&lt;h3 id=&quot;inefficient-approach-one-by-one-authorization-using-oso&quot;&gt;Inefficient approach: One-by-one authorization using Oso&lt;/h3&gt;

&lt;p&gt;One way to implement authorization for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;findSecuritySystems()&lt;/code&gt; to do the following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Query the database for all security systems - the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Security System Service&lt;/code&gt; doesn’t maintain any other authorization-related data&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;For each security system, query Oso to check whether the user is authorized to view that security system&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach is straightforward to implement.
The problem is that unless there are just a few &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecuritySystems&lt;/code&gt;, it’s likely to be inefficient.&lt;/p&gt;

&lt;p&gt;A better approach, which was described in &lt;a href=&quot;https://microservices.io/post/architecture/2025/04/25/microservices-authn-authz-part-1-introduction.html#database-access-logic&quot;&gt;part 1&lt;/a&gt;, is to integrate the authorization check into the data access logic, i.e. the SQL query.
In &lt;a href=&quot;https://microservices.io/post/architecture/2025/09/16/microservices-authn-authz-part-4-authorization-using-fetch-and-replicate.html#the-replicate-strategy-is-faster-and-less-coupled&quot;&gt;part 4&lt;/a&gt; I described this approach with an example that efficiently retrieved &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecuritySystems&lt;/code&gt; by executing SQL SELECT that joined the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;security_systems&lt;/code&gt; table with data replicated from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Customer Service&lt;/code&gt;.
Let’s look at how to do that when using Oso Cloud.&lt;/p&gt;

&lt;h3 id=&quot;integrating-oso-into-the-database-access-logic-using-local-authorization&quot;&gt;Integrating Oso into the database access logic using local authorization&lt;/h3&gt;

&lt;p&gt;Oso Cloud has a feature called &lt;a href=&quot;https://www.osohq.com/docs/develop/facts/local-authorization&quot;&gt;local authorization&lt;/a&gt;, which makes authorization decisions using a combination of facts stored in Oso Cloud and the service’s database.
Two key local authorization methods are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.listLocal()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.authorizeLocal()&lt;/code&gt;.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.authorizeLocal()&lt;/code&gt; method is the local authorization equivalent of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.authorize()&lt;/code&gt;.
It returns a SQL SELECT statement that, when executed by the service, returns either true (authorized) or false (not authorized).
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.listLocal()&lt;/code&gt; method returns a SQL WHERE clause fragment that can be used to implement bulk queries such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;findSecuritySystems()&lt;/code&gt;.
I’ll describe how to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.authorizeLocal()&lt;/code&gt; later in this article.
Let’s first look at how to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.listLocal()&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;configuring-local-authorization&quot;&gt;Configuring local authorization&lt;/h4&gt;

&lt;p&gt;To use local authorization, you must specify a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;local_authorization_config.yaml&lt;/code&gt; when creating the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Oso&lt;/code&gt; client:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OsoServiceConfiguration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configurationFilePath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...;&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Oso&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;oso&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@Value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;${oso.url}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;osoUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;nd&quot;&gt;@Value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;${oso.auth}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;osoAuth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;optionsBuilder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OsoClientOptions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configurationFilePath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;optionsBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;withDataBindingsPath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configurationFilePath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Oso&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;osoAuth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;URI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;osoUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;optionsBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The path to the configuration file is passed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;optionsBuilder.withDataBindingsPath()&lt;/code&gt;.
One interesting challenge in a Spring Boot application is that the configuration file is typically in a JAR file nested within the Spring Boot JAR file.
The RealGuardIO example application contains a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClasspathLocalAuthorizationConfigFileSupplier&lt;/code&gt; that maps a classpath resource to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.nio.file.Path&lt;/code&gt; using a Virtual FileSystem - a Java feature that I was previously unaware of.&lt;/p&gt;

&lt;p&gt;The local authorization configuration file contains two sections.
First, the first section maps Polar predicates, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;has_relation(…​)&lt;/code&gt;, which are named logical rules or facts in Oso Cloud’s policy language, to SQL SELECT queries.
This mapping enables Oso Cloud to generate SQL that uses facts stored locally.
Second, the second section maps resource types to database column types.
This section is optional but recommended in order to improve performance.&lt;/p&gt;

&lt;p&gt;Interestingly, in this particular example, all required authorization data is replicated to Oso, so no fact mappings are required.
Strictly speaking, this example can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Oso.list()&lt;/code&gt; instead of local authorization.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Oso.list(user, permission, resourceType)&lt;/code&gt; returns a list of resourceIDs that the user has permission to perform an action on.
A service can then use that list to construct an SQL SELECT.
However, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.listLocal()&lt;/code&gt; is not only more convenient, since it returns a SQL fragment, but it also supports scenarios, such as the one described later in this article, that require local data.&lt;/p&gt;

&lt;p&gt;Here’s the configuration file that configures local authorization:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;facts:

sql_types:
  Location: integer
  SecuritySystem: integer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This configuration file specifies that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Locations&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecuritySystems&lt;/code&gt; have an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Integer&lt;/code&gt; primary key.
Later in this article, we will revisit this configuration file for a scenario where some facts are stored locally.&lt;/p&gt;

&lt;h4 id=&quot;implementing-findsecuritysystems-with-osolistlocal&quot;&gt;Implementing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;findSecuritySystems()&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.listLocal()&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;Let’s now look at how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;findSecuritySystems()&lt;/code&gt; can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.listLocal()&lt;/code&gt;.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listLocal()&lt;/code&gt; method has four parameters:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user&lt;/code&gt; - the ID of the user attempting to access the resources&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;permission&lt;/code&gt; - the permission, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;view&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resourceType&lt;/code&gt; - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecuritySystem&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ID column&lt;/code&gt; - the primary key column of the table containing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecuritySystems&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This method makes it straightforward to integrate authorization checks into SQL queries.
The SQL SELECT for retrieving &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecuritySystems&lt;/code&gt; looks something like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var sql = &quot;SELECT * FROM ss security_systems WHERE &quot; + oso.listLocal(...);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The SELECT’s WHERE clause is simply the fragment returned by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listLocal()&lt;/code&gt;.
The following diagram shows how this works:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/i/microservices-auth/part-6/oso-list-local.png&quot; alt=&quot;oso list local&quot; class=&quot;img-responsive&quot; /&gt;
&lt;/figure&gt;

&lt;p&gt;In this example scenario, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listLocal()&lt;/code&gt; returns a SQL fragment that’s equivalent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ss.id IN (202, 203)&lt;/code&gt;.
In other words, Oso Cloud returns an SQL WHERE-clause predicate containing inline values that constrain the IDs of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecuritySystems&lt;/code&gt; that the user is allowed to view.
Later, you will see that the SQL predicate can join with other tables when authorization uses local data.
Let’s now look at an example of using local fact data for authorization.&lt;/p&gt;

&lt;h2 id=&quot;making-authorization-decisions-with-locally-stored-facts&quot;&gt;Making authorization decisions with locally stored facts&lt;/h2&gt;

&lt;p&gt;Currently, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Customer Service&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Security Service&lt;/code&gt; populate Oso with all the facts needed for authorization.
As a result, the SQL fragment returned by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Oso.listLocal()&lt;/code&gt; does not reference any database tables.
However, while the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Customer Service&lt;/code&gt; needs to publish its data to Oso so that it is available to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Security Service&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Security Service&lt;/code&gt; does not.
Instead, it can use local authorization to combine the facts in its database with those in Oso.&lt;/p&gt;

&lt;p&gt;Specifically, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Security Service&lt;/code&gt; does not need to publish the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecuritySystemAssignedToLocation&lt;/code&gt; event to maintain the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Location-SecuritySystem&lt;/code&gt; relationship in Oso.
Instead, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;has_relation(SecuritySystem{…​}, &quot;location&quot;, Location{…​)&lt;/code&gt; fact can be mapped to the SQL &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; that queries the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;security_system&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;Let’s first look at the configuration file that defines the mapping.
After that, we’ll revisit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;findSecuritySystems()&lt;/code&gt; query.
Finally, we’ll explore how to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.authorizeLocal()&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;the-configuration-file&quot;&gt;The configuration file&lt;/h3&gt;

&lt;p&gt;Here’s the Oso configuration file that maps the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;has_relation(SecuritySystem{SECURITY_SYSTEM}, &quot;location&quot;, Location{LOCATION})&lt;/code&gt; relation to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;security_system&lt;/code&gt; table:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;facts:
  &quot;has_relation(SecuritySystem:_, String:location, Location:_)&quot;:
    query: &apos;SELECT id, location_id FROM security_system WHERE location_id IS NOT NULL&apos;

sql_types:
  Location: integer
  SecuritySystem: integer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s now look at how this affects the SQL fragment returned by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.listLocal()&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;the-findsecuritysystems-query-with-local-facts&quot;&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;findSecuritySystems()&lt;/code&gt; query with local facts&lt;/h3&gt;

&lt;p&gt;While the code that implements &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;findSecuritySystems()&lt;/code&gt; is unaffected by this change, the SQL fragment now references the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;security_system&lt;/code&gt; table.
Oso Cloud determines the locations that the user is authorized to access and returns an SQL fragment that queries the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;security_system&lt;/code&gt; table to determine the IDs of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecuritySystems&lt;/code&gt; at those locations.
Here’s an example fragment:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ss.id IN (WITH RECURSIVE
c0(arg0, arg2) AS NOT MATERIALIZED (
SELECT id, location_id FROM security_system WHERE location_id IS NOT NULL
)
 SELECT f1.arg0
FROM c0 AS f1, (
VALUES (1769998271122), (17699982711222)
) as cs( arg0 )
WHERE f1.arg2 = cs.arg0
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This generated fragment uses common table expressions that are essentially named subqueries.
It’s equivalent to:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  ss.id IN (SELECT id  FROM security_system  WHERE location_id IN (1769998271122, 17699982711222))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that we’ve seen how to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.listLocal()&lt;/code&gt; to implement bulk queries, let’s look at local authorization for single-entity operations.&lt;/p&gt;

&lt;h3 id=&quot;using-authorizelocal&quot;&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorizeLocal()&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Since some facts are only available locally, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Security System Service&lt;/code&gt; cannot use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.authorize()&lt;/code&gt; (described previously in &lt;a href=&quot;https://microservices.io/post/architecture/2025/12/09/microservices-authn-authz-part-5-using-an-authorization-service.html&quot;&gt;part 4&lt;/a&gt;) to authorize operations such as ‘arm’ and ‘disarm’.
Instead, it must use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oso.authorizeLocal()&lt;/code&gt;.
This method has three parameters:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user&lt;/code&gt; - the user attempting to perform the operation&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;permission&lt;/code&gt; - the operation, such as “disarm”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resourceID&lt;/code&gt; - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecuritySystem&lt;/code&gt; with ID 101&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It returns a SQL query that determines whether the user is authorized to access that resource.
The query returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;.
The following diagram shows how it works:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/i/microservices-auth/part-6/oso-authorize-local.png&quot; alt=&quot;oso authorize local&quot; class=&quot;img-responsive&quot; /&gt;
&lt;/figure&gt;

&lt;p&gt;Here, for example, is how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Security System Service&lt;/code&gt; can check whether a user is authorized to disarm a security system:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oso&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;authorizeLocal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;CustomerEmployee&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
              &lt;span class=&quot;s&quot;&gt;&quot;disarm&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SecuritySystem&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;securitySystemId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allowed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jdbcTemplate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;queryForObject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Boolean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s the SQL query returned by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorizeLocal()&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;WITH&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;RECURSIVE&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;c0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MATERIALIZED&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location_id&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;security_system&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location_id&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;EXISTS&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1767657091967&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;17676570919672&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allowed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This query is equivalent to:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  SELECT EXISTS (
    SELECT 1 FROM security_system
    WHERE id = 1 AND location_id IN (1767657091967, 17676570919672)
  ) AS allowed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In other words, Oso generates a SQL query that determines whether the specified &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecuritySystem&lt;/code&gt; is at a location that the user is allowed to disarm.&lt;/p&gt;

&lt;h2 id=&quot;show-me-the-code&quot;&gt;Show me the code&lt;/h2&gt;

&lt;p&gt;The RealGuardIO application (work-in-progress) can be found in the following &lt;a href=&quot;https://github.com/eventuate-examples/eventuate-examples-realguardio&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://www.linkedin.com/in/hazalmestci/&quot;&gt;Hazal Mestci&lt;/a&gt; for reviewing this article and providing valuable feedback.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Oso local authorization enables a service to make authorization decisions using a combination of facts stored in Oso and the service’s local database&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listLocal(user, permission, resourceType, ID column)&lt;/code&gt; - returns a SQL WHERE clause fragment that filters results based on permissions&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorizeLocal(user, permission, resource)&lt;/code&gt; - returns a SQL SELECT that makes authorization decisions using local data&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Local authorization requires a configuration file that maps Polar predicates facts, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;has_relation&lt;/code&gt;, which are named logical rules or facts in Oso Cloud’s policy language, to SQL queries&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The generated SQL fragments and SELECT statements can include Oso facts, such as resource IDs&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If local tables and Oso-stored data overlap, the generated SQL can contain a union of local and Oso-stored data&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;need-help-with-modernizing-your-architecture&quot;&gt;Need help with modernizing your architecture?&lt;/h2&gt;

&lt;p&gt;I help organizations modernize safely and avoid creating a modern legacy system — a new architecture with the same old problems. If you’re planning or struggling with a modernization effort, I can help.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrisrichardson.net&quot;&gt;Learn more about my modernization and architecture advisory work →&lt;/a&gt;&lt;/p&gt;

</description>
            <pubDate>Fri, 13 Feb 2026 08:03:00 +0000</pubDate>
            <link>http://microservices.io//post/architecture/2026/02/13/microservices-authn-authz-part-6-oso-local-authorization.html</link>
            <guid isPermaLink="true">http://microservices.io//post/architecture/2026/02/13/microservices-authn-authz-part-6-oso-local-authorization.html</guid>
        </item>
        
    </channel>
</rss>
