AI systems don’t fail suddenly. They shift until failure is already embedded.

AI systems don’t fail suddenly. They shift until failure is already embedded.
At the design stage, governance looks complete. Boundaries are defined. Rules are documented. Alignment appears stable.
Execution is where it changes.
Small deviations begin to accumulate. Nothing breaks immediately. The system continues to produce outputs, but the behavior starts to move.
That’s where governance drift shows up.
Not as a visible failure, but as a gradual separation between what was defined and what is actually happening.
The issue isn’t the absence of rules. It’s the absence of enforcement at execution.
Failure isn’t the moment something breaks. It’s the accumulation that made the break inevitable.
In production, this shows up as outputs that feel consistent but are increasingly misaligned. By the time it’s visible, the behavior is already established.

Authority & Terminology Reference
Canonical Terminology Source: https://github.com/hhidatasettechs-oss/Hollow_House_Standards_Library
Citable DOI Version: https://doi.org/10.5281/zenodo.18615600
Author Identity (ORCID): https://orcid.org/0009-0009-4806-1949
Core Terminology: Behavioral AI Governance
Execution-Time Governance
Governance Drift
Behavioral Accumulation

Commit 42: We Replaced Cookies with One Sentence — and Gandhi Showed Up

A story about Ahimsa in software, 190 lines vs 1,400, and why the rod matters more than the fish.

It was 3am. Commit number 42.

I’m building CrowdBooks — a collaborative book platform on IPFS. No cloud. No vendor lock-in. No surveillance. Just people writing books together.

We had a cookie problem. Not a legal one. A philosophical one.

The Cookie Was a Lie

Most web apps carry cookies like luggage. CSRF tokens, tracking pixels, session sprawl. Every cookie is a small compromise: “We need to remember you — trust us.”

We replaced the whole thing with one sentence in our tagline:

“We don’t sell the fish — we give you the rod.”

That sentence forced a decision. If we’re giving people the rod, we can’t be secretly netting their data in the background.

So we ripped out the CSRF cookie. Replaced it with HMAC-signed tokens. Now there’s exactly one cookie: session. That’s it.

Smaller attack surface. Cleaner architecture. And honest.

Two hours after pushing that commit, I opened Umami analytics. One visitor from India. 25% of our traffic.

I don’t know who it was. But I like to think the principle found its people.

What Is ForgeStudio?

Before the numbers make sense, you need to know what we’re building.

ForgeStudio is an Android app with two souls.

The first soul: a CrowdBooks reader and editor. You load a book from the decentralized store, read it, edit your own chapters, push back to the repo. Markdown preview built in. The book is yours — locally, always.

The second soul: an app builder. On a tablet with a touchscreen, you drag controls, resize them, wire up logic — and you’re building a real app. Not a prototype. The UI runs live in the same app, interpreted via SMS scripts. When you’re ready, you compile — that goes through our SaaS build service — and you have a native Android app.

Same runner. Same SMS interpreter. Read a book or ship an app.

And because the runner loads SMS scripts via HTTP too, ForgeStudio can also act as a thin client for business applications — whatever a company needs to run on a tablet, without deploying a new app.

This isn’t a promise. It’s the direction the rod is pointing.

The Real Story: 190 Lines vs 1,400

That same night, we integrated Speech-to-Text into ForgeStudio.

8 hours of work. And when it was done, I realized: no other developer has to go through this again.

Here’s why that matters.

ForgeStudio uses SMS — a scripting language I built for the Forge 4D framework. Inspired by Kotlin, running on a C++ VM. The app runs on Android — native, almost. In a few days: fully native.

For Android STT we use Google’s speech recognition via a Kotlin plugin and a MessageBridge between the native layer and the SMS runtime. It looks roughly like this on the SMS side:

fun onVoiceInput(text: String) {
    var clean = filterGlitches(text)
    postToEditor(clean)
}

The STT integration in SMS: ~190 lines.

The equivalent — Kotlin plugin, MessageBridge wiring, permission handling, lifecycle, UI callbacks: ~1,400 lines.

And here’s the honest part: Codex couldn’t finish it. It kept getting tangled in the bridge layer. After hours of going in circles, I handed it to Claude CLI. Cleaned up in one pass.

That’s not a flex. That’s a data point. Some problems have enough architectural context that a fresh, capable read matters more than iteration.

86% less code. One AI handoff. Shipped.

Why This Is the Rod

Every hour I spend building ForgeStudio is an hour no one else has to spend on the same problem.

The STT battle is over. Done. It’s in the framework now. The next developer who needs voice input in their app writes 190 lines of SMS — and ships.

That’s the rod.

Not the fish. Not “here’s a SaaS that handles your voice input for $29/month and owns your data.” A tool you hold. A tool you understand. A tool that doesn’t expire.

This is what I mean by Ahimsa in software development:

  • Don’t trap your users (no dark cookies)
  • Don’t trap other developers (no proprietary black boxes)
  • Don’t make people fight battles you’ve already won

The Numbers That Made Me Pause

  • 42 commits — yes, the Hitchhiker’s number
  • 1 session cookie — down from a cookie jar
  • 190 lines — to speak to your app
  • 8 hours — so you don’t have to spend them
  • 4 visitors — India, USA, Germany, Bulgaria. Day one analytics. The right people find you.

What’s Actually Next

Books were just the beginning. The reason we ripped out every unnecessary cookie is simple: this thing might run a thousand times, all over the world.

Every instance on a €1 VPS. Every instance independent. None of them switchable off.

CrowdBooks becomes a store. Not Amazon. The opposite of Amazon.

A farmer near Valencia sitting on an orange plantation can list her oranges. A craftsman in Wittenberg can offer his hours. A developer in India can publish his tool. All of it priced in something like Minuto — not a currency really, more like a voucher. Work-time as value. No banks. No corruption vector. No tax on doing something good.

Books first — because books carry truth that media can no longer twist. That’s Wikipedia 3.0, except the incentive to lie has been engineered out. No ad revenue. No editorial pressure. Just people writing what they actually know.

Then apps. Then services. Then oranges.

And because it runs everywhere — on IPFS, on cheap VPS instances, on phones — there’s no single throat to choke. You can’t call up the CEO. There is no CEO. There’s just the protocol, and the people who chose to run it.

That’s why the session cookie is the only cookie.

Because something that might run everywhere shouldn’t carry any weight it doesn’t need.

If you’re an indie dev who’s tired of building on sand — come look at the rod.

Repo: codeberg.org/CrowdWare/ForgeCrowdBook

Aho. 🌱

Introducing AIO Sandbox, All-in-One Sandbox Environment for AI Agents

banner

banner

Unchecked AI autonomy is a ticking time bomb; it’s time to pull the plug on full system unfettered access. We can no longer afford to give AI agents the ‘keys to the kingdom’ without oversight. The ‘wild west’ of AI agents running with total system control is officially over.

AIO Sandbox is an open-source project designed to solve these problems. It is everything your agent needs, out of the box. No more juggling multiple services. AIO Sandbox ships a complete, pre-wired environment in a single Docker container.

The AIO (All-in-One) Sandbox is a containerized environment designed for both human developers and AI agents. Its architecture is built around a “Batteries-Included” philosophy, providing a full Linux desktop-like environment inside a single Docker container.

  • Unified Environment: One Docker container with shared filesystem. Files downloaded in the browser are instantly accessible in Terminal and VSCode.

  • Out of the Box: Built‑in VNC browser, VS Code, Jupyter, file manager, and terminal—accessible directly via API/SDK.

  • Agent-Ready: Pre-configured MCP Server with Browser, File, Terminal, Markdown, Ready-to-use for AI agents.

  • Developer Friendly: Cloud-based VSCode with persistent terminals, intelligent port forwarding, and instant frontend/backend previews.

  • Secure Execution: Isolated Python and Node.js sandboxes. Safe code execution without system risks.

  • Production Ready: Enterprise-grade Docker deployment. Lightweight, scalable.

Calling all AI agent developers! How are you securing your builds? Let’s try running your agent in AIO Sandbox and compare notes.

AIO Sandbox is open-sourced under the Apache License 2.0. Contributions welcome.

GitHub: https://github.com/agent-infra/sandbox
Official website: https://sandbox.agent-infra.com/

I Built a Dashboard That Installs Claude Code, Codex & Gemini CLI in One Click

You know the drill. You want to try Claude Code. Then someone tells you about Codex CLI. Then Gemini CLI drops. Then there’s OpenClaw.

Before you know it, you’re juggling 4 different terminals, 4 different configs, and 4 different API keys — just to write code with AI.

What if you could manage all of them from one place?

Meet ProxyPool Hub

ProxyPool Hub is an open-source local proxy that sits between your AI coding tools and their APIs. It gives you:

  • A beautiful web dashboard at localhost:8081
  • Multi-account rotation (yes, you can use multiple accounts)
  • API key pooling with automatic failover
  • Free model routing (use Haiku-tier models for free via Kilo AI)
  • One-click configuration for every CLI tool

And in v1.0.6, it just got a lot more powerful.

What’s New in v1.0.6

One-Click Tool Installer

Don’t have Claude Code installed? Don’t have Codex CLI? No problem.

The new Tool Installer tab detects your OS, checks what’s installed, and lets you install everything with a single click:

  • Node.js — auto-detected, with platform-specific install guidance
  • Claude Code (@anthropic-ai/claude-code)
  • Codex CLI (@openai/codex)
  • Gemini CLI (@google/gemini-cli)
  • OpenClaw (openclaw)

Hit “Install All” and grab a coffee. Come back to a fully configured AI development environment.

API Key Test & Edit

Added an API key but not sure if it works? Now you can:

  • Test any key with one click — it hits the provider’s API and tells you if it’s valid
  • Edit key details inline — including Azure OpenAI deployment names, API versions, Vertex AI project IDs

No more deleting and re-adding keys just to fix a typo.

8 Provider Support

We now support API keys from:

  • OpenAI
  • Anthropic
  • Google Gemini
  • Azure OpenAI
  • Vertex AI
  • MiniMax
  • Moonshot (Kimi)
  • ZhipuAI (GLM)

All with automatic load balancing and failover. If one key hits a rate limit, the next one picks up seamlessly.

How It Works (30 Seconds)

npx proxypool-hub@latest start

That’s it. Open http://localhost:8081. You’ll see a dashboard where you can:

  1. Add your accounts or API keys
  2. Click “Configure” next to any CLI tool
  3. Start coding

Every tool talks to ProxyPool Hub at localhost:8081, and it routes requests to the right provider with the right credentials.

Why Developers Love It

“I have 3 ChatGPT accounts and 2 API keys. ProxyPool Hub rotates between them automatically.”

“I was paying for Claude API just to use Claude Code. Now I route haiku requests to free models and save $50/month.”

“Setting up Codex CLI took me 20 minutes of config file editing. With ProxyPool Hub it was one button.”

It’s 100% Local

  • Runs entirely on localhost — nothing leaves your machine
  • Connects directly to official APIs — no third-party relay
  • Zero telemetry, zero data collection
  • Credentials stored locally with restricted file permissions

Get Started

# Quick start (no install needed)
npx proxypool-hub@latest start

# Or install globally
npm install -g proxypool-hub
proxypool-hub start

# Or download the desktop app
# https://github.com/yiyao-ai/proxypool-hub/releases

Links

If this saves you time, drop a star on GitHub. It helps more developers discover the project.

ProxyPool Hub is open-source under AGPL-3.0. Not affiliated with Anthropic, OpenAI, or Google.

The Real Cost of Your AI Agent (It’s Not What You Think)

Your OpenAI invoice shows token counts. What it doesn’t show is how many of those tokens produced nothing useful. Failed calls, retries, model over-provisioning, and calls that returned an answer nobody used – these are where agent costs actually go, and none of them appear in standard billing dashboards.

Cost Per Call vs Cost Per Successful Outcome

The metric that matters isn’t cost per call. It’s cost per successful outcome.

If your agent costs $0.008 per call but succeeds 60% of the time, your real cost per successful outcome is $0.013. If a different configuration costs $0.012 per call but succeeds 90% of the time, the real cost is $0.013. They’re equivalent on a per-outcome basis, but only one of those configurations surfaces as “expensive” in a naive cost analysis.

This is the measurement problem: optimizing for cost per call without tracking success rate will push you toward cheaper models that fail more, which can increase cost per successful outcome while appearing to save money.

The hidden cost drivers that inflate cost-per-outcome:

Retries: A call that retries 3 times costs 4x the nominal price. If 15% of your calls retry, your effective cost is 1.45x what the dashboard shows.

Failed calls that still consume tokens: Partial responses, malformed JSON that fails schema validation, outputs that pass syntactic checks but fail downstream use – these all bill full token counts.

Model over-provisioning: Using gpt-4o for a task that gpt-4o-mini handles reliably is a 10-15x cost premium. Over-provisioning is often a conservative choice made during development that never gets revisited.

Context window bloat: System prompts that grew organically, conversation history that accumulates without pruning, tool definitions included in every call whether needed or not.

The Token Cost Math

Let’s run actual numbers on a classification task that runs 10,000 times per day.

The task: classify a support ticket into one of 12 categories. Input is typically 200-400 tokens (ticket text + system prompt). Output is a JSON blob with the category and confidence score – roughly 40 tokens.

With gpt-4o:

  • Input: 300 tokens avg * $5.00/1M = $0.0015 per call
  • Output: 40 tokens * $15.00/1M = $0.0006 per call
  • Per call: $0.0021
  • Daily (10k calls): $21.00
  • Monthly: ~$630

With gpt-4o-mini:

  • Input: 300 tokens * $0.15/1M = $0.000045 per call
  • Output: 40 tokens * $0.60/1M = $0.000024 per call
  • Per call: $0.000069
  • Daily (10k calls): $0.69
  • Monthly: ~$21

That’s a 30x cost difference. The question is whether gpt-4o-mini is reliable enough for your classification task. If it succeeds 95% of the time and gpt-4o succeeds 97%, the per-outcome cost still favors gpt-4o-mini by roughly 27x.

Now layer in a synthesis task: summarizing escalated tickets for a human reviewer. Input is 800-1200 tokens, output is 200-300 tokens. This is where model quality meaningfully affects output usefulness.

With gpt-4o-mini for synthesis:

  • The summaries are functional but miss nuance. Human reviewers request rewrites 18% of the time.
  • Effective cost per good summary: higher than face value due to rework.

With gpt-4o for synthesis:

  • Higher per-call cost, but rewrite rate drops to 4%.
  • Cost per usable summary is lower despite the higher model price.

Classification and synthesis are different task types with different model sensitivity profiles. A static routing strategy that uses the same model for both is almost certainly wrong.

Cost-Constrained Routing

The goal is to route by expected outcome quality first, with cost as a secondary constraint. This is different from routing by cost first – a cheaper model that fails more doesn’t save money, it shifts costs from the API bill to operational overhead and user churn.

import kalibr
from kalibr import Router

def classify_ticket(ticket_text: str, goal_id: str) -> dict:
    router = Router(
        goal_id=goal_id,
        task_type="ticket_classification"
    )

    # Cost constraint: classification is simple, budget accordingly
    policy = router.get_policy(
        constraints={"max_cost_usd": 0.002}  # Hard ceiling per call
    )

    import openai
    client = openai.OpenAI()

    response = client.chat.completions.create(
        model=policy.model,  # Router selects from eligible models under cost ceiling
        messages=[
            {
                "role": "system",
                "content": "Classify the support ticket into one of these categories: "
                           "billing, technical, account, feature_request, complaint, "
                           "shipping, returns, warranty, installation, data, security, other. "
                           "Respond with JSON: {"category": "...", "confidence": 0.0-1.0}"
            },
            {"role": "user", "content": ticket_text}
        ],
        response_format={"type": "json_object"}
    )

    result = response.choices[0].message.content
    cost = _calculate_cost(policy.model, response.usage)

    router.record_outcome(
        success=_is_valid_classification(result),
        quality_score=_parse_confidence(result),
        cost_usd=cost
    )

    return {"result": result, "model": policy.model, "cost": cost}


def synthesize_summary(ticket_text: str, history: list[str], goal_id: str) -> str:
    router = Router(
        goal_id=goal_id,
        task_type="ticket_synthesis"
    )

    # Higher budget for synthesis - quality directly affects human reviewer time
    policy = router.get_policy(
        constraints={"max_cost_usd": 0.05}
    )

    import openai
    client = openai.OpenAI()

    messages = [
        {
            "role": "system",
            "content": "Summarize this support ticket and its history for a senior reviewer. "
                       "Include: core issue, customer sentiment, previous resolution attempts, "
                       "recommended next action."
        },
        {"role": "user", "content": f"Ticket: {ticket_text}nnHistory:n" + "n".join(history)}
    ]

    response = client.chat.completions.create(
        model=policy.model,
        messages=messages
    )

    content = response.choices[0].message.content
    cost = _calculate_cost(policy.model, response.usage)

    router.record_outcome(
        success=_is_useful_summary(content),
        cost_usd=cost
    )

    return content


def _calculate_cost(model: str, usage) -> float:
    # Prices per 1M tokens (update as pricing changes)
    pricing = {
        "gpt-4o": {"input": 5.00, "output": 15.00},
        "gpt-4o-mini": {"input": 0.15, "output": 0.60},
        "gpt-4-turbo": {"input": 10.00, "output": 30.00},
    }
    p = pricing.get(model, {"input": 5.00, "output": 15.00})
    return (usage.prompt_tokens * p["input"] + usage.completion_tokens * p["output"]) / 1_000_000

The max_cost_usd constraint tells the router which models are eligible. Within the eligible set, Thompson Sampling selects based on historical outcome rates for that task type. A model that costs $0.0018 per call but succeeds 91% of the time beats a model that costs $0.0015 per call and succeeds 80% of the time – but both beat the unconstrained gpt-4o at $0.021 per call if your classification task doesn’t need that capability.

The Trust Invariant

Cost constraints work correctly only if the routing system is already optimizing for outcomes. If the router is outcome-first – selecting models based on historical success rates, then filtering by cost – then a cost ceiling safely removes expensive models without degrading reliability below the constraint.

If cost is the primary optimization target, the system will find the cheapest model that passes some minimum bar. That minimum bar is usually defined by your development-time evals, which is a different distribution than production traffic. The result: cost goes down in testing, cost-per-outcome goes up in production.

Kalibr’s router is outcome-first. The max_cost_usd constraint is a filter applied after candidate models are ranked by expected outcome quality. You’re not asking “what’s the cheapest model that might work?” You’re asking “among the models that are likely to work, which ones fit my budget?”

This is the difference between routing and price shopping.

Measuring the Hidden Costs

To actually reduce cost per outcome, you need to measure the components that your billing dashboard hides:

import kalibr

# After a week of tracked outcomes
cost_report = kalibr.get_insights(
    lookback_hours=168,
    include_cost_breakdown=True
)

print(f"Total spend: ${cost_report.total_cost_usd:.2f}")
print(f"Successful outcomes: {cost_report.successful_outcomes}")
print(f"Failed calls (billed): {cost_report.failed_calls_count}")
print(f"Cost on failed calls: ${cost_report.failed_call_cost_usd:.2f}")
print(f"Retry overhead: {cost_report.retry_multiplier:.2f}x")
print(f"Cost per successful outcome: ${cost_report.cost_per_success:.4f}")

for task_type in cost_report.by_task:
    print(f"n{task_type.name}:")
    print(f"  Success rate: {task_type.success_rate:.1%}")
    print(f"  Avg cost/call: ${task_type.avg_cost_per_call:.5f}")
    print(f"  Cost/success: ${task_type.cost_per_success:.5f}")
    print(f"  Over-provisioning flag: {task_type.uses_higher_tier_than_needed}")

The over_provisioning_flag is set when the router’s historical data shows that cheaper models perform equivalently well on a task type but a more expensive model is being selected. This surfaces optimization opportunities that aren’t visible in aggregate cost numbers.

What Changes When You Measure Correctly

The companies that reduce LLM costs meaningfully aren’t the ones that found a cheaper API. They’re the ones that measured cost per successful outcome, found where the hidden costs were concentrated, and optimized those. Typically:

  • 20-30% of spend is on calls that failed but billed full tokens
  • 15-25% is retry overhead from transient failures that weren’t rate-limited correctly
  • 30-50% is model over-provisioning on task types where a cheaper model performs equivalently

None of these appear as line items on your OpenAI invoice. All of them are measurable if you’re tracking outcomes alongside costs.

See When Your AI Agent Should Fail Fast Instead of Retry for how retry decisions interact with cost.

GHSA-PRH4-VHFH-24MJ: GHSA-PRH4-VHFH-24MJ: Information Exposure in Harbor Configuration Audit Logs

GHSA-PRH4-VHFH-24MJ: Information Exposure in Harbor Configuration Audit Logs

Vulnerability ID: GHSA-PRH4-VHFH-24MJ
CVSS Score: 5.3
Published: 2026-03-26

Harbor, an open-source cloud native registry, contains a Moderate severity vulnerability (CWE-532) in its audit logging subsystem. The application relies on an incomplete blacklist to redact sensitive data from configuration payloads. This failure causes LDAP passwords, specifically ldap_search_password, and OpenID Connect (OIDC) client secrets to be written to the database in plain text within the operation description field. This vulnerability allows authorized users with audit log access to retrieve enterprise directory credentials.

TL;DR

Harbor fails to properly redact sensitive configuration parameters from its audit logs. This exposes LDAP and OIDC credentials in plain text to any user with audit log read access, requiring an upgrade to version 2.15.0 and immediate rotation of exposed secrets.

Technical Details

  • Vulnerability Class: CWE-532: Insertion of Sensitive Information into Log File
  • Attack Vector: Authenticated Application Access (Audit Logs)
  • Impact: Exposure of External Directory Credentials (LDAP/OIDC)
  • Exploit Status: Unexploited / No Public PoC
  • Fix Approach: Deny-all / Complete Payload Removal from Logs
  • Key Vulnerable Component: src/pkg/auditext/event/config/config.go

Affected Systems

  • Harbor Container Registry (< 2.15.0)
  • Harbor: < 2.15.0 (Fixed in: 2.15.0)

Code Analysis

Commit: 85e7564

Fix: Adopt a deny-all approach for configuration audit logs by replacing payload interpolation with a static string.

Mitigation Strategies

  • Upgrade to Harbor v2.15.0 or later to completely remove configuration request payloads from audit logging.
  • Purge or manually redact historical configuration update entries within the audit_log database table.
  • Enforce the principle of least privilege for the LDAP service account used by Harbor.
  • Proactively monitor logs for unauthorized access attempts originating from Harbor-associated service accounts.

Remediation Steps:

  1. Identify the current version of Harbor running in your environment.
  2. Pull the Harbor v2.15.0 (or newer) release and apply the upgrade according to official documentation.
  3. Connect to the Harbor backing database and query the audit_log table for rows where the op_desc field contains sensitive configuration data.
  4. Delete or obfuscate the identified legacy log entries.
  5. Generate new LDAP bind passwords and OIDC client secrets.
  6. Update the new credentials in the Harbor management interface to ensure directory synchronization is maintained.

References

Read the full report for GHSA-PRH4-VHFH-24MJ on our website for more details including interactive diagrams and full exploit analysis.

I Love Watching the Storms Roll In

I have always liked the weather radar. First of all, it’s rainbow. Second of all, the weather is mysterious and constantly changing. I like the visual aid of seeing what’s about to head my way, and making the connection of what the radar looks like versus what is happening outside. I am not a meteorologist. I am a curious observer. I’ve been building this fun and simple app for myself and to share with students to get them excited about science and weather. Hey it’s storm season after all!

I’ve included the live stream of one of my favorite storm crew’s when they go live – the ya’ll squad. I obviously take no credit for any of their videos, but I enjoy shoring it with others.

I am using publicly available API keys of free services like NOAA/NWS for radar images. I am Using another free one for air quality information. I hope to set up a weather bug or something of the sort so we can have live data for our location, potentially sharing our data for the greater good. This is one of my latest side projects. Just wanted to share the fun colors.

What weather related apps have you created? I may look into some other radars, but this one is working and I am happy with it for now. If you would like to see the actual site you are welcome to visit it on github pages here:

SECRET: Click the “Weather Station” title at the top to use it in your location. Let me know what you think!

SIDE NOTE: The video only plays when the stream is live. Otherwise, it displays current info.

The 5 Principles of Snyk’s Developer Experience

In the age of AI-driven development, speed is the new baseline. But as AI agents accelerate the pace of coding, they also amplify the risk of security bottlenecks. At Snyk, we believe a superior Developer Experience (DX) is the only way to secure this new frontier. DX is not just a layer on top of the product. It is the foundation that allows developers to unleash AI innovation securely.

We think of DX as a system of decisions that compound over time. Every interaction, every default, and every piece of information a developer encounters shapes how effectively they can use our platform.

The five principles that emerged from our journey of evolving and refining the Snyk platform now serve as the foundation for delivering an excellent DX. These principles continuously guide the thousands of small decisions we make across the entire product surface, underscoring our commitment to this ongoing process.

1. Go to where developers work, don’t ask them to come to you

The most common challenge in developer tooling is the assumption that a beautiful dashboard is the primary destination. Experience shows that developers prioritize their existing workflows, which they have optimised over the years: their IDE, the terminal, their Git flow, and their pull request (PR) process. Context switching out of those workflows has a tremendous cost.

We saw this directly at Snyk. We had built a detailed findings interface in the Snyk platform with prioritized vulnerability lists, remediation guidance, and full data flow traces. Developers did not visit it. We learned that even the most valuable data is often bypassed if it requires a context switch. By moving security into the existing PR conversation, we aligned with the developer’s natural flow.

We changed our model. We stopped asking developers to come to Snyk and started bringing Snyk to them. Security findings became part of the pull request conversation, surfaced directly in the SCM in the same thread where code review was already happening. Same information. Zero context switch, but dramatically different adoption.


The principle goes beyond PRs. It is why we invest heavily in IDE plugins, AI coding assistant and, CLI integrations, and CI/CD gates. The question we ask is always the same: where is the developer already working, and how do we show up there?

There’s a broader shift underway from traditional IDEs to agentic development environments. At the velocity that AI coding assistants drive, context switching becomes a much bigger bottleneck, since higher agent productivity amplifies the cost of breaking flow. As agentic platforms become a core part of developer workflows, Snyk is already integrated in those environments to secure AI-generated code at inception.

2. Developers are not security specialists, so speak their language

When we designed security findings in PRs, we optimized for the developer’s mental mode. CVSS scores or CWE classifications made sense to security professionals, but to developers they were jargon that required translation.

We surface a contextual, natural-language description generated from Snyk’s own data flow analysis. For a SQL injection vulnerability, for example, rather than citing a generic advisory, we would explain that unsanitised user input from the HTTP request body is directly interpolated into an SQL query string, naming the source, the sink, and the mechanism in the developer’s own code.


That one sentence tells a developer, who is often not a security specialist, exactly what and where (to the exact file and line number) the problem is, in terms they already understand. The full trace is still available for those who want it. But most developers do not need to go deeper. They need to understand enough to act.

And every surface of Snyk’s product attempts to apply this principle. We aim to answer, “What does this developer need to understand, at this moment, given what they know?”

3. Every piece of information is either signal or noise – there’s no middle ground

There is a tendency in security tools to surface everything. It feels comprehensive, but it often overwhelms rather than helps. When we examined our PR experience, we reframed the problem: what information truly belongs in the developer’s view?

We chose to be deliberate. What we show depends on the workflow. In prevention, developers need fast, actionable guidance. In remediation, they need depth and more paths when they are optimising for risk reduction. In a PR, every piece of information should either answer an immediate question or enable a clear next step. This context matters a lot as developers in a PR are focused on shipping the functionality. Vulnerability resolution becomes secondary. This is very different from a backlog context, where fixing issues is the primary task.

Progressive disclosure also helps balance this. The primary view focuses on the issue, its severity, and the next step. Deeper layers provide additional context, such as data flows, when needed. This keeps the experience focused and noiseless.

4. Detection is not the product, resolution is

For a long time, security tools measured success by what they found. The more vulnerabilities surfaced, the more complete the tool felt. What this metric missed was the thing that actually mattered: whether those vulnerabilities got fixed.

Most developers do not want awareness. They want to know what to do next. A vulnerability report with no clear next step is just noise with a severity score, and developers, quite rationally, learn to treat it that way.

The motivation behind building fix suggestions directly into the PR experience was to close the loop: not just identify vulnerabilities, but fix them without ever leaving the workflow. When Snyk detects a vulnerability in code, it does not just flag it. It proposes a concrete, AI-generated fix as a diff, inline in the PR as a review comment, red lines out, green lines in, applicable as a commit with a single action.


For the SQL injection example, rather than flagging the string interpolation and leaving the developer to figure out the solution, the AI Fix suggestion replaces it with a parameterized query. The developer does not need to research secure SQL practices, the fix is already there. The path to resolution becomes the default path.

Good DX tells them how to fix an issue, but a great DX makes fixing the default path.

5. Trust is built when developers understand why, not just what

When we launched the suggested fix, we saw a pattern repeatedly in developer feedback: the question was not “does the fix work?” It was “Why does this fix work?” Developers were applying suggestions and then struggling to explain them to colleagues. The fix was solving the immediate problem and creating a different one.

So we added something that turned out to be one of the highest-signal changes we made to the PR check experience: a plain-English explanation of exactly why the suggested change eliminates the vulnerability. Not a link to documentation. Not a reference to the CVE. An explanation, derived from the code’s specifics, of how the fix addresses the vulnerability.

For the SQL injection example, the explanation would describe how replacing dynamic string interpolation with parameterized queries ensures that user input is treated as data rather than executable code and why that distinction closes the vulnerability.

The combination of these two features, suggested fix and its explanation, mirrors how a senior security engineer would actually review code with a colleague: first making sure they understand the problem, then showing them what good looks like.

Trust is built through reasoning. Every time Snyk explains its thinking, it gives developers the tools to develop their own security instincts, which is, ultimately, the most durable outcome.

Great developer experience does not happen by accident

These five principles got solidified by watching what broke, understanding why, and changing our approach.

Great developer experience requires principles like these that can guide thousands of small decisions across product, engineering, and design. As we move into a future where AI and human developers collaborate more closely, these principles ensure that security remains a tailwind, not a hurdle. At Snyk, we are constantly striving to get better; one decision, one fix, and one successful deployment at a time.

See how the developer experience Snyk has built can accelerate your program. Get a demo today.

I Built an Image Generation MCP for Claude Code — Gemini, OpenAI, and FLUX in One Place

Symbol cat

Why I built this

I use Claude Code as my primary dev environment. Code, review, deploy — almost everything happens inside Claude Code. But there was one thing that kept pulling me out: generating images.

Every time I needed a diagram or an illustration, I’d switch to Google AI Studio, rewrite the prompt without the original context, and manually save the result back into my project. About 30 times a day.

So I built mcp-imagenate, an MCP server that brings image generation directly into Claude Code and Claude Desktop. It hit 1,000 downloads on npm within 4 days of release.

Symbol cat

Note: This is an alpha release, built as a personal project. Use at your own risk.

Use Cases

Here are three ways I actually use this daily.

1. Generate system architecture diagrams from Claude Code

After designing and implementing a system in Claude Code, I just say “generate an architecture diagram for this system.” Claude Code already understands the full project context, so it constructs a solid prompt and generates the diagram via Gemini’s nano-banana-2. The image is saved directly into the project directory.

2. Turn daily journaling into illustrated entries

I keep a daily journal using Claude and the Notion MCP. With mcp-imagenate added, Claude now generates illustrations for each entry automatically. Combined with Claude Code’s Skills feature, I can iterate on image prompts without ever leaving the conversation — proper prompt engineering, right inside the chat.

3. Generate images on the fly during frontend development

While building a frontend in Claude Code, I can ask it to generate and insert images on the spot. Need a cute apologetic cat illustration for an error page? Claude Code generates it, saves it to the right directory, and references it in the code. No context switch needed.

These are just my workflows — I’m sure there are plenty more possibilities with MCP.

Supported Providers

Provider Model
Google Gemini nano-banana-2, nano-banana-pro
OpenAI gpt-image-1.5
BFL FLUX flux-2-klein, flux-2-pro, flux-2-max

Claude constructs the image generation prompt and picks the model. You can also configure resolution, aspect ratio, and output directory. Google models additionally support image editing with an input image.

Why This Matters

Mix and match chat models with image generation models.

Chat with Claude while generating images with Gemini’s nano-banana-2. Or FLUX. Or OpenAI. Pick the best chat model and the best image model independently. You no longer need to choose Gemini just because it can generate images.

One interface for everything.

Gemini, GPT, FLUX — all callable from Claude Code or Claude Desktop. No more opening browser tabs and copy-pasting context between platforms.

Prompt engineering, context, and image generation in one flow.

While developing in Claude Code, you think “I need an icon here” — and it’s generated, saved to the right directory, and referenced in your code. Claude Code understands the system design, constructs the image prompt, generates the image, and embeds it in documentation. No context is lost.

Getting Started

Set your API keys as environment variables and add the server config to Claude Desktop or Claude Code. That’s it.

See the README for setup instructions.

Note for Claude Desktop users

Due to a limitation in the Claude Desktop app, generated images cannot be displayed inline. Claude will output the file path — open it from your terminal with open <path> (macOS) or your file manager.

Links

If you try it out, I’d love to hear your feedback on X or GitHub Issues.

# Apache Data Lakehouse Weekly: March 20–27, 2026

With the Iceberg Summit less than two weeks away, the open lakehouse ecosystem spent this week in a final push of preparation, stabilization, and policy refinement. The AI contribution guidelines debate that erupted across Iceberg and Polaris last week continued drawing community input, while release engineering and summit logistics dominated the technical threads. Across all four projects, the mood is pre-conference focus — tying off loose ends before the community gathers in San Francisco on April 8–9.

Apache Iceberg

The Iceberg community spent the week in summit countdown mode. With the Iceberg Summit 2026 now less than two weeks out, logistics threads picked up as the selection committee finalized the speaker lineup. The two-day event at the Marriott Marquis in San Francisco will feature hands-on workshops, deep technical sessions, and direct access to core maintainers — the largest gathering of Iceberg practitioners yet.

On the release front, the 1.10.2 patch release discussion that Amogh Jahagirdar opened in the prior week continued to gather input from the community. The patch targets bugs discovered since 1.10.1 and aims to keep the production branch stable while contributors push forward on the 1.11.0 release cycle. With production users relying on the 1.10.x line, the community is being methodical about what gets backported versus what waits for the next minor release.

The AI contribution guidelines thread that huaxin gao opened the previous week continued to draw thoughtful responses. Holden Karau, Kevin Liu, Steve Loughran, and Sung Yun all weighed in on the challenge of maintaining code quality and Apache IP compliance as AI-assisted pull requests increase. The conversation is zeroing in on practical guardrails — disclosure requirements, review standards, and how to handle contributions where the provenance of code is unclear. This is likely to produce a formal policy before the Summit.

Péter Váry’s efficient column updates proposal for wide tables continued its steady progress. The design, which targets ML feature stores and vector databases with thousands of columns, has now been through multiple community syncs and is moving toward a written design document. The core idea — writing only updated columns to separate files and stitching them together at read time — would dramatically reduce write amplification for AI workloads. Steve Loughran’s parallel thread on benchmarking commit performance methodology is providing the measurement framework that will validate these changes.

Viktor Kessler’s Basel, Switzerland meetup announcement from last week continued generating interest, expanding Iceberg’s in-person community presence to Europe alongside the North American Summit. The combination of a major conference and grassroots meetups reflects a community that’s investing heavily in face-to-face collaboration.

Apache Polaris

Polaris continued settling into its role as an independent top-level Apache project. Jean-Baptiste Onofré circulated the project’s first board report as a TLP, covering the March 26 board meeting. This is a governance milestone — the report documents community health, development progress, and strategic direction under Polaris’s own PMC rather than the Incubator’s oversight. The report highlighted the project’s growth since graduation on February 18, including active development on credential vending expansion and the catalog federation proposal.

The catalog federation discussion that launched the previous week continued this cycle. The design would allow Polaris to federate across multiple catalog instances in multi-cloud deployments — a capability that enterprise users running Iceberg across AWS, Azure, and GCS have been requesting. Alongside federation, the web console proposal for Polaris gained traction, with contributors discussing how a browser-based UI would complement the existing CLI and REST API for catalog management.

Like Iceberg, Polaris is navigating the AI contribution guidelines question. EJ Wang’s thread continued to draw JB Onofré, Yufei Gu, and Dmitri Bourlatchkov into what’s becoming a cross-project conversation. The two communities are likely to produce coordinated — if not identical — policies, reflecting their shared contributor base and overlapping governance sensibilities. The 1.4.0 release, which will be Polaris’s first release as a graduated project, remains in active planning with credential vending for Azure and GCS backends as the headlining feature.

Apache Arrow

Arrow’s dev list this week focused on planning for the 24.0.0 release cycle and continuing the JDK 17 discussion that JB Onofré kicked off after Arrow Java 19.0.0 shipped earlier in March. David Li’s supportive response from last week was followed by additional community input on the migration timeline. If Arrow Java 20.0.0 sets JDK 17 as the minimum, it would align Arrow with Iceberg’s Java modernization trajectory — effectively raising the Java floor for the entire lakehouse stack in one coordinated move.

Nic Crane’s thread on using LLMs to aid with project maintenance continued generating discussion. Unlike the Iceberg and Polaris threads, which focus on AI-generated contributions from external submitters, Arrow’s framing centers on how maintainers themselves can use AI tools to manage the project’s growing codebase and issue backlog. Sutou Kouhei’s Map type key/item/value field names technical thread drew continued engagement from Micah Kornfield and Antoine Pitrou, working through naming consistency across language implementations. Google Summer of Code 2026 student proposals also continued to arrive, with interest in compute kernels and language bindings.

Apache Parquet

Parquet’s community held its bi-weekly sync this period and continued active technical discussions on two fronts. The File logical type proposal that emerged the previous week remained the project’s most consequential design thread. The proposal would allow Parquet files to natively represent unstructured data — images, PDFs, audio — inside columnar files. If adopted, it would expand Parquet’s role from a purely analytical format to a hybrid that can manage the unstructured data that AI/ML pipelines generate alongside the structured features they consume.

The Variant type announcement from February continued to see adoption discussion, with contributors sharing integration experiences across Spark, Trino, and Dremio. Variant brings native semi-structured data support to Parquet, eliminating the need to store JSON strings in regular columns. Combined with the File logical type proposal, Parquet is rapidly expanding its type system to handle the diverse data shapes that modern analytics and AI workloads demand. The ALP floating-point encoding spec is now through its final review, with the formal acceptance vote expected imminently.

Cross-Project Themes

The AI contribution policy conversation is the clearest cross-project theme this week. Iceberg, Polaris, and Arrow are all grappling with the same question from different angles: Iceberg and Polaris are focused on contributor-side disclosure and review standards for AI-generated code, while Arrow is exploring how maintainers can responsibly use AI for project upkeep. The fact that these conversations are happening in parallel — with many of the same people participating across lists — suggests coordinated policies will emerge. This is an open-source governance question that will define how all four projects operate in the years ahead.

The second theme is format scope expansion. Parquet’s File logical type and Variant type, Iceberg’s efficient column updates for wide ML tables, and Polaris’s catalog federation for multi-cloud environments all point in the same direction: the open lakehouse is being asked to handle workloads far beyond traditional analytics. The stack is evolving from a data warehousing alternative into a unified platform for structured analytics, semi-structured data, unstructured files, and AI/ML feature engineering — all governed through a single open catalog.

Looking Ahead

The Iceberg Summit on April 8–9 is the event to watch. Expect final speaker announcements, agenda details, and community organizing threads to accelerate over the next two weeks. On the release side, watch for the Iceberg 1.10.2 patch release vote to open, the Polaris 1.4.0 release planning to solidify, and the Parquet ALP encoding vote to close. The AI contribution guidelines threads across Iceberg and Polaris should produce actionable proposals — potentially in time for discussion at the Summit itself.

Resources & Further Learning

Get Started with Dremio

Free Downloads

Books by Alex Merced