❌

Normal view

Using Visual Studio Code’s ‘air-gapped’ AI model mode

24 June 2026 at 10:00

Microsoft has been pushing hard to make Visual Studio Code a major way to consume its AI services, mostly in the form of GitHub Copilot. GitHub Copilot’s deep integration with VS Code brings many conveniences — inline autocomplete, for instance — but it’s frustrating for those, like me, who would rather use another model provider, or even a locally hosted LLM, for those functions.

Visual Studio Code 1.122 introduced a new feature, “Use BYOK [Bring Your Own Key] without a GitHub sign-in,” that allows you to “use chat, tools, and MCP servers in air-gapped or restricted environments where GitHub sign-in isn’t possible.” More importantly, it “enables fully offline workflows with local models like Ollama.”

In other words, you can now use locally hosted LLMs for chat, tools, and Model Context Protocol servers inside Visual Studio Code. The one thing you still can’t do is use a local LLM for inline and next-edit suggestions — at least, not without additional tooling.

Choosing a model for BYOK mode

If you want to use a local LLM with VS Code’s bring-your-own-model system, the first thing you need is a way to host the model. VS Code lacks a model-hosting mechanism of its own, although it’s conceivable that a VS Code extension may offer something like that in the future. That said, hosting models is complicated enough that a dedicated app is really needed for the job.

One easy way to host models is via a product like LM Studio, a convenient GUI for standing up, serving, and managing LLMs on one’s own hardware. The model host does not have to be the same system you run VS Code on, either. It can be on a server box you control, or on a cloud instance.

The choice of model is also important. Many models are powerful but won’t run well on commodity hardware because they’re simply too big. A good rule of thumb is to choose a model that fits into existing VRAM, along with the memory needed for a sizable token context (the more, the better). Also, the model should be suited to coding and development work. Some models in this vein that fit comfortably into 8GB VRAM include:

Setting up BYOK mode in VS Code

Once you have a model up and running, you can integrate it with Visual Studio Code. If you’ve disabled VS Code’s AI features, you will need to turn them on. Make sure the setting chat.disableAIFeatures is turned off. You can find it in Settings | Chat | Miscellaneous.

Third-party language models are managed through Visual Studio Code’s language model list. Press Ctrl-Shift-P and type Manage Language Models to open the list of existing language models.

Managing VS Code's AI language model list

Managing VS Code’s AI language model list. The models available by default are only models available as external APIs, not models that run locally.

Foundry

First you will see a list of the built-in models, which are all externally hosted. To add a new model, select Add Models at the top right and select Custom Endpoint.

You’ll then get a series of prompts:

  • Group Name: This is “Custom Endpoint” by default, but you can choose any name you want. The name is strictly for organizing the model list and doesn’t affect things like model recognition or connectivity.
  • API Key: If you’ve configured LM Studio to use an API key for serving models, provide it here. If you’re hosting the model locally and you haven’t explicitly set up API keys, you can leave this blank.
  • API Type: The options here are Chat Completions, Responses, and Messages. Most of the time you’ll want to use Responses, as it’s the most general-purpose option of the three.

Once you finish providing those answers, you’ll be dropped into a modal editor for a JSON file that holds the details about the endpoint you’re configuring.

A newly created custom endpoint for a locally hosted model

A newly created custom endpoint for a locally hosted model. The ID, name, and URL still need to be defined for this model to be useful.

Foundry

You’ll need to provide a few more details by typing them into the labeled fields:

  • id: A text field that uniquely identifies this particular entry. The choice of ID is pretty much arbitrary; if you’re using only a single model, the ID could be the model name.
  • name: The name of the model that is used to identify it on the model server. In LM Studio, you can get this name by clicking on My Models in the main interface, then selecting the three-dot icon for the model in question and clicking Copy Default Identifier. For Qwen 2.5, for instance, name might be something like qwen2.5-coder-7b-instruct.
  • url: The URL to the server’s endpoint. On LM Studio, this defaults to something like http://127.0.0.1:1234/v1. The /v1 at the end is important because that endpoint is used for autodiscovery of models and their capabilities.

The other fields generally don’t need editing. Most models have tool calling functionality. If you know for a fact that the model you’re using doesn’t have vision support, then set vision to false.

Once you have these fields filled in, you can close the modal editor to save the changes. If you reload the Manage Language Models page, you’ll now see your new endpoint:

A newly created local endpoint

A newly created local endpoint. The choice of name and group is arbitrary. “Custom Endpoint” is the default name for a newly created group of endpoints.

Foundry

You should now be able to launch the chat window and use the defined model for conversation and utilities:

Conversing with the local model using VS Code's chat window

Conversing with the local model using VS Code’s chat window. Note the selected code block in the left pane that is being used as the context for the conversation.

Foundry

One current, and major, limitation of Visual Studio Code’s BYOK functionality is that it only works for chat and utility tasks. It doesn’t allow you to use a local model for inline suggestions or code completions. The only way to take advantage of local models for expanded functionality with VS Code is to use a third-party tool like Continue.

It isn’t clear if Microsoft will eventually lift this restriction. GitHub Copilot integration in VS Code is a large part of how Copilot as a service reaches its target audience. For the time being, you can certainly use third-party and local models for a significant part of your AI-assisted development work in VS Code, and you can close the functionality gap with additional tooling.

Open source grapples with agentic coding

24 June 2026 at 10:00

Unless you’ve been living under an old woodpile in your backyard, you have certainly seen how agentic coding is rocking the software development world. Things are happening fast and furious, and keeping up is practically a full-time job. 

The latest area that is catching the attention of developers is how agentic coding is affecting the open source community. The open source movement has been defending the rights of folks to use, change, and contribute to software for many years. And of course, agentic coding is starting to become part of that process.

On the one hand, maintainers of open source projects rightfully are frustrated as they become overwhelmed with pull requests of dubious quality and usefulness being submitted by coding agents. On the other hand, as David Heinemeier Hansson notes, maintainers are starting to get a little snooty about accepting AI-written code, viewing it as somehow not worthy of being included. Some organizations have explicitly banned AI-generated submissions.

I get that they don’t want AI slop overwhelming their input queues. But I think it is a huge mistake to ban AI-written code outright.

Whose code?

Before I dig deeper into that notion, it’s important to look at another issue that arises from all of this: Who actually owns the code that AI writes? 

Copyright requires that a human produce the thing being copyrighted. If you prompt Claude Code with “Write me a CMS system” and then Claude writes you a CMS system that you check into a public GitHub repository unchanged, it’s not quite clear if that code is protected by copyright. However, if you prompt Claude Code with a specification and guidelines and then you work with Claude to refine the initial result, reviewing the code and making changes as part of an iterative process, then it could be argued that a human did produce that code. But it is not at all clear-cut legally. (Please note that I am not a lawyer.)

The current thinking is that the result of accepting verbatim the output of a simple prompt is not copyrightable, and that no one actually owns the code — an interesting notion in and of itself. 

But then the ethical question comes into play. If I find a bug in an open source project, I ask GitHub Copilot to fix it, and Copilot writes a clever and effective fix, then who cares who owns the code? Should a maintainer of the project reject such a pull request just because it was AI-generated? That seems silly to me, yet it is happening today. 

Our code

There is, too, the issue of license compliance for AI-generated code. As a general rule, LLMs generate code rather than copying it. They don’t copy and paste code directly from repositories. However, there have been cases where AI-produced code has resembled open source code so closely that the claim could be made that it is a copy. If this happens with GPL code, it could be a violation of the license to use it without the receiving code base being “infected.” Open source maintainers naturally should be concerned about this happening.

In the end, an open source maintainer should care about the quality and license compliance of submissions, not how those submissions were derived. Gatekeeping based on the source of code doesn’t seem like a good path towards project success. Good code is good code, no matter where it comes from.

Agentic coding is here, and the open source community needs to realize — and embrace — that inevitability.

OpenAI rolls out AI-led push to fix open-source software flaws

23 June 2026 at 11:35

OpenAI has launched a program with cybersecurity firm Trail of Bits to use AI to find and fix vulnerabilities in widely used open-source software, as enterprises face growing risks from flaws buried deep in their software supply chains.

The initiative, called Patch the Planet, uses AI-assisted vulnerability research alongside human review to help turn security findings into tested fixes that can be disclosed through existing project channels.

Initial participants include Python, Go, cURL, Sigstore, NATS Server, aiohttp, freenginx, pyca/cryptography, and python.org. These projects support software development, networking, cryptography, and supply chain infrastructure used across a wide range of enterprise applications and services.

OpenAI said each engagement will begin with consultation with maintainers to identify where security support is most needed. Researchers will then investigate potential vulnerabilities, validate meaningful issues, develop or refine patches, support testing, and coordinate disclosure through the project’s existing channels.

Participating security researchers will use the company’s models and Codex Security to analyze code and help move fixes toward release. Trail of Bits engineers will review findings before they are sent to maintainers, a step meant to filter out false positives and duplicate reports before they add to the workload of open-source projects.

The company is also working with HackerOne and Calif to support vulnerability triage, coordinated disclosure, and additional discovery work as the program expands.

OpenAI said work under the program has already identified “hundreds of security issues and merged dozens of patches, with many more still undergoing coordinated disclosure.”

The work has also produced tools for fuzzing, historical CVE analysis, and differential testing, along with systems to filter inaccurate findings before patches are generated, OpenAI added.

The focus on open-source security follows incidents such as Log4Shell and the XZ Utils backdoor, which showed how quickly a flaw in a shared component can move through enterprise software.

Analysts said Patch the Planet changes the risk equation only if enterprises treat AI-assisted vulnerability research as an input to a broader software supply chain risk program, not as a substitute for one.

“The key shift is speed: AI-assisted research can help find, validate, patch, test, and document issues faster, while human reviewers reduce false positives before maintainers are burdened,” said Biswajeet Mahapatra, principal analyst at Forrester. “But the dependency on scarce expertise does not go away; it moves to triage, exploitability judgment, patch safety, disclosure timing, and production rollout.”

Guardrails before deployment

CISOs should put governance controls in place before using AI-assisted vulnerability research in enterprise security pipelines, to ensure unverified findings do not overwhelm engineering teams, said Devashri Datta, an open-source cybersecurity architect.

“CISOs should demand a Safety Relevance Layer in their risk modeling, a structured framework that requires every AI-generated finding to pass automated verification, including dynamic proof-of-concept validation and strong false-positive filtering, before it reaches a human analyst,” Datta said.

Those controls should also cover disclosure, particularly when AI tools identify flaws in third-party open-source components that the enterprise does not control, Datta said. Organizations need predefined escalation paths, notification timelines, and role assignments that take effect once a confirmed issue is found in an external dependency.

“Ad hoc disclosure in an AI-accelerated environment isn’t just a process gap; it’s a liability,” Datta said. “Trusting AI in the production pipeline requires verifiable auditability: organizations must be able to trace why the AI flagged a line of code, how it validated the exploit, and how it determined that the patch would not break downstream production systems.”

Continuous exposure reduction

AI-assisted vulnerability research could force enterprises to move away from periodic patching cycles and toward more continuous risk assessment, analysts said. If variant analysis and differential testing can be compressed from weeks to days, security teams may need faster ways to decide which findings matter most in their own environments.

That shift also means enterprises can no longer rely only on generic CVSS scores to prioritize remediation, Datta said. Findings will need to be assessed against the affected system, its business role, runtime exposure and the likelihood that a flaw can be exploited.

“We have to move toward context-aware, safety-critical prioritization,” Datta said. “Enterprise SBOM and VEX programs must evolve from passive compliance spreadsheets into live, machine-readable data feeds. For AI-assisted pipelines specifically, that means extending the VEX model to cover AI-introduced risk surfaces.”

Mahapatra said vulnerability management programs will also need to become more closely tied to software ownership, supplier response, and business impact.

“Security teams should move from periodic vulnerability handling to continuous exposure reduction,” Mahapatra said.

That means SBOMs should be treated as live inventories tied to runtime exposure and supplier response, rather than static compliance documents. Patch decisions should also account for asset criticality, exploitability, compensating controls, and business impact.

The article originally appeared on CSO.

How fuzzy APIs are remaking the web

23 June 2026 at 10:00

For nearly as long as the web has existed, web development has wrestled mightily with the right way to connect components over the network. This is the question of the remote API. It influences every aspect of the software we build. We sort of arrived at a tolerable compromise with JSON APIs. While these have their limitations, you have to appreciate their underlying simplicity.

But the advent of AI-enabled endpoints that can mediate intent is changing the basic workings of the internet. This change is gradually reawakening an old dream, the service-oriented architecture (SOA). This time around, with luck, we’ll finally gain the flexible, discoverable, and maintainable automated service discovery we’ve longed for. Fingers crossed.

Why old-school SOA failed

Let’s call this burgeoning influence of AI on web architecture SOA 2.0.

To understand why SOA 2.0 is different from SOA 1.0, we have to remember the trauma of the 2000s. (This may be painful but also cathartic.) The original dream of SOA was beautiful: a world where disparate business services—inventory, billing, shipping, you name it—could automatically discover each other, understand capabilities, and orchestrate complex tasks without human intervention.

To achieve this, we built a monument to complexity. We had SOAP (Simple Object Access Protocol) for messaging, WSDL (Web Services Description Language) to define contracts, and UDDI registries for service discovery. At the center of it all sat the Enterprise Service Bus (ESB), a massive piece of middleware that was supposed to route everything gracefully, seamlessly. In case you young’uns are confused, that is all based on XML.

By the time you were done understanding the infrastructure well enough to know how to do something, you had forgotten what you set out to do.

It failed. It was egregiously heavy. Just to do some simple thing like create a “New Item” endpoint, you immediately had to begin scaling a wall of rigid definitions.

Because computers historically required absolute, deterministic perfection, if a single XML tag in a SOAP envelope was missing, or if a service updated its WSDL without every client re-generating its stubs, the entire multi-million-dollar pipeline would violently unravel. Some of us may be familiar with a similar challenge in containerized microservices (like Kubernates), where trying to determine where in the mesh a problem originated is… awkward.

Classic SOA was a house of cards, too brittle to survive the fuzzy reality of the internet.

The typical JSON API of today is a reaction against SOA. (It may be an overreaction.) We abandoned SOA for the relative simplicity of REST, giving up on the dream of autonomous service orchestration in exchange for manual integrations that just work.

The new intention-to-execution middleware

A sea change is already happening with app-level architecture. 

The effect of AI endpoints in an app’s service profile goes beyond just a new capability. It changes how the rest of the services work together. The overall effect is something like the app gaining an understanding of itself, and what it can do. This is not dissimilar to what WSDL was supposed to accomplish. But instead of a hard-coded descriptor, where some person had to keep what was available and what was described in sync, you now have a layer that can accept dynamically produced descriptors and unite them with fuzzy user intention and produce meaningful action.

You tie in AI endpoints to bridge between what the user is trying to accomplish, with the various strict capabilities available. These capabilities may exist within the app at the back end, at the front end, or at another service layer. The main thing is that there is a flexible AI layer that mitigates the need to hard-code the links between services.

In classic SOA, the contract was a rigid, unforgiving WSDL document. In modern common practice, the contract is a strongly coupled RESTful endpoint. In SOA 2.0, the contract has a hitherto unknown degree of flexibility, thanks to the natural language capabilities of an LLM.

When a user or a system expresses an intent—say, “Provision a new staging environment for the billing service”—the AI middleware doesn’t look for a hard-coded, point-to-point integration. Instead, it digests the intent and performs semantic routing, consulting a registry and selecting the appropriate tools. That registry, rather than a heavy UDDI, might be a vector database of available internal API endpoints, or a collection of available functions.

Modern LLMs equipped with function-calling capabilities act as the ultimate dynamic orchestrators. They read the JSON schema of a target REST API, understand its parameters, and dynamically map the user’s fuzzy, unstructured intent into a perfectly formatted JSON payload. If a field is missing, the LLM can either infer it from context or pause execution to ask the user for clarification.

The brittleness of SOA 1.0 is replaced by a shock absorber. If the target API changes a parameter name from customerID to clientId, the AI middleware can read the updated schema and adjust its mapping on the fly. No client code needs to be recompiled. No stubs need to be regenerated. The multi-million-dollar pipeline survives.

When software becomes smart

These are not just abstract ideas. I recently did my taxes, using a popular mainstream service that I will not name. I had several unusual and grumpy areas to deal with, including the new crypto regulations. It was not pretty.

But what I was most struck by was how dumb the software was, compared to the AI chatbot I was using to help guide me. I wanted to be able to tell the (stupid) software what I was trying to do. Such as “Carry my NOL from last year!” Or “I don’t know if I need a schedule K, you tell me!”

I don’t want another chatbot. I mean, I already have a good chatbot. I want the application to be well-integrated with AI services that understand the app, understand my current situation within the app, and meet me at the level of intent, applying the lessons learned by others who have used the same tools.

This kind of targeted, intelligent leveling up of intention is, from all I can see, the next stage of software development, and it is going to be massive.

Latency, non-determinism, and other challenges

We are trading the deterministic brittleness of classic SOA for the probabilistic fuzziness of SOA 2.0. And that trade is going to be demanded with ever more insistence by users. But it comes with a new set of trade-offs.

First, there is the latency tax. The old enterprise service bus was heavy to configure, but at run time, the messaging was just routed XML. Injecting an LLM into the critical path of an application adds hundreds of milliseconds, if not seconds, of latency. For asynchronous tasks or complex orchestrations, this is a welcome trade-off. For real-time, high-throughput microservices, it is a deal-breaker.

Second, there is the problem of non-determinism. We spent decades training ourselves (and our systems) to expect that given input A, a system will always produce output B. That deterministic equation was our bottom line faith. The intent layer doesn’t work that way. An LLM might route a request beautifully 99 times, then hallucinate a parameter on the 100th. Or it might choose an entirely different execution path based on a subtle shift in the user’s phrasing.

A third fly in the ointment is the so-called non-functional requirements, or NFRs. These are your pesky sidebar issues that refuse to be ignored, like security and reliability. 

Security concerns are magnified by model capabilities like function calling (or “function passing”). If you pair a user’s desires with what the AI can do, and you then let the AI decide, what happens next is clearly an act of faith unless guardrails are put in place. These guardrails must go beyond typical web security (i.e., make sure important function calls are hardened on the server, not exposed on the client) and must be internalized by the AI or (more likely) imposed from a layer outside the AI. There are a number of ways to do this, varying in degree of power and complexity. 

We certainly will continue to use standard practices (like RBAC and SSO) to enforce authentication. We will continue to implement standard authorization techniques (like OAUTH and JWT). But we will bring these to bear in the context of that intent layer and its capabilities.

Reliability is another challenge. For example, I recently hit a snag with Google’s Imagen API. Everything was working beautifully, then suddenly, some of the images stopped generating. There were no errors in the client or server logs; however, there were 500 errors in the network. Upon deeper examination, the prompting had morphed (between app context and user content) to include what the Imagen API rules deemed to be dangerous content. This was not obviously flagged prompting. It was fairly pedestrian creative writing, along the lines of “A dark, surreal, and glitchy cyberpunk landscape with menacing figures….” That kind of thing.

These are some of the ways that even simple, direct use of LLM APIs can surprise you. The question I am mulling is, what will be the unexpected outcomes on software writ large?

Dawn of a probabilistic web

Since its inception, the unpredictable, probabilistic nature of the internet came primarily from the humans using it (and background radiation flipping transistors, network failures, geopolitical effects on the ground, and the like). But AI-mediated APIs introduce an intentional, semantically controlled form of probability.

As developers, we will naturally discover the techniques that make consuming AI endpoints more effective. Here I am thinking about practices like structured responses and function calling. But the larger question is, what will the nature of software become?

In a world of binary states, strict protocols, and rigid URIs, if you send a GET request to a specific endpoint, you expect an exact, predictable response. We have spent the last 40 years treating the web like a vast, unimaginably complex state machine.

But as LLM-mediated APIs permeate our architecture with stochastics, the very fabric of the internet begins to change. By injecting AI into the routing and discovery layers, we are introducing a massive dose of probability into the foundation of our networks. When a request is no longer a hard-coded URI call but a natural language intent parsed by an LLM, the connection between node A and node B ceases to be a rigid wire. It becomes a weighted probability.

In essence, we are remaking the internet to mirror the architecture of the AI models we are deploying. Just as a neural network relies on the probabilistic firing of synapses rather than deterministic if/then statements, the next iteration of the web will rely on fluid, semantic discovery. Services won’t just “link” to each other; they will gravitate toward one another based on the conceptual proximity of their capabilities within a shared latent space.

This alters the character of software engineering. We lose (the illusion) of being entirely in control. Its strange paradox is that engineering using explicitly probabilistic components may make for a more resilient system. There is a longstanding debate about the best metaphor for software development. For the longest time, the construction of a building always seemed to be an apt analogy, or perhaps the mechanics of a vehicle. But these days, the gardening or cultivation metaphor is looking ever more relevant.

Despite the challenges posed by inserting AI in the stack, we are finally circling back to the original promise of the early 2000s. This time, fingers crossed, we are equipped with the right tools for the job.

We tried to build autonomous service discovery using rigid logic and deterministic XML, and it collapsed under its own weight. Now, we are building it with neural networks that understand the “intent” behind the integration. We are still building middleware, but instead of an enterprise service bus, we are building an enterprise reasoning bus.

The era of manually hard-coding every integration between every microservice may be coming to a close.

The missing layer in enterprise agentic AI

23 June 2026 at 10:00

In the past year, the enterprise AI ecosystem has gained enormous capability and zero consensus.

Developers now have a remarkable set of tools for building AI agents: OpenAI’s frameworks, Anthropic’s Claude tooling, LangChain, LangGraph, CrewAI, Microsoft AutoGen, and a growing list of alternatives. Each promises to coordinate reasoning loops, manage multi-step task execution, and connect agents to tools and APIs. For experimentation, the progress has been substantial. Teams can now assemble sophisticated agent workflows in days that would have taken months two years ago.

But I’ve watched this pattern before. In over two decades of building and selling distributed systems platforms, I’ve seen the same dynamic play out across nearly every major infrastructure shift: the tools for consuming a new capability arrive before the infrastructure for governing it does. The gap that emerges isn’t immediately obvious in development environments. It becomes obvious in production.

That’s exactly where enterprise AI stands today.

What agent frameworks don’t handle

Modern agent frameworks are fundamentally coordination systems. They determine what a system should do: which tools to call, how to sequence tasks, how to delegate work across agents. That’s hard work, and they’ve gotten quite good at it.

What they rarely address is where those tasks are allowed to run, and under what conditions.

Take a seemingly simple workflow: summarize customer support transcripts using an LLM. In a development environment, the implementation is clean. The agent calls a model API, passes the transcript, and returns a summary. In production at an enterprise, the same request may involve a dataset that can’t cross a specific geographic boundary, a model that isn’t approved for regulated data, and an audit requirement that demands a traceable record of what happened.

Those aren’t planning problems the agent framework was designed to solve. They’re execution governance problems. Most frameworks quietly assume they’re handled somewhere else in the stack. In many enterprise environments, they’re not handled at all. Gartner predicts more than 40% of agentic AI projects will be canceled by the end of 2027, citing inadequate risk controls as a primary driver of failure—a number that reflects exactly this gap.

What the missing layer actually does

Addressing these governance problems requires an additional layer between agent logic and execution: one that evaluates every agent action against policies governing where data can reside, which models may process it, who authorized the request, and how the action fits within the organizational context. The agent framework determines what the system should do. The orchestration layer determines whether and where it’s allowed to happen. Keeping those responsibilities separate allows both layers to evolve independently. It also means you can adopt new agent frameworks without rebuilding your governance model from scratch.

This separation will feel familiar to anyone who has worked through the Kubernetes era. Kubernetes doesn’t care what’s inside your container. It finds capacity, allocates resources, and ensures things run. The orchestration layer for agentic AI plays an analogous role: it doesn’t care which agent framework generated the request. It enforces the conditions under which that request can execute.

Richer authorization models

Traditional enterprise access control is built around a simple question: can user X access resource Y? That’s insufficient for autonomous agents.

A realistic authorization decision for an agent request might look more like this:

request = {
    "agent": "support-summary-agent",
    "task": "summarize",
    "dataset": "customer_support_logs",
    "model": "external_llm_api",
    "delegated_by": "user_4821"
}

policy = evaluate_policy(request)

if policy.allowed:
    route_to_execution(policy.execution_environment)
else:
    raise AuthorizationError(policy.reason)

The policy engine here evaluates dataset classification, model approval status, geographic processing rules, and the delegation chain that initiated the request. That might mean redirecting the task to an internal inference cluster instead of a public API endpoint, or blocking the request if no compliant execution environment exists. From the agent’s perspective, the task still executes. The orchestration layer ensures it runs in an environment that satisfies enterprise policy.

Why ontologies are load-bearing infrastructure

For the orchestration layer to make good decisions, it needs to do more than label data. It needs to understand how the entities involved in a request relate to each other, and reason over those relationships to determine what’s allowed.

Consider the customer support transcript example again. Metadata tells you the dataset contains PII (personally identifiable information). An ontology lets the system reason across a connected chain: the task operates on a dataset containing personal data; that data is governed by GDPR; the organization’s policy requires processing within an approved EU environment; the selected model runs outside that boundary. From those four connected facts, the orchestration layer can infer the request must be rerouted or blocked. The system reasoned over the relationships rather than matching against a hardcoded rule tied to a specific dataset.

This is what makes policy enforcement, execution routing, data locality, and audit decisions computable at runtime. An ontology can be built around virtually any entity-relationship set the enterprise needs to govern: datasets, models, agents, users, regulations, tasks, environments. The relationships that matter are the ones that drive the decisions the governance layer needs to make. Access control lists can restrict who touches a resource, but they can’t reason across a connected set of entities. That reasoning is what the orchestration layer depends on.

Decision provenance as a first-class requirement

Enterprise systems also require auditability. When automated agents trigger actions across multiple systems, organizations must be able to reconstruct the decision path that produced the outcome. Compliance depends on it. So does incident response and basic operational trust.

An orchestration layer generates records describing the initiating identity, the agent, the model, the data sources, the policies evaluated during authorization, and virtually anything else the organization chooses to capture in its ontology. That chain of custody allows teams to investigate incidents and validate compliance without treating production AI systems as operational black boxes.

Regulators and auditors are no longer satisfied with knowing what an AI system was designed to do. They want a factual record of what it did in a specific instance, under what authorization, and with what effect—something dashboards can’t provide, but a well-designed orchestration layer can. The EU AI Act makes this explicit: under Article 12 and Article 17, high-risk AI systems must maintain documentation that makes decisions traceable and auditable, with records sufficient to support investigation after the fact.

Where this leaves enterprise teams

Agent frameworks will keep improving. The coordination problems they solve are real, and the ecosystem will continue to mature. But the architectural challenge for enterprises has shifted. It’s no longer primarily about coordinating agents. It’s about governing how those agents interact with real infrastructure, real data, and real compliance obligations.

The patterns for doing that exist today: contextual authorization, data locality enforcement, ontology-aware policy evaluation, decision provenance. What most organizations are missing is the recognition that these capabilities belong in a distinct layer that operates independently of whichever agent framework sits above it. Build that layer, and the rest becomes manageable.

—

New Tech Forum provides a venue for technology leaders—including vendors and other outside contributors—to explore and discuss emerging enterprise technology in unprecedented depth and breadth. The selection is subjective, based on our pick of the technologies we believe to be important and of greatest interest to InfoWorld readers. InfoWorld does not accept marketing collateral for publication and reserves the right to edit all contributed content. Send all inquiries to doug_dineley@foundryco.com.

GitHub Actions hardens checkout security to block ‘pwn request’ attacks

23 June 2026 at 00:43

Stung by a surge in cyberattacks that have run amok in developer environments, GitHub has strengthened the security of actions/checkout to block ‘pwn request’ attacks that exploit insecure use of the pull_request_target workflow trigger to run an attacker’s code with the workflow’s full privileges.

Announced on June 18, actions/checkout v7 now automatically blocks and fails workflows when used inside pull_request_target or workflow_run events when attempting to fetch unreviewed fork pull request code.

From now on, the only away around these checks will be for developers to implement an opt out by adding an explicit allow-unsafe-pr-checkout to actions/checkout, GitHub said in its V7 changelog.

The change signals the beginning of a new ‘secure by default’ era in which security will be defined by the GitHub system rather than being left to discretion of developers. As part of that effort, on July 16, the new defaults will be backported to all supported major versions.

“Workflows pinned to a floating major tag (e.g., actions/checkout@v4) will automatically pick up the change. Workflows pinned to a specific SHA, minor, or patch version aren’t affected by the backport and will need to upgrade using Dependabot or through established upgrade processes,” GitHub explained.

However, because pwn request attacks can happen in other ways, “further hardening of additional events may be explored in future releases,” the changelog added.

Blind spot

If there’s a criticism that can be levelled at GitHub over this, it’s that it has taken so long to address a weakness that’s been known about for years.

The issue is with GitHub Actions, which allows triggers to run workflows, including pull_request, which processes third-party forks without giving access to secrets such as API keys, service tokens, and credentials. The downside is that this restriction prevents some automations from working, which is why developers turn to an alternative trigger, pull_request_target, which grants the required access.

At some point, attackers realized that where pull_request_target was configured carelessly with actions/checkout to pull in untrusted fork code, it offered a back door into repositories and their secrets.

In other words, the weakness in pull_request_target isn’t the trigger itself, which is legitimate and secure when correctly used, but in its  incorrect use. As GitHub’s changelog puts it: “Checking out the head of an unreviewed pull request from a fork inside one of these workflows typically lets attacker-controlled code execute with the workflow’s full privileges.”

The arrival of actions/checkout v7, however, should make this harder, automatically blocking risky workflows regardless of their configuration.

Unfortunately, a lot of damage has already been done. Open source repositories have recently come under sustained attacks from the TeamPCP hacking group, using a variety of techniques, including pwn requests.

A notable example was its attack last month, which compromised 170 node package manager (npm) packages, including the TanStack Router ecosystem, thanks to a pwn request exploit. Embarrassingly, in a separate incident not involving a pwn request, GitHub itself was breached and the attackers exfiltrated source code from around 3,800 of the company’s internal repositories.

Better late than never, GitHub has sprung into action, plotting a series of security reforms on the platform, including, earlier this month, limiting automatic install script execution in npm.

Why open infrastructure will define the AI era

22 June 2026 at 10:00

A new form of vendor lock-in is here. And it’s not proprietary languages or rigid enterprise software suites — it’s something more fundamental. It’s the very thing that writes the code.

JetBrains Research found that 74% of developers worldwide use AI tools. Claude Code, available only since May 2025, is now the most popular AI coding tool, followed by Gemini Code Assist and GitHub Copilot, according to Jellyfish’s 2026 State of Engineering Management Report.

The latter study also found that 91% of developers say their productivity has increased in the past 12 months. As coding output expectations are rewritten daily, the engineering world is becoming heavily reliant on paid external AI services.

Gartner predicts that by 2028 spending on AI coding tokens could exceed developer salaries. Yet, tokenmaxxing while vibe coding through a vendor’s cloud-based API feels like a far cry from the open foundations of free programming languages and open models, which many of today’s AI platforms now abstract.

“Open infrastructure will be the backbone of the AI era,” says Peter Farkas, CEO of Percona, a provider of open-source database solutions. “Right now, too many companies are building their entire AI strategy on top of proprietary platforms because the convenience is seductive.”

“It’s ‘three clicks’ to stand up a database or an AI service in a hyperscaler, and that convenience blinds people to the lock-in they’re signing up for,” he adds. “As AI workloads mature, organizations will realize that depending on one vendor for their data, models, runtime, and pricing is not a strategy.”

AI-assisted coding is democratizing software engineering for non-engineers and accelerating top performers. But if teams are always working within the confines of how one platform thinks the world should work, it could create locked-in toolsets at scale. And as AI platform costs rise, a fundamental question arises: will software developers consume AI on their own terms, or on someone else’s?

There’s a strong case that the long-term winners in tech will be built on open-source standards and foundations, similar to the history of cloud-native computing and the internet itself.

“Open always wins,” says Brian Alvey, CTO at WordPress VIP, a managed WordPress hosting platform. “Not because it’s a fancy ideology, but because it gives you total freedom to adapt, evolve, and stay in control.”

Open infrastructure avoids a future where developers perpetually rent. “For AI to be useful to people at large, it can’t be something you’re paying rent for the rest of your life,” says Manik Surtani, CTO and co-founder of the Agentic AI Foundation (AAIF), a vendor-neutral home for open-source agentic AI technologies. “And it can’t be concentrated in one particular corporation or a small handful of corporations, because we know how that goes.”

Pricey, closed, proprietary AI

AI development today is traveling two parallel paths. On one path, open-source AI is thriving and fueling tremendous growth in the number and variety of AI models and tools. Just take the thousands of open-weight models on HuggingFace, the community around the OpenClaw AI agent, or the many academic institutions publishing new breakthroughs.

“Open-source models and tooling are hot on the heels of state-of-the-art, with interesting and boundary-pushing work being shared by labs and researchers across the world,” says Austin Parker, director of AI strategy at Honeycomb, an observability platform provider, citing frontier open-source models like Mistral, DeepSeek, and Ai2’s OLMo as examples.

Others agree. “There’s unprecedented openness at the model and tooling layer, with open-source models, frameworks, and orchestration advancing at remarkable speed,” says Mark Collier, general manager of AI and infrastructure at the Linux Foundation.

On the other path, we’re seeing heavy reliance on proprietary AI systems controlled by Anthropic, Cursor, Google, Microsoft, OpenAI, and others. As Collier says, “Many platforms are wrapping those open components in closed, opinionated interfaces that trade short-term speed for long-term constraints.”

Open source and the AI tooling market don’t always mix well. LangChain’s Open Agent Platform, for instance, was open-sourced to much fanfare in 2025, but by 2026 had been deprecated, with the repository now recommending fully managed alternatives.

For Roman Shaposhnik, co-founder and CTO of Ainekko, provider of an open-source, composable AI stack, the current AI platform landscape is reminiscent of low-code and no-code platforms, which promised democratization of software development but often failed to deliver, becoming synonymous with platform lock-in and inflexibility.

“Honestly, it feels familiar,” Shaposhnik says. “We have incredibly powerful AI tools right now, but most of them come bundled as tightly controlled platforms.” This is a risk for AI, he says, because the infrastructure, models, and hardware are tightly coupled. “If those layers are closed, you lose flexibility fast.”

Some abstractions that sit on top of models, like routing and agent frameworks, tend to be tightly coupled and optimized for certain models. Other platforms take the walled garden concept quite literally. Anthropic, for instance, has repeatedly made headlines for blocking access to its Claude models over vague policy violations. The company recently shut off competitor xAI’s use and stonewalled OpenCode, drawing community backlash.

Moves toward increasingly closed systems don’t bode well for an AI economy already built on shaky economics. As Vikram Srivats, head of product experience at WaveMaker, provider of an agentic application development platform, adds, “Given the unit economics of AI tooling and pace of accelerated change to keep up, it seems obvious that some will evolve to more of a closed system to be able to monetize and gain ROI.”

Why openness matters in the AI era

Reliance on proprietary AI platforms can create long-term operational dependencies. As systems become less interoperable, organizations may be forced to standardize on a single stack across data pipelines, models, and decision logic, says the Linux Foundation’s Collier.

“As infrastructure consolidates, enterprises become more exposed when platforms change direction, raise prices, or fall behind technically,” he says. “If you can’t change platforms without re-architecting your AI systems, you’ve already given up too much control.”

“When you build on someone else’s platform, you have to live by their rules and those rules always change,” adds WordPress VIP’s Alvey. “We’ve all seen this before, businesses wasting time and money building to serve Google, Facebook, YouTube, and the App Store, instead of building to serve their customers.”

Platform lock-in can also create direct business risk. As Ainekko’s Shaposhnik says, “It usually shows up as higher costs, fragile systems, and growing risk when it’s time to change direction.”

At Ainekko, an internal group called the AI Plumbers focuses on back-end AI infrastructure like inference, scheduling, memory, and hardware integration. “Their view is simple,” says Shaposhnik. “If those layers are closed, everything above them becomes fragile.”

Open standards, interfaces, and infrastructure provide a necessary hedge against closed systems to prevent this sort of fragility. “In the AI era, open infrastructure gives enterprises control, portability, and choice at exactly the time they need it most,” says Percona’s Farkas.

It can cost upwards of $100,000 to migrate enterprise software, according to Cloudaware, making portability a major enterprise concern. From this perspective, procuring closed systems can become a costly architectural dependency.

Others argue that openness is a critical hedge against vendor concentration risks at large, especially if AI replaces human labor en masse. “If all of that economic value is now being concentrated in the hands of one or two companies,” says the AAIF’s Surtani, “that’s an order of magnitude bigger problem than we’ve seen in any other wave of computing.”

Instead, open foundations allow adaptability to evolving conditions so enterprises can swap out models, agents, data, hardware, and orchestration, as needed. “Open standards let those components change independently without breaking the system,” says Collier. 

Openness can also help future-proof businesses against economic upheaval. “Open everything will help build a cushion for businesses and users to survive and thrive after the almost-certain correction in the current hype cycle,” says WaveMaker’s Srivats.

Momentum toward open AI infrastructure

At the industry level, momentum toward open AI infrastructure is growing. The establishment of the Agentic AI Foundation, Anthropic’s donation of Model Context Protocol (MCP), and Block’s donation of its Goose agent are significant ecosystem-wide moves toward openness. Other advances include the donation of llm-d, a Kubernetes framework for LLM inference, to the Cloud Native Computing Foundation (CNCF).

For Parker, donations like this help ensure long-term support and care. “Open standards aren’t just the foundation of the internet, they’re the foundation of the AI space,” he says. “I predict that we’ll see these practices continue, especially as enterprise adoption increases in earnest,” he adds.

Still, some question whether this level of stewardship is enough for a rapidly evolving ecosystem. “The internet benefited early on from groups that helped keep vendors aligned,” says Shaposhnik. “In AI infrastructure, we don’t really have that yet.”

“All of us open source veterans are hopeful,” he says, “but we also need to adapt to this new reality in what we do regarding AI infrastructure.”

Beyond industry governing bodies, companies themselves are also spearheading open AI initiatives. Warp, an agentic development environment, recently went open source amid closed-source rivals. Arcade.dev, meanwhile, is pushing an open-source Agent Library for agentic memory.

Where openness matters most in the AI stack

While AI infrastructure can be open in many ways, a few layers stand out as especially important. First is the openness of the model itself. “Open-source models must be the foundation of future trust and value,” says WaveMaker’s Srivats.

“The forms of open infrastructure that reduce integration friction and accelerate adoption stand out,” adds Neeraj Abhyankar, VP of data and AI at R Systems, a global digital solutions provider. For him, open model representation formats, open orchestration and execution layers, open agentic protocols, and open governance and metadata standards are all essential for enterprise flexibility.

Others place more value on the connective tissue between AI components. “The most important forms of open infrastructure are the ones that connect systems together,” says Collier. “That includes open APIs, metadata standards, identity and policy frameworks, and protocols for how models and agents communicate.” 

Arguably, MCP has become the connective tissue between AI agents and the broader API ecosystem. “If we get MCP right we unlock the same level of interoperability between entities on the web and models driving them as we came to enjoy during the Web 2.0 era and the API-first boom,” says Shaposhnik. “If we don’t we risk massive proprietary lock-ins.”

Parker agrees that open protocols will underlie future AI progress. “We’ll see continued development and progress on AI agents which will rely on protocols like MCP and ACP [Agent Client Protocol] to interoperate with various clients and each other,” he says. Yet a gap remains around API conventions for models. “It would be nice if we could get a commitment from model providers to use a standard here.”

For the AAIF’s Surtani, opening up the protocol layer is the most important aspect. “I think it’s really important for interoperability, for choice,” he says. “It means you can bring your own agent, you can bring your own framework, you can bring your own harness, and pick what model you want.”

Open standards may also play a significant role within inference architecture. “As AI expands to the edge, developers need visibility into how models run, how memory is used, and how performance scales,” says Shaposhnik. Open systems could make it easier to optimize, debug, and adapt while helping enterprises avoid observability fragmentation.

Lastly, cloud-native architectural standards are a key ingredient for open AI infrastructure. “We’re seeing Kubernetes become the missing link for people who want the hyperscaler-style convenience without hyperscaler lock-in,” says Percona’s Farkas. For him, Kubernetes has become the de facto hybrid enterprise deployment option for data, workloads, and AI components.

History repeats itself

The 2026 State of Open Source Report found avoiding vendor lock-in to be the primary driver of open source adoption. But beyond being a strategic decision for a single company, open infrastructure provides a layer for entire industries to be built upon.

Arguably, the internet itself is evidence of this, where groups like the IETF and the IEEE were instrumental in defining the fundamental protocols. “Without open protocols we would’ve been in telco hell and without phenomenons like Google or Facebook,” says Shaposhnik.

Or, take the history of Linux as a parallel. “Linux became the default operating system because it offered a common, vendor-neutral foundation that everyone could build on,” says Collier. “In the AI era, open infrastructure will define the layers that organizations rely on for long-term continuity.”

At the infrastructure level, open standards have repeatedly underpinned major platform shifts, from Docker to Kubernetes. The question now is whether AI will develop a similarly durable standards layer.

For Parker, it’s too early to say, but the current growth of AI mirrors the early cloud. “Remember that it took many years before we saw the development and popularization of the open source cloud-native ecosystem,” he says. “I think it would be a mistake to extrapolate from the current trajectory towards a closed, proprietary future.”

Others agree the future must be rooted in openness. “I see open infrastructure becoming the foundation of enterprise AI,” says R Systems’s Abhyankar. “As systems become more distributed and agent‑driven, closed ecosystems simply won’t scale.”

The groundwork is being laid through open agentic protocols, open frameworks, and industry support intended to reduce fragmentation around proprietary standards.

“Ironically, the AI movement has mostly seemed to learn from the mistakes of the past and is starting off on a more open foot,” says Parker. “Over time, I believe we’ll see innovation and openness thrive.”

Researchers grow a hypothesis tree for AI coding agents

19 June 2026 at 23:16

AI coding agents can tend to isolate research, running experiments and generating ideas that are then forgotten when context windows reset. This can waste tokens, as models then repeat the same mistakes and hit the same dead ends.

But new research argues that it’s not the model itself, but the overarching ‘tree,’ that needs tweaking. To that end, data scientists from the Gaoling School of Artificial Intelligence, Renmin University of China, and Microsoft Research have introduced Arbor, a “persistent hypothesis tree” that helps agents remember and refine learnings over long research sessions.

A long-lived coordinator manages research strategy across the tree, while short-lived executors spin up isolated worktrees to test different hypotheses. As results come back, the tree updates, narrowing and refining throughout experimentation.

In practical tests, this technique delivered more than two-fold performance gains over standard AI coding agents across real-world engineering tasks, for the same budget.

This is because, said Mahmoud Ramin, a research director at Info-Tech Research Group, “Arbor accumulates information over time and allows agents to build upon prior discoveries just as humans do, through learning, adaptation, and eventually building upon what they have learned in the past.”

How Arbor grows

Arbor’s builders argued that longer execution on its own does not guarantee research progress. The challenge is maintaining a state that turns many individual attempts into “cumulative hypothesis refinement.”

Further, progress should not depend on human overseers regularly stepping in to dictate logical next steps or interpret the meaning of previous trials, they noted. To be truly autonomous, agentic research frameworks must maintain connections between experiments, data, results, and failures over time.

Arbor is built to fulfill three system requirements. First, it must be able to branch as sub-trees test out competing hypotheses that are all potentially plausible. At the same time, unrestricted branching can degenerate the whole framework, so that must be controlled to remain organized. The researchers call this “branching with coherence.”

Second, the infrastructure must separate local execution from overarching strategy. Testing out single hypotheses requires short-horizon tasks like editing, debugging, and evaluation. But these should not “obscure” the larger tree making decisions based on evidence gathered across the whole run.

Finally, the systems must be able to distinguish exploratory improvement from verified improvement. This prevents AI from overfitting during trial-and-error instead of iteratively learning from underlying patterns.

Persistence is at the core; the tree links hypotheses and ideas, the code or configuration artifacts used to test them, experimental evidence (results, metrics), and distilled insights (such as “this data filter helped, but this learning rate scheduler didn’t”).

Once a project kicks off, shorter-execution work trees run code, log their work, and collect metrics. The long-lived coordinator above them serves as the de-facto head of research, keeping an eye on the process, updating nodes, selecting “promising leaves,” pruning or merging branches, propagating reusable lessons, and deciding which hypotheses to pursue next.

“The tree therefore acts as the operational research state of the system,” Arbor’s builders wrote. “It is simultaneously the search frontier, the memory of past attempts, and the audit trail for verified artifact improvement.”

Outperforming Codex and Claude on new data

To test how well this process works, the researchers evaluated Arbor in an autonomous optimization (AO) setting: the agent was given an initial research artifact (a data pipeline, harness, or training script) and was tasked with improving its “held-out performance” through iterative experimentation, without human steering. Held-out performance is a machine learning (ML) metric that evaluates how well models are able to generalize on data they haven’t seen before.

The tree-based architecture was tested on several real research tasks across model training (its ability to improve training recipes and hyperparameters), harness engineering (how well it can upgrade evaluation or training harnesses), and data synthesis (its capacity to generate better data for training or evals).

Ultimately, Arbor outperformed the average held-out gains of Codex and Claude Code by 2.5x, for the same resource budget.

The takeaway, said the researchers: Keeping a structured, evolving hypothesis tree yields greater performance improvements than running the same models as ‘memoryless’ coding agents.

Arbor’s most innovative feature is its ability to maintain the agent’s memory and retain relevant data from prior attempts and hypotheses, Info-Tech’s Ramin pointed out, and, he said, “the next step for autonomous agents may be accumulating evidence over time.”

However, this does raise concerns about the auditability of robust research environments at a large scale, he noted. “As autonomous agents become more capable of performing work without human operators overseeing them, enterprises will need transparency into how and/or why an agent took a specific action or reached a certain conclusion.”

Write cleaner and faster Python code

19 June 2026 at 10:00

Meta’s long-awaited Pyrefly linter is out in a 1.0 version, and the forthcoming Python 3.15 has a super-efficient sampling profiler. Plus we have a comprehensive rundown of Python’s indispensable virtual environments — and a warning about a novel breed of malware that exploits Python’s package ecosystem.

Top picks for Python readers on InfoWorld

How to use virtual environments in Python
Isolate and protect your Python projects from each other, and empower them to do more, with virtual environments and their native-to-Python tooling.

Pyrefly 1.0: A fast, forward-looking Python linter
The first full release of Meta’s long-awaited linting and type checking tool for Python delivers speed and offers advanced features for type-checking PyTorch and Django projects.

Hands-on with the new sampling profiler in Python 3.15
Among Python 3.15’s best new features is a sampling profiler, for instrumenting your code and finding its bottlenecks with a minimum of performance impact or fuss. See up-close how it works.

All about Hades, the supply-chain malware that hides in Python packages
It hides in Python packages. It replicates itself across systems. It fools LLM-based code analysis tools into ignoring it. And there may be a lot more like it to come.

More good reads and Python updates elsewhere

Python Steering Council calls for temporary pause on JIT project
The requested pause stays in place until a proper Standards Track PEP lands for the experimental JIT (just-in-time) compiler, the better to describe how the JIT will be a formal and supported part of Python.

Pyodide 314.0: Pyodide packages on PyPI
Thanks to PEP 783, Python packages built with Pyodide (Python ported to WebAssembly) can be installed straight from PyPI instead of through Pyodide — another step closer to Py-on-Wasm becoming an everyday thing.

All about that Python 3.14 garbage collection rigmarole
A new garbage collector introduced in Python 3.14 was yanked at the last minute due to reports of higher memory usage. Here’s a deep dive into what changed for the worse and why.

Are you really expected to run five type checkers now?
No, but you should keep your options open. This blog post from a Pyrefly contributor recommends choosing one of the major offerings (Mypy, Pyrefly, Pyright, ty, Zuban, etc.), but also getting to know the others too.

AI coding agents may be getting bad instructions from ‘smelly’ config files

19 June 2026 at 03:06

AI coding agents are becoming critical to software development, but the configuration files that guide them, such as Agents.md or Claude.md, can be “smelly.”

That means they can contain structural flaws, redundancies, or counterproductive workflows that bloat context, waste tokens, and make coding agents less reliable.

Researchers from the Department of Computer Science at Brazil’s Federal University of Minas Gerais hope to shed light on this problem, presenting what they call the “first catalog of smells” for coding agent configuration files. The most odorous? Lint and skill leakage, context bloat, and conflicting instructions.

“Our results show that these smells are widespread in practice,” the researchers wrote. Consequently, they “may directly influence how coding agents interpret project conventions, prioritize instructions, and perform development tasks.”

Smelly configs in the harness make models misbehave

Agents like Claude Code, Codex, Cursor, and Gemini are increasingly taking over software engineering tasks like code generation and review, test creation, bug fixing, software migration, and documentation writing.

Essentially, they are a combination of a large language model (LLM) and a harness; the model is the brain, the harness provides a loop that executes actions and allows agents to call the tools they need to fulfill a task. These might include web search engines, issue-tracking platforms, and test runners.

Agents’ behavior is guided by config files such as Agents.md and Claude.md, which provide instructions around project workflows, testing requirements, and domain-specific knowledge. This helps maintain consistency across separate tasks and sessions. Typically, these config files are loaded at the start of a session as part of a prompt and are maintained throughout the task.

But the researchers found that these configurations are riddled with smells; 91 of 100 popular open-source repositories containing Agent.md or Claude.md files had at least one smell.

The six strongest odors:

  • Lint leakage (appearing in 62% of files)
  • Context bloat (42%)
  • Skill leakage (35%)
  • Conflicting instructions (28%)
  • Init fossilization (24%)
  • Blind reference (16%)

The scent of waste

Lint leakage occurs when instructions in config files needlessly include rules that are already enforced by analysis tools like code formatters or linters (which filter out bugs, security vulnerabilities, inconsistencies, and programmatic errors, by, for example, restating generic style guide recommendations, formatting rules, line length, naming conventions, or import ordering).

This repetition increases a model’s context size and wastes tokens, the researchers pointed out. It “can divert the model from focusing on more important project-specific concerns, such as architectural constraints, domain rules, or safety policies.”

Context bloat means that configurations are excessively large and overloaded with rules, examples, or details that are unnecessary or low priority. This drives up token usage, ultimately raising costs and distracting the model from higher priority instructions.

With skill leakage, rarely-used or task-specific instructions are unnecessarily included in the configuration, rather than in separate dedicated skill or task files. This specialized knowledge is dragged into every session, even when the model doesn’t need it to perform its task. Thus, the context window becomes larger, more expensive, and difficult to maintain, the researchers noted.

“Furthermore, such rules may compete for attention with the rules that are actually critical for the project,” they wrote.

Just as it sounds, conflicting instructions means that file rules contradict one another, leading to ambiguity; the model essentially gets “confused” and has to choose arbitrarily. This can lead to inconsistency and unstable results.

Init fossilization occurs when files are generated once but never reviewed or edited again, so they include stale or irrelevant rules because they don’t reflect changes in the codebase. “As a result, the configuration tends to accumulate noise, increase context consumption, and reduce the overall effectiveness of the agent over time,” the researchers explained.

Finally, blind references point to files or docs without explaining what they’re for. Consequently, the agent might simply ignore them, leading to problems if they’re critical to a task, load unnecessary materials to gather context, taking up tokens and space, or fail to prioritize important information.

Additionally, the researchers discovered that smells often co-occur in the same file and trigger the appearance of others; for instance, skill leaking and conflicting instructions can increase the likelihood of context bloat by 83% because they add extemporaneous or irrelevant information.

How to air out smells

While these smells are “widespread in practice,” there are ways to air them out.

For example, to reduce lint leakage, stylistic constraints such as formatting, and import ordering should be removed from prompts. Let programmatic tools handle them; spending budget on style rules is a waste, the researchers noted.

To cut down on context bloat, Claude.md and Agents.md files should remain concise and provide project-specific guidance. For instance, Anthropic recommends a target of fewer than 200 lines per Claude.md file.

To limit skill leakage, developers should provide specific instructions in config files about the project build, test running, code conventions, and other important context. Task-specific instructions should be kept in separate markdown files with descriptive names, the researchers advise.

Additionally, to avoid conflicting instructions, builders should periodically review config files to remove instructions that are contradictory or outdated. Similarly, reducing init fossilization requires continuous updating of files, the researchers explained. This is particularly important in cases where an agent makes the same mistake twice in a row, a code review reveals a detail the agent should have already known, or when developers find themselves prompting corrections and clarifications already addressed in a previous session.

Finally, to minimize blind references, developers should tell agents when and why to read files, and include references with concise explanations of the document’s role, the information it contains, and scenarios where it should be used. For instance, text may reference an external dependency, include a link to its GitHub repository, and provide a brief explanation of its purpose. “Then the agent is able to understand the role of the dependency without needing to load or inspect the external repository directly,” the researchers explained.

Ultimately, they concluded, configuration files are “key artifacts” in agentic software development, and when they get smelly, there’s a problem. Therefore, “their quality deserves effort and attention.”

Angular Signals in practice: Building a signal-first form in Angular

18 June 2026 at 10:00

Understanding a reactivity model in the abstract is useful, but it is ultimately incomplete without seeing how it shapes real application code. Concepts such as state, derivation, and explicit dependencies only become meaningful when they influence how forms are built, validated, and maintained in practice.

In two previous articles, “Angular Signal Forms: From event pipelines to signal-driven state” and “Angular Signals explained: How pull-based reactivity changes how we model state,” we reframed form behavior as a state-driven problem and examined Angular Signals as a pull-based reactivity model well-suited to that kind of work. The natural next step is to apply those ideas to an actual Angular form and observe how the architecture changes when state becomes the primary concern.

This article focuses on a concrete example: a modest but realistic registration form. Rather than introducing new concepts, the goal here is to make earlier ideas tangible. We will see how a signal-backed model reshapes validation, interaction state, and submission logic, and how much coordination logic simply disappears when form behavior is expressed declaratively.

The focus here is not on novelty or completeness, but on making the underlying ideas easier to reason about. By walking through a signal-first form from model definition to submission, we can evaluate whether this approach truly reduces complexity and where it introduces new trade-offs that teams should understand before adopting it more broadly.

Read the series:

Implementing a signal-first registration form

With the conceptual groundwork in place, we can now turn theory into a concrete implementation. In this section, we will build a fully working registration form using Angular’s Signal Forms API. This example is deliberately modest in scope, but it is designed to serve as the foundation for the rest of the series. Each subsequent article will extend this same example rather than introducing a new one.

The form collects an email address, a password, a confirmation password, and explicit acceptance of terms. While simple on the surface, this structure allows us to explore field-level validation, cross-field constraints, interaction state, and submission behavior, all without reverting to event-driven form logic.

Project setup and structure

The example assumes a standard Angular application created with the Angular CLI and configured to use Signals (Angular 17+). The Signal Forms APIs (Angular 21+) live under @angular/forms/signals, which must be explicitly imported.

https://github.com/sonukapoor/angular-signal-forms

The folder structure is intentionally conservative:

src/
  app/
    registration/
      registration.component.ts
      registration.component.html
      registration.model.ts

Separating the model from the component keeps form state independent of presentation. This becomes increasingly valuable as the form grows or is reused across multiple components.

Defining the form model

We begin by defining the shape of the data that the form collects. This is a plain TypeScript interface with no Angular dependencies. Treating the form model as a simple data structure reinforces the idea that the form’s values are just state.

// registration.model.ts
export interface RegistrationData {
  email: string;
  password: string;
  confirmPassword: string;
  acceptedTerms: boolean;
}

This interface mirrors what would typically be sent to a back-end API. There is no duplication of state, no separate “form value” object, and no mapping required at submission time.

Creating the signal-backed form

The form itself is created in the component using a writable signal as the source of truth. The form() function attaches form semantics validation, field state, and submission to that signal.

// registration.component.ts
import { CommonModule } from "@angular/common";
import { Component, signal } from "@angular/core";
import {
  email,
  form,
  FormField,
  required,
  submit,
} from "@angular/forms/signals";
import { RegistrationData } from "./registration.model";

@Component({
  selector: "app-registration",
  imports: [FormField, CommonModule],
  templateUrl: "./registration.html",
  styleUrl: "./registration.css",
})
export class Registration {
  readonly model = signal({
    email: "",
    password: "",
    confirmPassword: "",
    acceptedTerms: false,
  });

  readonly registrationForm = form(this.model, (schema) => {
    required(schema.email, { message: "Email is required" });
    email(schema.email, { message: "Enter a valid email address" });

    required(schema.password, { message: "Password is required" });
    required(schema.confirmPassword, {
      message: "Please confirm your password",
    });

    required(schema.acceptedTerms, {
      message: "You must accept the terms to continue",
    });
  });

  async onSubmit(event?: Event) {
    event?.preventDefault();

    await submit(this.registrationForm, (value) => {
      console.log(value());
      // Mock Server Call
      return Promise.resolve([
        {
          kind: "EmailAlreadyExists",
          field: this.registrationForm.email,
          error: { kind: "server", message: "Email already taken" },
        },
      ]);
    });
  }
}

Several design decisions are worth noting.

First, the model signal is defined as read-only. All mutations to the model occur through form bindings, not ad hoc assignments in the component. This keeps the component declarative and avoids the temptation to manipulate form state imperatively.

Second, validation is declared in one place. The schema function describes constraints on the model without introducing control trees, validator arrays, or observable pipelines. Angular takes responsibility for re-running validation whenever the model changes.

Finally, submission logic is explicit. The submit() helper ensures that the form is valid before invoking the callback, and it passes the current model value directly. There is no need to check flags or manually extract values.

Binding the form to the template

With the form defined, the next step is to bind it to the template. Signal Forms provide the [formField] directive, which connects an input element directly to a field in the form schema.





  
@if (registrationForm().errors().length > 0) {
@for (error of registrationForm().errors(); track error.message) {

{{ error.kind }}

}
}
@if ( registrationForm.acceptedTerms().invalid() && registrationForm.acceptedTerms().touched() ) {

{{ registrationForm.acceptedTerms().errors()[0].message }}

}
@if ( registrationForm.confirmPassword().invalid() && registrationForm.confirmPassword().touched() ) {

{{ registrationForm.confirmPassword().errors()[0].message }}

}
@if ( registrationForm.password().invalid() && registrationForm.password().touched() ) {

{{ registrationForm.password().errors()[0].message }}

}
@if ( registrationForm.email().invalid() && registrationForm.email().touched() ) {

{{ registrationForm.email().errors()[0].message }}

}

What stands out here is the absence of indirection. Each input binds directly to a field. Validation state is accessed through signals such as invalid() and touched(). Error messages are read from a structured error object, not reconstructed manually.

This template contains no subscriptions, no async pipes, and no event handlers for value changes. The UI simply reflects the current form state.

Interaction state and user experience

One of the common criticisms of declarative form models is that they obscure user interaction logic. Signal Forms address this directly by exposing interaction metadata as signals.

The touched() signal determines whether a field has been interacted with. By combining it with invalid(), we control when validation messages appear. This logic remains purely declarative: the template describes when errors should be visible, and Angular ensures the signals stay up-to-date.

The disabled state of the submit button is derived from registrationForm.invalid(). There is no need to manually enable or disable it in response to events. If the form becomes valid, the button is enabled automatically.

Why this scales

Even at this early stage, several advantages of a signal-first form model are apparent. The form’s behavior is expressed in terms of state and derivation, not events. The model, validation rules, and UI bindings are clearly separated. There is no duplication of logic between the component and the template.

As the form grows, this structure holds. Additional fields introduce additional schema entries and template bindings, not new subscription logic. Cross-field validation can be added declaratively. Asynchronous validation and persistence can be layered on without rewriting the core model.

Most importantly, the form remains inspectable. At any point during execution, the model signal reflects the current state of the form. Derived state validity, errors, and UI flags can be understood by reading the code, not by tracing runtime behavior.

What we did not solve yet (and why)

At this stage, it would be easy to walk away with the impression that Signal Forms eliminates most of the hard problems associated with form handling. That impression would be misleading. What we have built so far is intentionally incomplete, not because the approach falls short, but because introducing too much too early obscures the value of the underlying model.

One area we have deliberately postponed is cross-field validation that expresses richer business rules. Many real-world forms depend on relationships between fields rather than isolated constraints. Password confirmation is a familiar example, but more complex scenarios quickly arise in enterprise applications. While Signal Forms support these patterns, introducing them before establishing a clear understanding of derived state risks turns validation back into an imperative exercise rather than a declarative one.

We have also avoided asynchronous validation. Server-backed checks introduce latency, partial failure, cancellation, and race conditions. These are not trivial concerns, and treating them casually often leads to subtle bugs and confusing user experiences. Although Signal Forms provide the necessary hooks to model asynchronous behavior, doing so responsibly requires a careful discussion of pending state, effects, and life-cycle boundaries. That discussion belongs in its own article.

Another omission is persistence and synchronization. Many forms need to autosave drafts, synchronize state with local storage, or react to changes by triggering external side effects. These behaviors are not part of the form state itself; they are consequences of state changes. Treating them as such is essential to keeping the architecture comprehensible. Introducing persistence too early would blur the distinction between state and reaction that this article has worked to establish.

Finally, this article has not addressed migration and interoperability. Few teams are starting from a blank slate. Most will adopt Signal Forms incrementally within applications that already rely on reactive forms or template-driven forms. Hybrid approaches, bridging strategies, and gradual refactors are all critical topics, but they presuppose familiarity with both paradigms. Addressing migration before establishing a solid signal-first mental model would undermine that foundation.

These omissions are intentional. A form architecture that tries to do everything at once often ends up doing nothing clearly. By focusing on the core ideas of state, derivation, and declarative validation, we create a base that can absorb additional complexity without collapsing under it.

Signal Forms in the context of Angular’s evolution

To fully appreciate Signal Forms, it helps to step back and view them not as an isolated feature, but as part of a broader shift in Angular’s design philosophy.

For much of its history, Angular emphasized declarative templates paired with imperative coordination in component classes. RxJS became the backbone of that coordination, providing a powerful abstraction for handling asynchronous workflows, user input, and external events. This model scaled well, but it also encouraged developers to express state indirectly through streams and subscriptions.

Signals represent a deliberate recalibration. They re-center Angular’s reactivity model around state and derivation, rather than events and emissions. This shift is visible across the framework: in component inputs, change detection, and now forms. Signal Forms are not an attempt to replace everything that came before; they are an attempt to make the most common use case, modeling and deriving state, simpler and more explicit.

Framed this way, the design of Signal Forms aligns more closely with state-driven form behavior. The requirement to start with a model signal reflects the idea that the state should have a single, inspectable source of truth. Schema-based validation aligns with the notion that constraints are properties of state, not behaviors triggered by events. Field state exposed as signals reinforces the idea that validity, errors, and interaction metadata are derived values that should be read, not managed.

It is also worth noting that Signal Forms do not attempt to abstract away form behavior. They do not hide form state behind opaque classes or life-cycle hooks. They do not require developers to think in terms of control hierarchies or subscription graphs. Instead, they expose form behavior directly, making it easier to reason about how values, validation, and UI feedback relate to one another.

This approach aligns closely with other recent changes in Angular, including the introduction of modern template control flow and a stronger emphasis on explicit data dependencies. Together, these features point toward a framework that favors clarity over indirection and composition over orchestration.

Importantly, Signal Forms are still evolving. Their APIs may change, and their surface area will almost certainly expand. That is precisely why grounding them in first principles matters. Developers who understand why Signal Forms work the way they do will be far better equipped to adapt as the APIs mature.

This article has intentionally avoided duplicating documentation or enumerating every available feature. Instead, it has focused on establishing a conceptual framework that makes the official APIs feel intuitive rather than surprising. When viewed this way, Signal Forms are not a new way to write forms; they are a clearer expression of what forms have always been.

A new way to think about forms

Building the registration form in this article reveals a quiet but important shift. The reduction in complexity does not come from fewer features or simpler requirements. It comes from expressing form behavior in terms of state and derivation rather than orchestration and reaction.

By treating the data model as the single source of truth, validation rules as declarative constraints, and UI behavior as derived from current conditions, much of the coordination logic that typically surrounds forms becomes unnecessary. There are fewer subscriptions to manage, fewer flags to synchronize, and fewer life-cycle concerns to reason about. Form behavior becomes easier to inspect because it is visible directly in the relationships between values.

This approach does not eliminate the hard problems associated with forms. Asynchronous validation, persistence, and interoperability with existing Angular Forms APIs still require careful design. What changes is where that complexity lives. Instead of being interwoven with state representation, those concerns are layered explicitly on top of a clear foundation.

Signal-first forms are not a universal replacement for existing patterns, nor are they a shortcut to simpler applications. They are, however, a strong example of how aligning APIs with first principles can reduce cognitive overhead and improve maintainability over time. For teams building large, state-heavy forms, this alignment can make the difference between code that merely works and code that continues to evolve without friction.

Why AI coding debt is different

18 June 2026 at 10:00

In hardware, when you ship something broken, the consequences are severe and often irreversible. That’s the world I worked in for years, in verification roles at Mellanox and later at Alibaba. The stakes forced the industry to build a rigorous verification culture. You proved designs worked before they left the building.

In software, verification disciplines look like CI/CD pipelines, static analysis, canary deployments, and observability. But those systems were built around code written at human speed, with human comprehension baked into the process. AI code generation has broken that assumption. The writing process can no longer be trusted to carry institutional knowledge and judgment into the codebase. The industry is being pushed toward the kind of rigorous verification culture that hardware engineers have practiced for decades.

Enterprises are generating code faster than at any point in history. Google recently disclosed that 75% of the company’s new code is now AI-generated. Meta has set internal targets requiring most of its engineers to generate the majority of their committed code with AI tools by mid-2026. The velocity gains are significant. But a growing body of evidence suggests the industry is accumulating a new form of technical debt, one that is less visible than the traditional kind and harder to unwind. It’s also preventable, and the organizations that get ahead of it will have a meaningful advantage over those that don’t.

Understand what makes this debt different

The standard narrative frames this as AI writing bad code. That’s not quite right. The more precise problem is cognitive debt: the loss of understanding of how and why software was built the way it was.

When a human writes code, something else happens alongside the typing. They simulate edge cases, reason through dependencies, and make judgment calls grounded in organizational context, including the business requirements behind a feature, the best practices the team has established, and the reasoning behind past architectural choices. That cognitive loop is how institutional knowledge gets built. When AI writes the code, you can get output that is syntactically correct, passes CI, ships cleanly, and leaves no one holding the mental model. The code works until something changes or breaks, and then the team is excavating a black box.

This is distinct from traditional technical debt, which is messy code. Cognitive debt is invisible code that functions but that nobody truly owns. And it compounds faster, because the same velocity that makes AI generation attractive is what prevents anyone from stopping to build the understanding that maintainability requires.

GitClear’s analysis of 211 million changed lines of code across major repositories found that during 2024, duplicate code blocks of five or more lines increased eightfold, while refactoring dropped from 25% to under 10% of all code changes. Refactoring is the slow, unglamorous work that keeps codebases healthy, and developers are doing far less of it. Google’s 2024 DORA report found that a 25% increase in AI adoption correlates with a 7.2% decrease in delivery stability. DORA analysts note that the root cause isn’t flawed code per se; AI inflates batch sizes, and larger changesets have always been riskier to ship.

These findings aren’t indictments of AI-assisted development. They’re diagnostics, and they point toward a specific set of fixes.

Close the context gap first

In a survey of 609 developers we conducted last year, 65% said AI misses relevant context during critical tasks like refactoring, writing tests, or reviewing code. Context is the primary driver of AI code quality, and it’s where most enterprise organizations are underinvesting.

When an AI tool generates code without access to your organization’s architectural decisions, historical pull requests, security policies, or existing module patterns, you get solutions that are locally correct but globally incoherent. Closing that gap requires context engineering: ensuring the tools and agents you use have access, at the right moment, to the right organizational knowledge, and the judgment to determine what is actually relevant for a given task. A retrieval system that surfaces too much irrelevant context can degrade output quality as readily as one that surfaces too little. The specific tooling matters less than the discipline. Context infrastructure needs to be actively maintained, not indexed once and forgotten.

Build this infrastructure before you scale AI generation. Retrofitting is significantly harder. Treat it the way you treat your CI pipeline, as a prerequisite for safe production deployment.

Consider what happens when a team has built this context infrastructure well. Their code review tooling knows about a deprecated internal API, because that deprecation decision lives in months of past pull request discussions that have been indexed and surfaced. When generated code references the old API, the review flags it. Without that context layer, the same mistake gets waved through every time. That’s the kind of institutional knowledge that evaporates when humans stop writing every line of code, and that you have to actively work to preserve.

Build a verification layer that matches your generation velocity

Almost all of the investment in AI-assisted development has gone into generation. Very little has gone into verification. That imbalance is where the tech debt accumulates.

I think of these as the blue team and the red team. The blue team covers code generation, autocomplete, and agentic coding. It’s getting the headlines, the budgets, and the product launches. The red team covers integrity checks, behavior coverage, and alignment with organizational standards. In most organizations, it’s an afterthought. A CI pipeline catches obvious failures. A code review might happen, but reviewers are overwhelmed by the volume of AI-generated output and cannot meaningfully evaluate all of it. The result is code with a veneer of having been reviewed without anyone having actually understood it.

The Crowdstrike outage of 2024 is worth keeping in mind here. AI didn’t generate the problematic code, but the incident illustrated what happens when a single software error propagates through production systems without sufficient verification. That exposure multiplies when code is being generated faster than humans can understand it.

A real verification layer means automated analysis that evaluates whether generated code aligns with your organization’s best practices, architectural standards, and compliance requirements. It means test coverage that reflects intended behavior, not only the happy path the AI chose to generate tests for. And it means traceability: a connection between the requirement and the implementation, so that six months from now, someone can understand what the code does and why it exists.

The numbers support investment here. In the same developer survey, teams that integrated AI into their code review workflow saw quality improvements in 81% of cases, compared to 55% for comparable teams without it. 

Make ownership non-negotiable

Every piece of AI-generated code in production needs an accountable human who understands it well enough to maintain it. This is harder than it sounds, and it’s where most organizations are falling short.

The same velocity that makes AI generation attractive also creates pressure to skip the slow work of genuine comprehension. A developer reviews a 500-line pull request that an AI generated in three minutes and faces a real choice: spend two hours actually understanding it, or approve it because it looks right, passes the test, and “LGTM” (looks good to me). 

Real ownership means slowing down generation velocity enough to allow for meaningful review, and being explicit with your team that this is the right trade-off. When that doesn’t happen, you’ve started building your next legacy system.

What to do this quarter

The good news is that none of this requires a multi-year transformation. The structural problems are real, but they have concrete solutions, and engineering leaders can make meaningful progress on all three fronts without waiting for the next budget cycle.

  • Audit your context infrastructure. If your AI tools are generating code without access to your organization’s architectural decisions, deprecated APIs, and security policies, fix that before expanding generation velocity further. The quality of context determines the quality of output.
  • Invest in the red team. Establish an automated code quality and governance layer that evaluates generated code against your specific organizational standards, beyond functional correctness. This is a distinct investment from your code generation tooling and needs to be treated as such.
  • Establish ownership explicitly. Every AI-generated feature in production should have a human owner who genuinely understands it. Make that a formal requirement.

The organizations that get this right will find that AI generation becomes far more reliable once it has a verification layer underneath it. The ones that don’t will keep shipping faster while understanding their systems less, until the accumulated debt forces a reckoning. That’s a solvable problem. The question is whether you solve it now or later.

—

New Tech Forum provides a venue for technology leaders—including vendors and other outside contributors—to explore and discuss emerging enterprise technology in unprecedented depth and breadth. The selection is subjective, based on our pick of the technologies we believe to be important and of greatest interest to InfoWorld readers. InfoWorld does not accept marketing collateral for publication and reserves the right to edit all contributed content. Send all inquiries to doug_dineley@foundryco.com.

Building a signal-first form in Angular

18 June 2026 at 10:00

Understanding a reactivity model in the abstract is useful, but it is ultimately incomplete without seeing how it shapes real application code. Concepts such as state, derivation, and explicit dependencies only become meaningful when they influence how forms are built, validated, and maintained in practice.

In two previous articles, “Angular Signal Forms: From event pipelines to signal-driven state” and “Angular Signals explained: How pull-based reactivity changes how we model state,” we reframed form behavior as a state-driven problem and examined Angular Signals as a pull-based reactivity model well-suited to that kind of work. The natural next step is to apply those ideas to an actual Angular form and observe how the architecture changes when state becomes the primary concern.

This article focuses on a concrete example: a modest but realistic registration form. Rather than introducing new concepts, the goal here is to make earlier ideas tangible. We will see how a signal-backed model reshapes validation, interaction state, and submission logic, and how much coordination logic simply disappears when form behavior is expressed declaratively.

The focus here is not on novelty or completeness, but on making the underlying ideas easier to reason about. By walking through a signal-first form from model definition to submission, we can evaluate whether this approach truly reduces complexity and where it introduces new trade-offs that teams should understand before adopting it more broadly.

Implementing a signal-first registration form

With the conceptual groundwork in place, we can now turn theory into a concrete implementation. In this section, we will build a fully working registration form using Angular’s Signal Forms API. This example is deliberately modest in scope, but it is designed to serve as the foundation for the rest of the series. Each subsequent article will extend this same example rather than introducing a new one.

The form collects an email address, a password, a confirmation password, and explicit acceptance of terms. While simple on the surface, this structure allows us to explore field-level validation, cross-field constraints, interaction state, and submission behavior, all without reverting to event-driven form logic.

Project setup and structure

The example assumes a standard Angular application created with the Angular CLI and configured to use Signals (Angular 17+). The Signal Forms APIs (Angular 21+) live under @angular/forms/signals, which must be explicitly imported.

https://github.com/sonukapoor/angular-signal-forms

The folder structure is intentionally conservative:

src/
  app/
    registration/
      registration.component.ts
      registration.component.html
      registration.model.ts

Separating the model from the component keeps form state independent of presentation. This becomes increasingly valuable as the form grows or is reused across multiple components.

Defining the form model

We begin by defining the shape of the data that the form collects. This is a plain TypeScript interface with no Angular dependencies. Treating the form model as a simple data structure reinforces the idea that the form’s values are just state.

// registration.model.ts
export interface RegistrationData {
  email: string;
  password: string;
  confirmPassword: string;
  acceptedTerms: boolean;
}

This interface mirrors what would typically be sent to a back-end API. There is no duplication of state, no separate “form value” object, and no mapping required at submission time.

Creating the signal-backed form

The form itself is created in the component using a writable signal as the source of truth. The form() function attaches form semantics validation, field state, and submission to that signal.

// registration.component.ts
import { CommonModule } from "@angular/common";
import { Component, signal } from "@angular/core";
import {
  email,
  form,
  FormField,
  required,
  submit,
} from "@angular/forms/signals";
import { RegistrationData } from "./registration.model";

@Component({
  selector: "app-registration",
  imports: [FormField, CommonModule],
  templateUrl: "./registration.html",
  styleUrl: "./registration.css",
})
export class Registration {
  readonly model = signal({
    email: "",
    password: "",
    confirmPassword: "",
    acceptedTerms: false,
  });

  readonly registrationForm = form(this.model, (schema) => {
    required(schema.email, { message: "Email is required" });
    email(schema.email, { message: "Enter a valid email address" });

    required(schema.password, { message: "Password is required" });
    required(schema.confirmPassword, {
      message: "Please confirm your password",
    });

    required(schema.acceptedTerms, {
      message: "You must accept the terms to continue",
    });
  });

  async onSubmit(event?: Event) {
    event?.preventDefault();

    await submit(this.registrationForm, (value) => {
      console.log(value());
      // Mock Server Call
      return Promise.resolve([
        {
          kind: "EmailAlreadyExists",
          field: this.registrationForm.email,
          error: { kind: "server", message: "Email already taken" },
        },
      ]);
    });
  }
}

Several design decisions are worth noting.

First, the model signal is defined as read-only. All mutations to the model occur through form bindings, not ad hoc assignments in the component. This keeps the component declarative and avoids the temptation to manipulate form state imperatively.

Second, validation is declared in one place. The schema function describes constraints on the model without introducing control trees, validator arrays, or observable pipelines. Angular takes responsibility for re-running validation whenever the model changes.

Finally, submission logic is explicit. The submit() helper ensures that the form is valid before invoking the callback, and it passes the current model value directly. There is no need to check flags or manually extract values.

Binding the form to the template

With the form defined, the next step is to bind it to the template. Signal Forms provide the [formField] directive, which connects an input element directly to a field in the form schema.





  
@if (registrationForm().errors().length > 0) {
@for (error of registrationForm().errors(); track error.message) {

{{ error.kind }}

}
}
@if ( registrationForm.acceptedTerms().invalid() && registrationForm.acceptedTerms().touched() ) {

{{ registrationForm.acceptedTerms().errors()[0].message }}

}
@if ( registrationForm.confirmPassword().invalid() && registrationForm.confirmPassword().touched() ) {

{{ registrationForm.confirmPassword().errors()[0].message }}

}
@if ( registrationForm.password().invalid() && registrationForm.password().touched() ) {

{{ registrationForm.password().errors()[0].message }}

}
@if ( registrationForm.email().invalid() && registrationForm.email().touched() ) {

{{ registrationForm.email().errors()[0].message }}

}

What stands out here is the absence of indirection. Each input binds directly to a field. Validation state is accessed through signals such as invalid() and touched(). Error messages are read from a structured error object, not reconstructed manually.

This template contains no subscriptions, no async pipes, and no event handlers for value changes. The UI simply reflects the current form state.

Interaction state and user experience

One of the common criticisms of declarative form models is that they obscure user interaction logic. Signal Forms address this directly by exposing interaction metadata as signals.

The touched() signal determines whether a field has been interacted with. By combining it with invalid(), we control when validation messages appear. This logic remains purely declarative: the template describes when errors should be visible, and Angular ensures the signals stay up-to-date.

The disabled state of the submit button is derived from registrationForm.invalid(). There is no need to manually enable or disable it in response to events. If the form becomes valid, the button is enabled automatically.

Why this scales

Even at this early stage, several advantages of a signal-first form model are apparent. The form’s behavior is expressed in terms of state and derivation, not events. The model, validation rules, and UI bindings are clearly separated. There is no duplication of logic between the component and the template.

As the form grows, this structure holds. Additional fields introduce additional schema entries and template bindings, not new subscription logic. Cross-field validation can be added declaratively. Asynchronous validation and persistence can be layered on without rewriting the core model.

Most importantly, the form remains inspectable. At any point during execution, the model signal reflects the current state of the form. Derived state validity, errors, and UI flags can be understood by reading the code, not by tracing runtime behavior.

What we did not solve yet (and why)

At this stage, it would be easy to walk away with the impression that Signal Forms eliminates most of the hard problems associated with form handling. That impression would be misleading. What we have built so far is intentionally incomplete, not because the approach falls short, but because introducing too much too early obscures the value of the underlying model.

One area we have deliberately postponed is cross-field validation that expresses richer business rules. Many real-world forms depend on relationships between fields rather than isolated constraints. Password confirmation is a familiar example, but more complex scenarios quickly arise in enterprise applications. While Signal Forms support these patterns, introducing them before establishing a clear understanding of derived state risks turns validation back into an imperative exercise rather than a declarative one.

We have also avoided asynchronous validation. Server-backed checks introduce latency, partial failure, cancellation, and race conditions. These are not trivial concerns, and treating them casually often leads to subtle bugs and confusing user experiences. Although Signal Forms provide the necessary hooks to model asynchronous behavior, doing so responsibly requires a careful discussion of pending state, effects, and life-cycle boundaries. That discussion belongs in its own article.

Another omission is persistence and synchronization. Many forms need to autosave drafts, synchronize state with local storage, or react to changes by triggering external side effects. These behaviors are not part of the form state itself; they are consequences of state changes. Treating them as such is essential to keeping the architecture comprehensible. Introducing persistence too early would blur the distinction between state and reaction that this article has worked to establish.

Finally, this article has not addressed migration and interoperability. Few teams are starting from a blank slate. Most will adopt Signal Forms incrementally within applications that already rely on reactive forms or template-driven forms. Hybrid approaches, bridging strategies, and gradual refactors are all critical topics, but they presuppose familiarity with both paradigms. Addressing migration before establishing a solid signal-first mental model would undermine that foundation.

These omissions are intentional. A form architecture that tries to do everything at once often ends up doing nothing clearly. By focusing on the core ideas of state, derivation, and declarative validation, we create a base that can absorb additional complexity without collapsing under it.

Signal Forms in the context of Angular’s evolution

To fully appreciate Signal Forms, it helps to step back and view them not as an isolated feature, but as part of a broader shift in Angular’s design philosophy.

For much of its history, Angular emphasized declarative templates paired with imperative coordination in component classes. RxJS became the backbone of that coordination, providing a powerful abstraction for handling asynchronous workflows, user input, and external events. This model scaled well, but it also encouraged developers to express state indirectly through streams and subscriptions.

Signals represent a deliberate recalibration. They re-center Angular’s reactivity model around state and derivation, rather than events and emissions. This shift is visible across the framework: in component inputs, change detection, and now forms. Signal Forms are not an attempt to replace everything that came before; they are an attempt to make the most common use case, modeling and deriving state, simpler and more explicit.

Framed this way, the design of Signal Forms aligns more closely with state-driven form behavior. The requirement to start with a model signal reflects the idea that the state should have a single, inspectable source of truth. Schema-based validation aligns with the notion that constraints are properties of state, not behaviors triggered by events. Field state exposed as signals reinforces the idea that validity, errors, and interaction metadata are derived values that should be read, not managed.

It is also worth noting that Signal Forms do not attempt to abstract away form behavior. They do not hide form state behind opaque classes or life-cycle hooks. They do not require developers to think in terms of control hierarchies or subscription graphs. Instead, they expose form behavior directly, making it easier to reason about how values, validation, and UI feedback relate to one another.

This approach aligns closely with other recent changes in Angular, including the introduction of modern template control flow and a stronger emphasis on explicit data dependencies. Together, these features point toward a framework that favors clarity over indirection and composition over orchestration.

Importantly, Signal Forms are still evolving. Their APIs may change, and their surface area will almost certainly expand. That is precisely why grounding them in first principles matters. Developers who understand why Signal Forms work the way they do will be far better equipped to adapt as the APIs mature.

This article has intentionally avoided duplicating documentation or enumerating every available feature. Instead, it has focused on establishing a conceptual framework that makes the official APIs feel intuitive rather than surprising. When viewed this way, Signal Forms are not a new way to write forms; they are a clearer expression of what forms have always been.

A new way to think about forms

Building the registration form in this article reveals a quiet but important shift. The reduction in complexity does not come from fewer features or simpler requirements. It comes from expressing form behavior in terms of state and derivation rather than orchestration and reaction.

By treating the data model as the single source of truth, validation rules as declarative constraints, and UI behavior as derived from current conditions, much of the coordination logic that typically surrounds forms becomes unnecessary. There are fewer subscriptions to manage, fewer flags to synchronize, and fewer life-cycle concerns to reason about. Form behavior becomes easier to inspect because it is visible directly in the relationships between values.

This approach does not eliminate the hard problems associated with forms. Asynchronous validation, persistence, and interoperability with existing Angular Forms APIs still require careful design. What changes is where that complexity lives. Instead of being interwoven with state representation, those concerns are layered explicitly on top of a clear foundation.

Signal-first forms are not a universal replacement for existing patterns, nor are they a shortcut to simpler applications. They are, however, a strong example of how aligning APIs with first principles can reduce cognitive overhead and improve maintainability over time. For teams building large, state-heavy forms, this alignment can make the difference between code that merely works and code that continues to evolve without friction.

AWS targets software release bottlenecks with DevOps Agent update

17 June 2026 at 16:00

The problem with software development today may no longer be writing code. With AI coding assistants generating code faster than ever, the bigger challenge is reviewing, testing, and safely releasing it.

AWS is betting that software teams need help with that part of the process, adding release management features to its DevOps Agent.

The new features, currently in preview, automatically assess code changes against organizational standards, identify potential release risks, and generate tests tailored to individual changes before they reach production.

The release readiness feature, in particular, runs the code in an AWS-managed isolated environment, executing lightweight user journey tests to verify the software builds, runs, and passes basic functional checks before the change enters the pipeline, the company wrote in a blog post.

The findings of these tests can be viewed through the DevOps Agent console, as comments on pull requests in GitHub or GitLab, or can be invoked directly through IDEs via Kiro or the Claude Code plugin, it added.

Targeting AI-era software delivery bottlenecks

Running code in isolated environments and delivering the results directly through developer tools helps address two longstanding challenges in software delivery, said Pareekh Jain, principal analyst at Pareekh Consulting.

It enables teams to validate how code changes behave before deployment, catching issues that static analysis may overlook, while reducing context switching by embedding findings into existing workflows, in turn accelerating fixes, Jain said.

The analyst pointed out that the release readiness capability addresses a key bottleneck in AI-driven software development: “While AI coding agents can generate code quickly, reviews, compliance checks, dependency validation, and release approvals still slow deployment.”

“By automatically checking code changes against internal standards, security policies, and dependency impacts, AWS helps developers, DevOps teams, and SREs identify issues earlier, reduce manual review effort, and improve release confidence,” Jain added.

These gains in productivity for developers could also translate into tangible business benefits for CIOs, according to Jain.

“Release readiness as a feature could help enterprises capture more value from AI-generated code while reducing operational overhead by eliminating the need for additional QA and DevOps resources. This means that they can accelerate software delivery without sacrificing reliability,” the analyst noted.

Autonomous testing before merging code

While release readiness reviews focus on assessing whether a code change is safe to move through the delivery pipeline, AWS is also adding a separate feature aimed at validating how those changes behave in production-like environments.

Named autonomous release testing, the new capability generates and runs change-specific test plans for web and API-based applications in customer-provisioned, production-like environments before the change actually merges, the company wrote in the blog post.

For Jain, autonomous release testing is “even more” important for developers and SREs as it “automates one of the most time-consuming parts of software delivery.”

“Developers spend less time creating and maintaining tests, while SREs benefit from fewer rollbacks and improved system reliability,” Jain said.

These benefits stem from the feature’s ability to automatically generate tests tailored to individual code changes, covering functional correctness, behavioral regressions, and integration scenarios that might otherwise require significant manual effort, Jain added.

However, AWS is not alone in trying to bring AI deeper into the software delivery lifecycle.

Microsoft-owned GitHub has been expanding Copilot’s code review capabilities, allowing the service to automatically review pull requests, suggest fixes, and provide feedback directly within developer workflows.

Google, meanwhile, has been steadily broadening the scope of Gemini Code Assist beyond code generation to support software development tasks such as code review and developer assistance.

AWS’s differentiation, though, according to Jain, lies in tying those capabilities to release management and operational workflows that span development and production environments.

Availability and pricing

For development teams interested in evaluating DevOps Agent’s new capabilities, AWS said both features are available in preview at no additional cost in the US East (N. Virginia) region.

AWS DevOps Agent, billed per agent-second, is included in the AWS Free Tier for new customers.

Additionally, new AWS DevOps Agent customers receive a 2-month free trial starting with their first operational task after general availability.

Each trial month includes up to 10 agent spaces, 20 hours of investigations (incident response), 15 hours of evaluations (incident prevention), and 20 hours of on-demand SRE tasks (chat), the company said.

Once those limits are exhausted, customers are charged based on consumption, with investigations, evaluations, and on-demand SRE tasks each priced at $0.0083 per agent-second, AWS added.

A prerequisite for using the new release management features includes connecting at least one GitHub or GitLab repository to an AWS DevOps Agent Space.

Z.ai pitches GLM-5.2 for long-running software engineering tasks

17 June 2026 at 11:32

Z.ai has released GLM-5.2, an MIT-licensed open-source AI model designed for long-running software engineering tasks, as the Chinese company seeks to challenge proprietary coding models on cost and performance.

The company said GLM-5.2 ranked just behind Anthropic’s Claude Opus 4.8 on FrontierSWE, a long-horizon coding benchmark, trailing it by 1%. Z.ai said the model also edged out OpenAI’s GPT-5.5 by 1%.

Z.ai said GLM-5.2 supports a one million-token context window with up to 131,072 output tokens, positioning it for agentic coding workflows that require reasoning across large codebases.

The company is also making an efficiency argument. It said GLM-5.2 uses a technique called IndexShare, which reduces per-token compute by 2.9 times at a one million-token context length. It also said changes to the model’s multi-token prediction layer increased the acceptance length for speculative decoding by up to 20%.

The changes are aimed at a practical problem for developers: long-context coding agents can be expensive to run when they are asked to work across large repositories.

Enterprise appeal

GLM-5.2’s clearest appeal is that it pairs stronger coding capabilities with the cost advantages of an open-source model. But capability alone will not be enough to make it a credible alternative.

“Western enterprises will want independent benchmark validation, successful deployments at global enterprises, strong security and governance controls, and long-term support commitments,” said Pareekh Jain, CEO of Pareekh Consulting.

Jain said the fastest route to enterprise credibility would be hosting by a major cloud provider like AWS. That would allow customers to use the model under standard enterprise terms, with service-level commitments and compliance certifications.

Tulika Sheel, senior VP at Kadence International, said GLM-5.2 would also need to prove it can operate as a stable enterprise product.

“Demonstrated success in real-world deployments and transparent governance will be just as important as benchmark scores,” Sheel said.

The performance and cost claims will also need to hold up against established models.

“Enterprise leaders generally consider two major factors when evaluating new models,” said Lian Jye Su, chief analyst at Omdia. “First, they look at overall performance against competitors, where GLM-5.2 performs well in long-horizon agentic coding and software engineering. Second, they look at the cost of adoption. As an open-source model, GLM-5.2 has clear cost advantages.”

Su said the model could appeal to engineering teams under pressure to control AI costs. It may also attract open-source advocates and companies with significant operations in Asia-Pacific.

But the claims still need wider validation, particularly around hallucination control and coherence during extended tasks. These are critical issues for enterprises considering AI coding agents, which may need to work across large codebases and multi-step software engineering workflows.

Jain said the one million-token context window could be useful for large codebase analysis. It could also help with legacy modernization projects and complex engineering documentation.

He said long-context capability may also help with audit logs or legal contracts, where splitting material into smaller chunks can create errors across document boundaries. But for everyday coding tasks, effective retrieval systems may matter more than very large context windows, making some of the benefits more limited in practice.

Governance risks

The governance question depends largely on where the model runs.

Sheel said enterprises should evaluate GLM-5.2 as they would any strategic technology partner, rather than as a standalone model. That means looking at where data is stored and whether the model can be used in environments customers control.

That deployment choice is central to the risk calculation, according to Jain. Because GLM-5.2 is available under an MIT license, companies can download the weights and run them on their own infrastructure, reducing the need to send sensitive data to Z.ai.

“The risk flips completely if you use Z.ai’s hosted API instead,” Jain said.

He said Chinese national security rules could require domestic companies to cooperate with government requests, making hosted use difficult for regulated industries or workloads involving sensitive data.

Su said the issue is not limited to Chinese vendors. Recent restrictions affecting access to some Anthropic models have also highlighted the risk that enterprises may have limited control over the availability of AI services from foreign providers.

“Selecting solutions from American and Chinese AI vendors does expose non-US Western enterprises to additional risk of having zero control over the availability and uptime of these models,” Su said.

10 tips for getting better R code from your AI coding agent

17 June 2026 at 10:00

Most generative AI tools know less about R than languages like JavaScript and Python, thanks to how much training data is available for each. However, with a little extra setup, you can give a large language model (LLM) the knowledge it needs to improve its R skills.

Here are 10 ways to help generative AI write R code like a pro.

Use a coding agent

AI coding agents have more power, flexibility, and coding-focused tools than general-purpose chatbots.

Anthropic’s Claude Code and OpenAI’s Codex agents have versions that run in a terminal, IDE extensions, desktop and mobile apps, and other integrations.

R users may also be interested in Posit’s Posit Assistant, which is designed for data analysis in both R and Python. It needs less setup for R than general-purpose coding agents, and it has more built-in knowledge about data science, R package development, and Shiny apps. Plus, it can read objects in your R and Python environments by default, which can be useful in some situations (although perhaps not if you’re working with sensitive data). There are versions of Posit Assistant for RStudio, the Positron IDE, and the terminal. Setup info is here.

Note: Posit Assistant is not the same as the older Positron Assistant that was demo’d at last year’s posit::conf(). The older assistant will eventually be superceded by Posit Assistant. Posit Assistant comes pre-installed with RStudio but not pre-activated, so you don’t need to use it unless you want to.

Google’s original entry in this space, Gemini CLI, is being retired in favor of a new “Antigravity CLI” starting June 18.

There are other IDE platforms with built-in agents, including Cursor and Windsurf, and terminal + subscription coding agents such as Warp, which was open-sourced in April. However, I won’t be covering those here.

You may be limited at work by what your employer allows you to use, but you can still experiment on your own with public data — and then lobby for a new agent if a different one better meets your needs. Whatever you choose, though, moving to one of these from a web-based chatbot should produce better code.

“The shift from chatbot to agent is the most important change in how people use AI since ChatGPT launched,” says Ethan Mollick, co-director of the Wharton School’s Generative AI Labs at the University of Pennsylvania.

Set up CLAUDE.md, AGENTS.md, or GEMINI.md knowledge files

All the major coding agents look for knowledge files to load each time you start a session, and you can easily edit those files. The files can include things like your proficiency in various languages and how you like to document projects. For example, I tell my LLMs that I’d like a README.md in every project with info on how to use the project and technical info on how the project was coded.

Most coding tools let you have both an overarching main file that’s loaded into every session, and an additional file per project.

If you’re adding Claude or Codex to an existing code base, the /init slash command will create one of those .md project files after scanning and analyzing the code. You can also ask an LLM to interview you to create or add to one of those files.

Claude Code looks for a user-level main CLAUDE.md file at ~/.claude/CLAUDE.md and then a project-level file at ./CLAUDE.md or ./.claude/CLAUDE.md. The /memory slash command shows where those files are located. Codex uses AGENTS.md files. Antigravity docs say it looks for a main GEMINI.md file plus GEMINI.md and/or AGENTS.md files in your working directory.

Positron Assistant is set up to read AGENT.md, AGENTS.md, POSITRON.md, CLAUDE.md, GEMINI.md, and LLMS.txt in a workspace root directory, according to the docs. See the Positron docs for more on custom instructions.

Use agent skills

Agent skills can turn an LLM with questionable R knowledge into an expert that understand how you want it to write code. You can develop your own skills, work with your LLM to create skills, or download skills written by others. Claude even has a skill to help you build skills. This is one of the best ways to stop having to repeat the same instructions over and over. Instead, the LLM will “remember” what’s in your skills files by loading them when they’re needed.

What’s the difference between the knowledge .md files mentioned above and a skill? I like to think of CLAUDE.md or AGENTS.md files as important background info that’s always available, while skills are more specific instructions that are useful at certain times. Or, as Claude Opus 4.7 put it: “Skills are for triggered workflows (‘when user asks X, do Y’). A standing rule that applies to every project isn’t trigger-based; it’s a directive I should always follow.” Standing rules should go in CLAUDE.md.

“Create a skill when you keep pasting the same instructions, checklist, or multi-step procedure into chat, or when a section of CLAUDE.md has grown into a procedure rather than a fact,” according to Anthropic’s Claude Code docs. “Unlike CLAUDE.md content, a skill’s body loads only when it’s used, so long reference material costs almost nothing until you need it.” Only skill descriptions are loaded at the start of each session, so the LLM knows what skills are available.

Anthropic originally created skills for Claude in October 2025 and then published the concept as an open standard a couple of months later. Most coding agents now use them.

Anthropic has an easy-to-folllow guide to creating custom skills here if you want to try your hand at building your own.

Posit Assistant comes with several R-related skills built in and allows users to add more. You’ll find them here.

If you’re not using Posit Assistant, you can add Posit-developed skills to another coding agent. Posit published a GitHub repository with skills for creating R packages, Shiny apps, and Quarto documents; for creating and resolving GitHub pull requests; for open-source R and Python package releases; for code reviews (R, Python, JavaScript/TypeScript, SQL); and for creating architectural documentation for a codebase. Browse them all here.

Read and edit the skills you download

Skills are just a folder with one or more markdown text files that have a structured YAML header. That folder can include optional resources and scripts, too. Skill instruction files are easy to read and edit, so you can make sure they do what you want. Tweak them as desired.

For example, Claude helped me write my own customized R skill. Claude leans toward tidyverse packages, but there are other packages I like a lot, too, such data.table. I made sure the R skill knows my package preferences, and under what circumstances I prefer each.

If one of your preferred procedures changes, remember to update the associated skills. Or, ask an LLM to update it for you. Keeping skills up to date will make your coding agent more useful.

Keep your CLAUDE.md or AGENTS.md files updated, too. Maybe you started off with a CLAUDE.md file that said you’re an experienced Python programmer who is just learning R. Three months from now, you might want to update your R skill level. Or, perhaps you told an AGENTS.md file that you like thoroughly documented code, but now you’d prefer a lighter touch. You may want to have your coding agent go over those files with you from time to time and ask you about the main points and whether they need updating.

Use the btw R package and its MCP server

It’s frustrating when an LLM writes code based on an ancient R package version in its training data, or when it doesn’t know about a relatively recent package at all. btw solves this problem by letting your coding agent access info about all the R packages installed on your system. That means it can write code based on your specific R environment. Plus, btw lets an LLM access variables in your current R environment via a Model Context Protocol (MCP) server.

MCP servers are a standardized way for LLMs to access external data — in this case, your running R session (external doesn’t have to mean cloud). Like skills, MCP was created by Anthropic as an open standard and has since been adopted by most major AI platforms. The btw R package includes an MCP server, which you can install for Claude Code by running the following code in a terminal window (not R console).

claude mcp add -s "user" r-btw -- Rscript -e "btw::btw_mcp_server()"

btw comes with a lot of tools. It’s not a great idea to overload your LLM with tools it may never use. If you just want to register btw tools for accessing your R session and looking up package documentation, you can run a command like this instead:

claude mcp add -s "user" r-btw -- Rscript -e "btw::btw_mcp_server(tools = btw::btw_tools('btw_tool_run_r', 'docs', 'env'))"

You only need to do this once.

To connect Claude Code to your open R session, you also need to run btw::btw_mcp_session() in every new R session. (I sometimes forget this part until I’m puzzled why Claude can’t read my R variables or even see what packages I have installed.)

You can see a demo of btw in this Posit video that compares Claude Code and Posit Assistant.

test_claude_code_btw

The btw R package lets Claude Code and other agents read objects in your R session.

Foundry

You don’t need to do this setup for Posit Assistant, since tools for accessing your R session and variables are built in.

Use plan mode for your projects

I cannot stress this enough. Just as humans benefit from having a plan before starting to implement a project, LLMs benefit from working through a plan before beginning to generate code. Plus, it can be useful at times to “brainstorm” with an LLM about structures and features, ask it for alternatives, or even have another LLM review a plan before implementing it.

Anthropic advises starting with plan mode. “Letting Claude jump straight to coding can produce code that solves the wrong problem. Use plan mode to separate exploration from execution,” they wrote in a best practices doc.

Claude, Codex, Gemini, and Posit Assistant all have a plan mode in their CLI versions that can be activated with the /plan slash command.

claude_plan1


Foundry

claude_plan2 rev

When in plan mode activated with /plan, Claude will often ask questions before coming up with its plan.

Foundry

Make sure your coding agent learns from its mistakes

This is one of the best tips I read first from Joe Amditis, associate director of operations at the Center for Cooperative Media at Montclair State University: If your coding agent makes a mistake and you work together to fix it, make sure to save that memory so it doesn’t make the same error again.

Your agent may have an auto memory system that’s supposed to do some of this (I’ve used Claude Code’s), but you can instruct any coding agent to keep a separate lessons learned file for each project, too, or ask it what’s the best way to ensure it doesn’t make the same error again. This isn’t a guarantee, any more than you can be assured an LLM will follow all the rules in a CLAUDE.md or AGENTS.md file or all the steps in a skill. But it has definitely cut down on my agents making the same errors over and over.

Have your agent write tests and do code reviews

Tests and code reviews done by a coding agent aren’t a substitute for a human checking that software works. Review an LLM’s results yourself any time a task is important! However, agent-generated tests are still a good way to head off some problems and cut down the time you spend as your LLM’s debugging partner. If you don’t know where to start to help your agent know how to test and review code, see Posit’s testing-r-packages and critical-code-reviewer skills. Your agent may also have built-in code review skills, such as Claude Code’s /code-review slash command.

Code review skills are available from many sources. For example, Sentry has a code review skill in its repository. Aimed specifically at its project’s needs, it can be a useful sample for similar skills. And superpowers is a popular set of general-purpose programming skills that’s billed as “a complete software development methodology for your coding agents, built on top of a set of composable skills and some initial instructions that make sure your agent uses them.” I don’t use superpowers, but a lot of other people clearly do given its more than 227,000 GitHub stars and 20,000 forks.

Another tip: Several experts suggest using a different LLM — maybe even from a different provider — to conduct a code review, since each model has its own strengths and weaknesses.

Don’t forget general prompting good habits

Whatever programming language you’re using, being clear will improve your outputs. Keep your requests targeted, and don’t expect the LLM to read your mind.

“Codex handles complex work better when you break it into smaller, focused steps,” OpenAI says in its developer docs. “Smaller tasks are easier for Codex to test and for you to review. If you’re not sure how to split a task up, ask Codex to propose a plan.”

“Take time to make your prompts as relevant as possible, just as you would when helping a new teammate scope a task,” Google advises in its Five Best Practices for Using AI Coding Assistants. “Consider what details you need to share for a person to succeed, and provide all those details to your AI tool.”

And, don’t load up your context window to the LLM’s published limit. Performance often degrades as you get close to the maximum token limit.

Take advantage of open LLMs, particularly if you have budget and token limits

Open-weight models — especially ones small enough to run on a desktop computer — may never rival frontier LLMs like Claude, GPT, or Gemini. But for a lot of R coding, they don’t need to.

To see how well an LLM can write R code, it should have the same kind of harness that Claude Code, Codex, or Posit Assistant gives larger LLMs. “The harness is the product,” argues Mallory Mejias at Sidecar, an AI education company. “The model is the engine inside it — important, but increasingly interchangeable.” I wouldn’t go that far, since I still find the LLM to be a critical piece of this equation, and models differ. But the same LLM will perform differently depending on the tools and context it has.

Posit recently added Google’s open-source Gemma 4 26B to Assistant’s existing options of larger, closed-source LLMs. “Up until this point, models of this size — small enough to run comfortably on high-end consumer laptops — were on our radar but not yet capable enough to drive an agent harness like Posit Assistant,” Posit senior software engineer Simon Couch wrote on the Posit blog. “This has changed in the last few months with releases like Gemma 4.” However, to use it in Posit Assistant in RStudio, you still need to run it through a Posit AI subscription, not locally. It uses 1/10 the budget that the same session with Claude Sonnet would consume.

Several projects can use Claude Code to run local LLMs. Ollama, open-source software for running LLMs locally, does this with the terminal command ollama launch claude --model , such as:

ollama launch claude --model gemma4:26b

The makers of Unsloth, an open-source framework for running and training models, say running local LLMs inside Claude Code can be very slow due to a cache invalidation issue. They say this can be fixed by adding "CLAUDE_CODE_ATTRIBUTION_HEADER" : "0" to ~/.claude/settings.json under “env”.

Unsloth can also use Claude Code to run local models, but it’s somewhat more involved to install and set up than Ollama. See this Unsloth tutorial.

Open-source coding agent Open Code runs LLMs from OpenAI, Anthropic, Google, Kimi, Alibaba’s Qwen, and others. I haven’t warmed up to it yet compared with commercially backed CLI tools I’ve tried, but it has 174,000 GitHub stars so clearly a lot of fans.

AI consultant Thomas Wiegold, who switched from Claude to Open Code, said “OpenCode covers everything I need for my daily workflow. It’s fast, the provider flexibility is genuinely useful rather than theoretical, and the TUI is better for extended sessions…. That said, I’m not going to pretend it’s all smooth sailing.” He noted some stability issues and a remote code execution vulnerability earlier this year.

Wiegold’s suggestion? “Install both. Try others. Stay flexible.”

In summary

Large language models remain imperfect and unpredictable tools, but they’re improving rapidly — as are the harnesses around them. Even frontier LLMs in commercial coding agents can ignore instructions at times and otherwise behave in unpleasantly surprising ways. However, you’ll vastly improve your chances of generating quality code if you use coding agents, take time to set them up with quality instructions, and remember good prompting techniques. Good luck!

—

Coding agent info

Claude Code – Anthropic’s coding agent is available in the terminal and as an IDE extension, a desktop app, mobile apps, Slack app, and a cloud version that can work directly in your repos on GitHub. Arguably the first breakthrough coding agent, it now includes an elegant remote-control option where you can start a session on your desktop and then continue it on a phone or tablet. While designed for Claude LLMs, you can use it to run local LLMs via tools like Ollama or Unsloth Studio. When using Claude models, it tends to offer less usage than other vendors’ options. Anthropic has posted the terminal version’s code on GitHub, with usage governed by Anthropic’s commercial terms of service. You can use Claude Code via API pay per use or as part of a Claude subscription.

Codex – OpenAI’s answer to Claude Code is available via terminal, app, IDE extension, or cloud, with integrations for GitHub, Slack, and Linear. The CLI tool is open source under an Apache license, available on GitHub, and works via API pay per use or as part of a ChatGPT subscription.

Posit Assistant – The Posit (formerly RStudio) coding agent is designed for data work in R and Python, although Posit senior software engineer Simon Couch told me it would do fine for programming work for other uses and in other languages. It is available for the RStudio IDE (via a Posit AI subscription in RStudio), Positron IDE, and as a stand-alone CLI terminal app, although the CLI tool currently doesn’t feel as full-featured as the IDE integrations (that may change). As of this writing, you can also use API keys from Anthropic, OpenAI, and Snowflake Cortex and a GitHub Copilot account in Positron. Posit Assistant is being updated quite frequenty, Couch told me. If you tested it a month or two ago, it has more capabilities now.

Antigravity CLI – Google’s terminal-based tool will be replacing the Gemini CLI for unpaid and Google One users this month. There’s also an Antigravity IDE, SDK, and platform for orchestrating multiple agents. One advantage of Antigravity: Google offers a free plan with access to Gemini 3.5 Flash, Gemini 3.1 Pro, Gemini 3 Flash, Claude Sonnet 4.6, Claude Opus 4.6, and gpt-oss-120b, and what it describes as “generous” but undefined weekly rate limits based on “the degree we have capacity.”

Designing frontend systems for cloud latency, not just cloud failure

17 June 2026 at 10:00

Frontend reliability is often discussed in terms of outages. Teams prepare for failed API calls, downtime and visible crashes because those failures are easy to recognize and measure. However, in many modern applications, the bigger challenge is not complete failure but latency. Systems rarely go fully offline. Instead, they become slow enough that users lose confidence in the interface long before anything technically breaks.

Most frontend engineers have experienced this in production. A page eventually loads, but only after several seconds of waiting. A save action succeeds in the backend, yet the interface remains unchanged long enough that the user clicks the button again. A dashboard renders immediately, but the critical data appears so late that the application feels unstable. In practice, users rarely distinguish between “slow” and “broken.” If an interaction feels uncertain or delayed, trust drops quickly.

As frontend systems become increasingly dependent on distributed cloud infrastructure, latency becomes a normal operating condition rather than an occasional exception. APIs may depend on multiple downstream services, serverless systems may introduce startup delays and state updates may propagate asynchronously across regions or caches. Frontend reliability therefore can no longer be defined only by uptime. It also depends on how clearly the interface behaves while waiting on slow cloud dependencies.

Reliability is more than preventing outages

Frontend teams traditionally define reliability around visible failure. A stable application is one that avoids blank screens, uncaught exceptions and broken API requests. While those issues still matter, they represent only one category of reliability problems.

In many production systems, the application remains technically available while still feeling unreliable to users. An API request that takes ten seconds may still return successfully. A delayed state update may eventually synchronize correctly. A dashboard may fully render after several refresh cycles. From a monitoring perspective, these systems appear healthy. From a user perspective, however, the experience feels inconsistent and unpredictable.

What makes this difficult is that many frontend applications are still designed around ideal conditions. Interfaces often assume fast responses, immediate consistency and stable network behavior. Cloud environments rarely behave with that level of predictability. Distributed systems naturally introduce latency, asynchronous updates and intermittent delays, even when everything is technically functioning correctly.

This changes how frontend engineers need to think about resilience. Modern interfaces are no longer designed only for success and failure. They also need to handle slow success, delayed feedback and partial availability in ways that remain understandable to users.

Slow APIs and the user experience problem

One of the most common latency issues frontend teams encounter is the slow API response. Technically, the request succeeds, but the delay changes how users interpret the application. A user waiting several seconds for a response rarely thinks about infrastructure behavior or distributed systems. They assume the interface is frozen, unresponsive or broken.

This becomes especially noticeable in cloud-connected systems where response times vary depending on caching layers, regional routing, serverless initialization or downstream dependencies. Frontend applications designed around consistently fast responses often struggle in these conditions because they treat latency as exceptional instead of expected.

Many applications still rely on generic loading spinners that provide little context beyond “something is happening.” While spinners technically indicate activity, they also communicate uncertainty. Users do not know whether the system is progressing, stalled or close to failure. As waiting time increases, frustration grows quickly.

More effective interfaces treat loading as part of the user experience rather than a temporary placeholder. Skeleton screens, layout-preserving placeholders and contextual loading feedback provide users with a clearer understanding of what is happening. Even relatively small decisions can make a noticeable difference. For example, users generally tolerate a dashboard chart loading later far more than they tolerate waiting several seconds before the navigation menu appears. Similarly, an e-commerce page that progressively loads recommendations often feels faster than one that blocks the entire interface until every service responds.

These patterns do not reduce actual latency, but they significantly improve perceived responsiveness. When users understand that the system is actively processing their request, they are far more tolerant of delays.

Delayed state updates and perceived instability

Another common issue in cloud-based systems is delayed state synchronization. A user submits an action successfully, but the interface does not immediately reflect the result. Even if the backend processes the request correctly, the delay creates uncertainty around whether the action worked at all.

This behavior is increasingly common in distributed architectures where writes may propagate asynchronously across services, regions or caches. Frontend applications that assume immediate consistency often expose these delays directly to users, leading to repeated clicks, duplicate submissions and confusion around application state.

In many cases, the real problem is not the delay itself but the absence of clear feedback. Users are generally willing to wait if the interface acknowledges that progress is occurring. Without feedback, even short delays begin to feel unreliable.

Frontend systems can reduce this uncertainty by designing around transitional states more intentionally. Pending confirmations, temporary UI updates and clearer progress indicators help maintain confidence while backend systems synchronize. Users care less about exact infrastructure timing than about whether the interface feels responsive and understandable throughout the interaction.

Progressive rendering and partial availability

Traditional frontend rendering strategies often wait for all required data before displaying meaningful content. While this simplifies state management, it also magnifies perceived latency by forcing users to stare at incomplete or empty screens.

Modern cloud systems rarely deliver all information simultaneously. Some requests complete quickly while others depend on slower downstream services. Treating the entire interface as blocked until every dependency responds unnecessarily increases the feeling of slowness.

Progressive rendering offers a more resilient alternative. Instead of waiting for the entire page, the application renders available content immediately while secondary information loads incrementally. A profile page may display account details before loading recommendations. A dashboard may render navigation and layout structure first while analytics populate later. This creates a sense of continuous progress rather than complete inactivity.

What makes this approach effective is that users tolerate delayed secondary content far better than delayed primary interaction. Even when total loading time remains unchanged, the interface feels significantly more stable because progress is visible.

Progressive rendering also changes how frontend teams think about dependency importance. Not every cloud service needs to block the entire user experience. Separating critical interaction paths from secondary content creates systems that remain usable even under imperfect network conditions.

Designing recovery, not just error messages

Latency-related problems are often made worse by weak recovery patterns. Many applications either wait indefinitely or fail abruptly with vague messaging such as “Something went wrong.” Neither approach creates confidence for users who are already uncertain about system behavior.

Frontend resilience improves significantly when interfaces guide users through delays and recovery intentionally. Instead of displaying generic failures immediately, applications can acknowledge that an operation is taking longer than expected while still preserving user progress. Retry actions, recoverable workflows and state preservation help users continue without restarting tasks entirely.

This becomes especially important in forms and transactional flows. Losing user input because of a temporary timeout often damages trust more than the delay itself. In practice, people are usually willing to retry an action. They are far less willing to repeat work they already completed once.

These recovery patterns are not simply UX enhancements. They are architectural decisions that recognize cloud latency as a normal operating condition rather than an edge case.

Designing for latency is designing for reality

As frontend systems become more dependent on distributed cloud infrastructure, latency becomes unavoidable. The most reliable interfaces are not necessarily the ones with the fastest response times. They are the ones that communicate clearly, preserve user confidence and remain usable during delays.

Frontend teams spend enormous effort optimizing rendering performance while often underestimating the impact of latency behavior on user trust. In many applications, the difference between a reliable experience and a frustrating one is not milliseconds of rendering speed but how clearly the interface handles waiting.

Frontend engineers do not need to become cloud infrastructure specialists to design for these realities. However, understanding that cloud latency is a normal part of modern application behavior fundamentally changes how interfaces should be built. Designing for latency is ultimately not about preparing for rare outages. It is about designing for the way modern systems behave every day.

This article is published as part of the Foundry Expert Contributor Network.
Want to join?

❌