<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Inspector.dev</title>
    <description>The latest articles on DEV Community by Inspector.dev (inspector).</description>
    <link>https://dev.to/inspector</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F837%2F41bffde2-11a0-4e30-904e-1f09ab6d2a75.png</url>
      <title>DEV Community: Inspector.dev</title>
      <link>https://dev.to/inspector</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/inspector"/>
    <language>en</language>
    <item>
      <title>Debug Your PHP App From Your Phone, Through Your AI Assistant</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Tue, 28 Jul 2026 14:53:27 +0000</pubDate>
      <link>https://dev.to/inspector/debug-your-php-app-from-your-phone-through-your-ai-assistant-3mhb</link>
      <guid>https://dev.to/inspector/debug-your-php-app-from-your-phone-through-your-ai-assistant-3mhb</guid>
      <description>&lt;p&gt;Last month I was at dinner when my phone buzzed with an Inspector alert: an error on one of our own endpoints. The old routine kicks in automatically at that point. Open the dashboard on a screen too small for it, squint at a stack trace, tell yourself "I'll look properly when I’m back at the laptop", and spend the rest of the evening with that specific low grade guilt of knowing something is broken and choosing to do nothing about it.&lt;/p&gt;

&lt;p&gt;This time I didn't do that. I opened Claude on my phone, asked it to check what was going on with that endpoint, and within a couple of messages it had pulled the actual error, traced it to a query that started timing out after a data migration earlier that day, and proposed the fix. I reviewed it, it looked right, and the incident was basically closed before the table finished eating. That gap, between getting the alert and being able to do something real about it, is what we spent the last stretch of work closing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part of the workflow nobody designed for
&lt;/h2&gt;

&lt;p&gt;We built the Inspector MCP server so your AI coding assistant could read your production data directly: errors, response times, slow queries, the same information you’d normally go dig up in the dashboard. If you missed that first release, the original announcement covers what it does.&lt;/p&gt;

&lt;p&gt;It worked well from day one, but only in one context: coding agents running on your own machine, like Claude Code or Cursor, where you paste your Inspector API token into a config file once and the tool uses it locally from then on. That's fine when the AI client lives on your laptop next to your code. It falls apart the moment the client is Claude or ChatGPT running as a hosted app in a browser or on your phone, because there's no config file there to paste a token into, and there shouldn’t be. Hosted apps authenticate through OAuth, the login-and-approve flow you already know from connecting Slack or Google Drive to some other tool, not through a secret you copy and paste. Our server simply didn’t speak that language yet, so the alert would land on your phone and the trail stopped right there. You could read that something broke. You couldn’t do anything about it without switching devices.&lt;/p&gt;

&lt;p&gt;That's the specific moment this update is built for. Not "AI assistants can now use Inspector data", which was already true, but the alert-to-fix path being unbroken end to end, on whatever device you're holding when the alert arrives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting Inspector to your AI account, step by step
&lt;/h2&gt;

&lt;p&gt;The whole point of this release is that there is no JSON configuration and no API token involved anymore. If you tried the first version and remember editing a config file, forget that part. Here is the actual flow, using Claude as the example, because it's the client I use most. ChatGPT and other web based agents follow the same pattern under different menu names.&lt;/p&gt;

&lt;p&gt;Step 1: add the connector with just a URL&lt;br&gt;
In Claude, open Settings and go to the Connectors section, then choose to add a custom connector. You give it a name, Inspector, and paste the server URL, which you'll find in your application settings inside the Inspector dashboard. It looks like this, with your own application ID at the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://app.inspector.dev/mcp?app=YOUR_APP_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. You don't need to touch "Advanced settings", and there is no field asking you for an authorization token, because the server now negotiates that part on its own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8g5c7kg9cy5osc46h2i7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8g5c7kg9cy5osc46h2i7.png" alt="Claude custom MCP server" width="800" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: authorize the connection on Inspector
&lt;/h2&gt;

&lt;p&gt;As soon as you connect, you're redirected to Inspector, where you'll see a plain authorization screen telling you which application is asking for access and what it will be able to do. In this case, Claude requesting permission to use the MCP server. You log in with the Inspector account you already have, click Authorize, and the handshake completes behind the scenes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnreb2m3rfrlptsy0zgwc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnreb2m3rfrlptsy0zgwc.png" alt="Inspector MCP server authorization" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the piece that was missing before, and it's the reason the whole thing now works from a phone: your credentials stay between you and Inspector, and the AI client walks away with a scoped token it can refresh on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: check the tools you just gave your assistant
&lt;/h2&gt;

&lt;p&gt;You land back in Claude with a confirmation that you're connected, and the connector page now shows the tools the Inspector MCP server exposes, along with a permission switch for each one. You'll see the ability to analyze a specific error, pull recent errors from your production environment, list recent transactions, inspect the details of a single transaction, and get the ten worst performing transactions in your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl8m61332u9mi62aud4z7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl8m61332u9mi62aud4z7.png" alt="Inspector MCP server tools list" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Worth noticing that these are all read only. Your assistant can look at your production data and reason about it, but it isn’t changing anything in your Inspector account. You can also decide per tool whether Claude is always allowed to use it, should ask first, or shouldn’t touch it at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: try it with one prompt
&lt;/h2&gt;

&lt;p&gt;The fastest way to confirm everything works is to ask something broad and see if it comes back with real data instead of a polite guess. Copy and paste this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Look at Inspector and let me know what kind of transactions happened in my application recently.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get an actual summary of your traffic: the endpoints, jobs and commands that ran, how they performed, and anything that stands out. Once you see real numbers coming back, the connection is done and you can forget it exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like when something actually breaks
&lt;/h2&gt;

&lt;p&gt;The setup above takes two minutes and then disappears into the background. The part that matters is the next time an alert reaches your phone while you're nowhere near a desk.&lt;/p&gt;

&lt;p&gt;You open the assistant straight from the notification and start with something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inspector just flagged an error on the /checkout/complete endpoint. What's happening?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The assistant pulls the real error through the MCP connection: exception type, how often it's firing, when it started, which transactions are affected. Then you keep going in the same thread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Show me the slowest transaction involved and suggest what to fix in the code.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's working from actual execution data now, not from reading your code in isolation and guessing which branch is expensive. It can propose a fix, and if your coding agent is set up with access to your repository, open a pull request or push to a branch so the change is waiting for you already reviewed by the time you sit down.&lt;/p&gt;

&lt;p&gt;This won't replace a proper debugging session for anything genuinely complex. But for the alert that hits during a commute, at dinner, or on a Sunday afternoon, the difference between "I'll deal with it tonight" and "I already dealt with it" is the whole reason we built this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it took actual engineering work
&lt;/h2&gt;

&lt;p&gt;We could have shipped a shortcut, some long lived token you paste into a web form, and called the mobile use case supported. It would have demoed fine. It also would have meant handing a static credential to a third party service, which is the exact failure mode OAuth exists to prevent, and it would have made revoking access a manual step that's easy to forget. Doing it properly means Inspector now behaves like any other real OAuth provider: connected applications are visible and revocable from your account, tokens expire and refresh on their own, and the security model matches what you already expect when you connect one service to another.&lt;/p&gt;

&lt;p&gt;It's a small piece of infrastructure next to the monitoring itself, but it's the piece that decides whether "you can debug from your phone" is actually true or just true in a demo video. For us, it's the former now.&lt;/p&gt;

&lt;p&gt;If you haven't connected it yet, the server URL is in your application settings in the &lt;a href="https://app.inspector.dev" rel="noopener noreferrer"&gt;Inspector dashboard&lt;/a&gt;. Add it to whichever AI assistant you carry around, laptop, browser, or phone.&lt;/p&gt;

</description>
      <category>php</category>
      <category>ai</category>
      <category>webdev</category>
      <category>agents</category>
    </item>
    <item>
      <title>Conversational Data Collection: Introducing AIForm for Neuron AI</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Wed, 01 Apr 2026 10:48:01 +0000</pubDate>
      <link>https://dev.to/inspector/conversational-data-collection-introducing-aiform-for-neuron-ai-57c</link>
      <guid>https://dev.to/inspector/conversational-data-collection-introducing-aiform-for-neuron-ai-57c</guid>
      <description>&lt;p&gt;One of the more interesting things about building an open-source framework is that the community often knows what to build next before you do. When I started Neuron AI, I had a fairly clear picture in my head of the core primitives — agents, tools, workflows, structured output. What I didn’t fully anticipate was how quickly developers would start pushing those primitives toward very specific, practical use cases. The feature requests and questions that come through GitHub and the newsletter are often the most honest signal I have about where real-world PHP developers are actually trying to go.&lt;/p&gt;

&lt;p&gt;Over the past few months, one request kept surfacing in different forms: how do I use Neuron AI to collect information from a user through a conversation instead of a traditional form? The details varied — a registration flow here, a support intake there, a booking assistant somewhere else — but the underlying need was the same. People were trying to build this themselves on top of the agent and workflow components, and it was working, but it required a non-trivial amount of plumbing.&lt;/p&gt;

&lt;p&gt;So today I'm releasing &lt;a href="https://github.com/neuron-core/ai-form" rel="noopener noreferrer"&gt;&lt;strong&gt;AIForm&lt;/strong&gt;&lt;/a&gt;, a Neuron AI component that handles exactly this use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;The idea is straightforward. You define the data you want to collect as a plain PHP class using the same &lt;code&gt;#[SchemaProperty]&lt;/code&gt; attributes you already know from Neuron AI's structured output system. You attach validation rules where needed. Then you extend AIForm, wire up a provider, and define what should happen when the form completes. The component takes care of the rest: managing the conversation across multiple turns, tracking which fields have been collected, retrying on validation failures, and calling your callback once everything is in order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RegistrationData&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;#[SchemaProperty(description: 'User full name', required: true)]&lt;/span&gt;
    &lt;span class="na"&gt;#[NotBlank]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="na"&gt;#[SchemaProperty(description: 'Email address', required: true)]&lt;/span&gt;
    &lt;span class="na"&gt;#[Email]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="na"&gt;#[SchemaProperty(description: 'Phone number')]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$phone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RegistrationForm&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AIForm&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$formDataClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RegistrationData&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;AIProviderInterface&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ANTHROPIC_API_KEY'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ANTHROPIC_MODEL'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;mixed&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;RegistrationData&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a controller, you process each incoming message through the form instance and get back a state object telling you the current status, completion percentage, and any missing fields, everything you need to drive the UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RegistrationForm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setChatHistory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileChatHistory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/tmp/chats/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$sessionId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nv"&gt;$handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$form&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="nv"&gt;$state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'status'&lt;/span&gt;          &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'message'&lt;/span&gt;         &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getLastResponse&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="s1"&gt;'completion'&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getCompletionPercentage&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="s1"&gt;'missing_fields'&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMissingFields&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="s1"&gt;'is_complete'&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$form&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isComplete&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The confirmation step
&lt;/h2&gt;

&lt;p&gt;Something that came up during the build was the question of what to do once all required data is collected but before the callback fires. In many real flows: registrations, bookings, checkout-adjacent interactions, you want the user to review what was collected and confirm before anything is committed. AIForm handles this with &lt;code&gt;requireConfirmation()&lt;/code&gt;, which causes the workflow to throw a FormInterruptRequest instead of submitting immediately. You can serialize that interrupt into the session, present the AI-generated summary to the user, and then resume the workflow with the user's response. If they confirm, the callback runs. If they want to change something, the form drops back into collection mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RegistrationForm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;requireConfirmation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$form&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="nv"&gt;$state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getInterrupt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;FormInterruptRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$_SESSION&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'form_interrupt'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getInterrupt&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="c1"&gt;// return the AI-generated summary to the user&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// on the next request, resume:&lt;/span&gt;
&lt;span class="nv"&gt;$interrupt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;unserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SESSION&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'form_interrupt'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nv"&gt;$handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$form&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="nv"&gt;$interrupt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is built on the same human-in-the-loop interruption mechanism introduced in NeuronAI v2 workflows, so the pattern will feel familiar if you've used that before.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters beyond the obvious
&lt;/h2&gt;

&lt;p&gt;The instinct when you first see this is to think of it as a chatbot wrapper around a form. That's a reasonable first impression, but it slightly misses the point. The more interesting aspect is what happens with users who don't fill in forms cleanly: they skip optional fields, mistype emails, answer questions out of order, or abandon the flow halfway through because the interface felt rigid. A conversational flow handles all of this naturally — the AI asks follow-up questions, flags validation failures in plain language, and keeps state across turns without you writing any of that logic yourself.&lt;/p&gt;

&lt;p&gt;There's also a less obvious benefit for mobile and voice-adjacent interfaces, where long forms are genuinely painful to use. If your PHP application already has an API layer and a frontend consuming it, plugging AIForm into a controller gives you a conversation endpoint you can connect to any interface — including ones that don't have keyboard input as their primary interaction model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built on the existing stack
&lt;/h2&gt;

&lt;p&gt;AIForm is a NeuronAI workflow under the hood, which means it inherits everything the workflow system already provides. That includes native Inspector integration, if you have &lt;code&gt;INSPECTOR_INGESTION_KEY&lt;/code&gt; set in your environment, every form conversation will appear in your Inspector dashboard with the full execution timeline. This matters in production when a conversation stalls or a validation loop behaves unexpectedly and you need to understand exactly what happened.&lt;/p&gt;

&lt;p&gt;The package is available now on GitHub at &lt;code&gt;neuron-core/ai-form&lt;/code&gt;. Install it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require neuron-ai/ai-form
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Documentation for the structured output system and workflow components that AIForm builds on is at docs.neuron-ai.dev. If you build something with it, I'd genuinely like to hear about the use case — the community feedback is what shaped this component in the first place.&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>ai</category>
      <category>backend</category>
    </item>
    <item>
      <title>Maestro: A Customizable CLI Agent Built Entirely in PHP</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Mon, 16 Mar 2026 14:18:04 +0000</pubDate>
      <link>https://dev.to/inspector/maestro-a-customizable-cli-agent-built-entirely-in-php-3d3</link>
      <guid>https://dev.to/inspector/maestro-a-customizable-cli-agent-built-entirely-in-php-3d3</guid>
      <description>&lt;p&gt;For a long time, the implicit message from the AI tooling industry has been: if you want to build agents, learn Python. The frameworks, the tutorials, the conference talks, all pointed in the same direction. PHP developers who wanted to experiment with autonomous systems had two options: switch stacks or stitch something together from raw API calls and hope it holds.&lt;/p&gt;

&lt;p&gt;That's the gap &lt;a href="https://github.com/neuron-core/neuron-ai" rel="noopener noreferrer"&gt;Neuron AI&lt;/a&gt; was built to close. And now, with Neuron v3 introducing a workflow-first architecture, I wanted to prove the point in the most direct way possible: build something that the ecosystem assumes can only be done in another language. That's how &lt;a href="https://github.com/neuron-core/maestro" rel="noopener noreferrer"&gt;Maestro&lt;/a&gt; was born: a fully customizable, extension-driven CLI agent built entirely in PHP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/neuron-core/maestro" rel="noopener noreferrer"&gt;https://github.com/neuron-core/maestro&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I really believe that it is important to create the basis for agentic systems development in PHP, and this project is a further step to provide PHP developers with all the necessary elements to build a native AI stack they can build upon to power the next generation of software solutions.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/F01ZQWSAsw0"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Neuron
&lt;/h2&gt;

&lt;p&gt;Neuron is a PHP framework for developing agentic applications. By handling the heavy lifting of orchestration, data loading, and debugging, Neuron clears the path for you to focus on the creative soul of your project. From the first line of code to a fully orchestrated multi-agent system, you have the freedom to build AI entities that think and act exactly how you envision them.&lt;/p&gt;

&lt;p&gt;We provide tools for the entire agentic application development lifecycle — from LLM interfaces, to data loading, to multi-agent orchestration, to monitoring and debugging. Neuron's architecture prioritizes the fundamentals that experienced engineers expect from production-grade software: a strong PHP 8 typing system with 100% PHPStan coverage, IDE-friendly method signatures, minimal external dependencies through standard PSR interfaces, and a design that works identically whether you're building a microservice in pure PHP, a Laravel application, or a Symfony project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7xtnr8ea3aol7l4p3qy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7xtnr8ea3aol7l4p3qy.png" alt="Neuron AI Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  An Agent Runtime, Not just a Coding Tool
&lt;/h2&gt;

&lt;p&gt;The easiest way to describe Maestro is to start with what it is not. It's not a code completion plugin. It's not a fixed-purpose tool that does one thing. It's a CLI agent runtime — a framework for running an AI agent in your terminal that you can shape toward any purpose through its extension system.&lt;/p&gt;

&lt;p&gt;Out of the box, Maestro ships with a &lt;code&gt;CodingExtension&lt;/code&gt; that turns it into a coding assistant: it gives the agent filesystem tools, a code-aware system prompt, and everything you'd expect from a tool that reads your project and proposes changes. But that extension is just a bundle of capabilities that happens to ship with the default installation. You can disable it. You can replace it. You can install extensions built by other people from Packagist. The agent runtime underneath — the conversation loop, the event system, the tool approval flow, the UI rendering pipeline — knows nothing about coding. It only knows how to run an agent and expose the right hooks for extensions to plug into.&lt;/p&gt;

&lt;p&gt;This is the architectural decision that makes Maestro interesting as a project. The coding agent was the first demonstration, a proof that the patterns the industry has been building in Python and TypeScript are fully expressible in PHP. But "coding agent" was never the destination.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Extension System
&lt;/h2&gt;

&lt;p&gt;An extension is a PHP class that implements &lt;code&gt;ExtensionInterface&lt;/code&gt;. The contract is intentionally minimal: a &lt;code&gt;name()&lt;/code&gt; method that returns a string identifier, and a &lt;code&gt;register()&lt;/code&gt; method that receives an &lt;code&gt;ExtensionApi&lt;/code&gt; instance where you wire everything up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyExtension&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ExtensionInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'my-extension'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ExtensionApi&lt;/span&gt; &lt;span class="nv"&gt;$api&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$api&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$myTool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$api&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$myCommand&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$api&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'my_tool'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$myRenderer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$api&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'my-extension.guidelines'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/memory/guidelines.md'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$api&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AgentResponseEvent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// react to agent responses&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Through the &lt;code&gt;ExtensionApi&lt;/code&gt;, you have access to five integration points. Tools are the actions the AI agent can take — anything you register here becomes something the agent can decide to call during a conversation. Inline commands are slash-prefixed commands available in the interactive terminal session (&lt;code&gt;/deploy&lt;/code&gt;, &lt;code&gt;/status&lt;/code&gt;, &lt;code&gt;/help&lt;/code&gt;) that run outside the AI loop, handled directly by your code. Memory files are Markdown documents injected into the agent's system prompt before the conversation starts, giving the agent domain knowledge, conventions, and instructions specific to your use case. Renderers control how the output of specific tools is displayed in the terminal. And event handlers let you react to what the agent is doing — thinking, responding, requesting tool approval — with arbitrary code.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;registerMemory&lt;/code&gt; call is worth dwelling on, because it's the mechanism that controls the agent’s personality and expertise. When you install the &lt;code&gt;CodingExtension&lt;/code&gt;, the memory file it registers contains instructions about how to read and modify code safely, how to reason about diffs, when to ask for clarification. If you build a database migration assistant, your memory file contains your conventions for writing migrations, your team’s naming rules, which tables are sensitive. If you build a deployment workflow agent, it contains your environment topology, your rollback procedures, what the agent should always confirm before proceeding. The agent isn’t smart about your domain because it was trained on it, it's smart because your extension told it what to know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Install as a global Composer tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer global require neuron-core/maestro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure Composer’s global bin directory is in your system PATH:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$(composer config -g home)/vendor/bin:$PATH"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configuration lives in &lt;code&gt;.maestro/settings.json&lt;/code&gt; at the root of your project. Run the init command to start the interactive setup guide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /path/to/your/project
maestro init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At minimum, you need a provider and an API key. Maestro supports all the providers available through Neuron, such as Anthropic, OpenAI, Gemini, Cohere, Mistral, Ollama, Grok, and Deepseek, all routed through a &lt;code&gt;ProviderFactory&lt;/code&gt; that maps the default field to the corresponding Neuron AI provider instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"anthropic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"providers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"anthropic"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"api_key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sk-ant-your-key-here"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"claude-sonnet-4-6"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to run everything locally without sending data to an external API, point it at an Ollama instance instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ollama"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"providers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ollama"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"base_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:11434"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"llama2"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Tool Approval Flow
&lt;/h2&gt;

&lt;p&gt;When the agent wants to modify a file, execution doesn't just proceed. It stops, and you see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The agent wants to write changes to src/Service/UserService.php

[1] Allow once
[2] Allow for session
[3] Reject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Allow for session" is the option I use most in practice. It means I approve write operations on a given file type or tool once per session, without having to confirm each individual change.&lt;/p&gt;

&lt;p&gt;This granularity matters. You probably want to approve the first few changes in an unfamiliar session to build confidence, then let the agent run more freely once it's demonstrated it understands what you’re asking.&lt;/p&gt;

&lt;p&gt;This is one of the most interesting feature provided by the Neuron AI framework, thanks to the Workflow architecture. Neuron Workflow support execution interruption, so you can create fully customizable huma-in-the-loop experience. The agent will stop its execution, waiting to be resumed exactly from where it left off. Learn more on the &lt;a href="https://docs.neuron-ai.dev/workflow/human-in-the-loop" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing Extensions
&lt;/h2&gt;

&lt;p&gt;Extensions are declared in the same &lt;code&gt;settings.json&lt;/code&gt; file. You can enable or disable individual extensions, pass them configuration values, and control exactly what the agent is capable of in a given project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"anthropic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"providers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"NeuronCore\\Maestro\\Extension\\CodingExtension"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"MyVendor\\DeployExtension\\DeployExtension"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"staging"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"api_key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-key"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disabling the &lt;code&gt;CodingExtension&lt;/code&gt; and enabling only your own extension turns Maestro into a completely different agent — one that knows nothing about code and everything about your specific domain. The runtime doesn’t change. The conversation loop, the tool approval flow, the event system — all of that stays exactly the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Packaging and Distributing Extensions
&lt;/h2&gt;

&lt;p&gt;Extensions are Composer packages. You write the code, define a composer.json with a dependency on &lt;code&gt;neuron-core/maestro&lt;/code&gt;, and add an &lt;code&gt;extra.maestro&lt;/code&gt; field that declares your extension class names:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-vendor/my-extension"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"require"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"neuron-core/maestro"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.0"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"extra"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"maestro"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"MyVendor&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;MyExtension&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;MyExtension"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"autoload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"psr-4"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"MyVendor\\MyExtension\\"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once a user installs your package with composer require &lt;code&gt;my-vendor/my-extension&lt;/code&gt;, running composer dump-autoload triggers auto-discovery. Maestro reads the extension class names from the extra field and registers them without the user needing to touch &lt;code&gt;settings.json&lt;/code&gt; at all, unless they want to configure or disable the extension explicitly.&lt;/p&gt;

&lt;p&gt;This is intentionally familiar territory for any PHP developer who has worked with Laravel packages or Symfony bundles. Ship a package, declare what it contributes, let the host framework discover and integrate it. The entire extension ecosystem lives on Packagist, installed and updated the same way every other PHP dependency in your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP Integration
&lt;/h2&gt;

&lt;p&gt;For extensions that need to reach beyond the local environment, Maestro supports Model Context Protocol servers in the configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mcp_servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tavily"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://mcp.tavily.com/mcp/?tavilyApiKey=your-key"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each entry spins up a subprocess and connects it to the agent as an additional tool source. This is how an extension targeting a GitHub workflow gives the agent the ability to read issues, open pull requests, and trigger CI runs — without you having to implement those integrations yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Demonstrates
&lt;/h2&gt;

&lt;p&gt;Maestro is a working proof that the patterns the rest of the industry has been building in Python and TypeScript are fully expressible in PHP. But more than that, it's a proof that the PHP ecosystem has the right primitives to build a platform, not just a tool.&lt;/p&gt;

&lt;p&gt;The extension system is what makes that distinction real. A coding agent is something you install and use. A platform with an extension system is something you build on, contribute to, and share through the package manager your entire community already uses. That's the version of the story I'm most excited about — not what Maestro does out of the box, but what it enables once developers start building on it.&lt;/p&gt;

&lt;p&gt;I'm really looking forward to hearing your feedback, experiments, and ideas on how to develop this new chapter of the AI ​​in the PHP space.&lt;/p&gt;

&lt;p&gt;If you want to explore the code, the repository is at &lt;a href="https://github.com/neuron-core/maestro" rel="noopener noreferrer"&gt;https://github.com/neuron-core/maestro&lt;/a&gt;. The Neuron AI documentation lives at &lt;a href="https://docs.neuron-ai.dev" rel="noopener noreferrer"&gt;https://docs.neuron-ai.dev&lt;/a&gt;. Questions, issues, and pull requests are open.&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>PHP’s Next Chapter: From Web Framework to Agent Framework</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Tue, 18 Nov 2025 11:06:11 +0000</pubDate>
      <link>https://dev.to/inspector/phps-next-chapter-from-web-framework-to-agent-framework-59p4</link>
      <guid>https://dev.to/inspector/phps-next-chapter-from-web-framework-to-agent-framework-59p4</guid>
      <description>&lt;p&gt;I've spent the last year building Neuron, a PHP framework designed specifically for agentic AI applications. What started as a technical challenge became something else entirely when developers began reaching out with stories I wasn't prepared to hear. They weren't asking about framework features or deployment strategies. They were telling me about losing their jobs.&lt;/p&gt;

&lt;p&gt;One senior developer had spent eight years at a fintech company, building and maintaining their entire backend infrastructure in PHP. The systems worked. The codebase was clean. Then the leadership decided to pivot toward AI-driven automation. Within six months, the entire PHP team was let go, replaced by Python engineers who could integrate LangChain and build agent workflows. He watched his expertise become irrelevant not because he wasn't skilled, but because the tools he knew couldn't participate in the conversation that mattered to his company's future.&lt;/p&gt;

&lt;p&gt;Here is the link to the post on the Neuron GitHub repository: &lt;a href="https://github.com/neuron-core/neuron-ai/discussions/156#discussioncomment-13436693" rel="noopener noreferrer"&gt;https://github.com/neuron-core/neuron-ai/discussions/156#discussioncomment-13436693&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2c94x4uhbc41b96vuju.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2c94x4uhbc41b96vuju.jpeg" alt="PHP developers ai jobs" width="800" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another engineer contacted me after his SaaS company made a similar shift. They didn't abandon PHP because it was slow or outdated. They abandoned it because when the CTO asked "can we build autonomous agents that handle customer support and data analysis", the answer from the PHP ecosystem was silence. No frameworks, no examples, no path forward. Python had entire conferences dedicated to agentic architectures while PHP developers were still arguing about whether type hints mattered.&lt;/p&gt;

&lt;p&gt;These aren't isolated incidents. I hear versions of this story regularly now, and what disturbs me most is how predictable it all was. The PHP community saw the AI wave coming and collectively decided it was someone else's problem. We kept optimizing for the web patterns we've always known, reassuring ourselves that "PHP powers a significant portion of the internet" as if market share from past decisions protects against future irrelevance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cost of Ignoring What's Actually Happening
&lt;/h2&gt;

&lt;p&gt;Some people dismiss AI development as a trend, a temporary excitement that will settle down and return us to familiar patterns. This perspective fundamentally misunderstands what's occurring. Agentic applications aren’t a feature being added to existing software. They represent a different approach to building systems entirely. Companies aren't experimenting with this because it's fashionable. They're adopting it because it changes their operational economics in ways that matter to survival.&lt;/p&gt;

&lt;p&gt;When a business realizes they can automate complex workflows that previously required multiple employees, they don't care about your framework preference or language loyalty. They care about implementation speed and ecosystem maturity to deploy effective solutions as soon as possible. If the only credible path to building these systems runs through Python, then Python is what they'll use. Your years of PHP expertise become a liability rather than an asset because you can’t deliver what the company needs to remain competitive.&lt;/p&gt;

&lt;p&gt;The PHP community's response to this has been inadequate bordering on negligent. We write articles titled "Why PHP is the Best Choice" that convince nobody because they address none of the actual questions people are asking. Nobody talk about how to build agentic applications that can interact with multiple APIs, maintain conversation context, and make autonomous decisions. They don't provide patterns for integrating language models into Laravel applications or handling the operation complexity that agent workflows require. They just repeat the same defensive talking points about PHP's web capabilities while the industry moves toward problems PHP developers claim they can't solve.&lt;/p&gt;

&lt;p&gt;This creates a self-fulfilling prophecy. PHP appears unsuitable for AI development because no one builds the tools to make it suitable. Talented developers leave for ecosystems that support their career growth. Companies hire outside the PHP community because we don't demonstrate competence in the areas they're investing in. Then we point to the exodus as evidence that maybe PHP really isn't meant for this kind of work, completing a cycle of irrelevance we constructed ourselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens When the Tools Finally Exist
&lt;/h2&gt;

&lt;p&gt;The developers who lost their positions didn't lack skill or intelligence. They were caught in an ecosystem that hadn't yet evolved with the problems businesses needed solved. But some of them found their way to Neuron and discovered something that changed their trajectory: PHP handles agentic applications naturally once you have the right enabling paltform in place. The language's mature capabilities, and large package ecosystem, provide exactly what these systems need.&lt;/p&gt;

&lt;p&gt;** What was missing wasn't potential but actual implementation.**&lt;/p&gt;

&lt;p&gt;These developers started building again. Not toy projects or proofs of concept, but production agentic systems handling real business logic. Customer service agents that resolve support tickets autonomously. Data analysis agents that generate insights from business metrics. Workflow automation that adapts to changing conditions without manual intervention.&lt;/p&gt;

&lt;p&gt;They're now demonstrating capabilities their previous employers assumed required abandoning PHP entirely. What changed was their access to tools designed for the problems they were solving. They didn't have to become Python developers or learn entirely new paradigms. They applied their existing PHP knowledge to agentic architectures using a framework that understood both domains. Their career trajectories shifted because PHP finally has a credible answer when someone asks about building intelligent, autonomous systems.&lt;/p&gt;

&lt;p&gt;The community forming around this work represents PHP's actual future, not its past. These developers understand that web frameworks were just the first chapter, and that the language's evolution doesn't end with serving HTTP requests. They're building the proof that PHP developers can lead in agentic development rather than watch from the sidelines. Every production agent they deploy, every autonomous workflow they implement, every business problem they solve with AI-driven systems reinforces that PHP belongs in this space.&lt;/p&gt;

&lt;p&gt;That gap is closing now, and the developers who bridge it first are positioning themselves at the front of PHP's next chapter. Your expertise in PHP doesn't have to be a limitation in an AI-driven industry. The tools exist now to take what you already know and apply it to the systems companies are actually building. The question isn’t whether PHP can participate in agentic development anymore. The question is whether you’ll be part of this revolution.&lt;/p&gt;

&lt;p&gt;Discover the new space Neuron is creating in the PHP ecosystem. Start developing your next application with Neuron-powered AI agents at &lt;strong&gt;&lt;a href="https://neuron-ai.dev" rel="noopener noreferrer"&gt;https://neuron-ai.dev&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>ai</category>
      <category>webdev</category>
      <category>neuron</category>
    </item>
    <item>
      <title>Storing LLM Context the Laravel Way: EloquentChatHistory in Neuron AI</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Fri, 07 Nov 2025 15:34:51 +0000</pubDate>
      <link>https://dev.to/inspector/storing-llm-context-the-laravel-way-eloquentchathistory-in-neuron-ai-545e</link>
      <guid>https://dev.to/inspector/storing-llm-context-the-laravel-way-eloquentchathistory-in-neuron-ai-545e</guid>
      <description>&lt;p&gt;I've spent the last few weeks working on one of the most important components of Neuron the Chat History. Most solutions treat conversation history in AI Agents forcing you to build everything from scratch. When I saw Laravel developers adopting Neuron AI, I realized they deserved better than that.&lt;/p&gt;

&lt;p&gt;The current implementation of the ChatHisotry already allows developers to store the agent context on file or in a general SQL table. The new EloquentChatHistory component changes how you manage LLM context in Laravel applications. Instead of fighting with custom storage solutions or maintaining parallel data structures, you now work with conversation history the same way you handle any other data in your application: through Eloquent models.&lt;/p&gt;

&lt;p&gt;It could be a starting point for future imporvements, so if you are working on Laravel and you think this integration can be improved feel free to let us know posting on the repository discussion. We are glad to receive any feedback. Other Laravel integrations can eventually be bundled into a dedicated integration package.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Your Laravel Projects
&lt;/h2&gt;

&lt;p&gt;When you're building AI features into a real application, context management quickly becomes a practical problem. You need to show conversation history in admin panels, filter chats by user or project, run background jobs that reference past interactions, or export data for analytics. With traditional approaches, you’re constantly translating between your AI framework's storage format and your application’s data layer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EloquentChatHistory&lt;/code&gt; want to mitigates or even eliminates that friction. Your chat history lives in your database as a proper Eloquent model, which means it integrates naturally with everything else in your Laravel ecosystem. Need to scope conversations by organization? Use query builders you already know. Building an admin panel with Filament or Nova? Your chat history is just another resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Neuron&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\ChatMessage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Agent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Chat\History\ChatHistoryInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Chat\History\EloquentChatHistory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyAgent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mf"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;chatHistory&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;ChatHistoryInterface&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EloquentChatHistory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'THREAD_ID'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;modelClass&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ChatMessage&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;contextWindow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50000&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component works with your existing database structure. You define the Eloquent model, specify which columns map to message roles and content, and Neuron handles the rest. It's a thin adapter that respects how Laravel developers actually work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Integration, Not Just Storage
&lt;/h2&gt;

&lt;p&gt;Your chat messages become first-class citizens in your application architecture. You can attach them to tickets, orders, or support conversations through standard Eloquent relationships. Background jobs can query relevant context without special handling. Your testing suite can seed and verify conversation flows using factories and assertions you already use for everything else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Eloquent\Model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatMessage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$fillable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'thread_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'role'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'content'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'meta'&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$casts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'content'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'array'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="s1"&gt;'meta'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'array'&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * The conversation that owns the chat message.
     *
     * @return BelongsTo&amp;lt;Conversation, $this&amp;gt;
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;BelongsTo&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;belongsTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Conversation&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'thread_id'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Starting Point, Not Final Destination
&lt;/h2&gt;

&lt;p&gt;I'm releasing EloquentChatHistory as a foundation you can build on. The implementation handles the common case: storing and retrieving messages with proper threading. But your application probably has specific requirements around metadata, search, etc. The component is designed to be extended, not prescribed.&lt;/p&gt;

&lt;p&gt;I'm particularly interested in seeing how the community extends this. The Neuron GitHub repository is where improvements and variations can evolve. If you build something useful on top of EloquentChatHistory , sharing that helps everyone building AI features in Laravel apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://docs.neuron-ai.dev/the-basics/chat-history-and-memory#eloquentchathisotry" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; walks through setup and configuration. You'll need to create a migration for your chat messages table, define your Eloquent model, and configure the field mappings. From there, it's standard Neuron AI workflow.&lt;/p&gt;

&lt;p&gt;Create the migration script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:migration create_chat_messages_table --create=chat_messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The schema below is the basic starting point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chat_messages'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'thread_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'role'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'content'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'meta'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

     &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'thread_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// For efficient ordering and trimming&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real test isn't whether EloquentChatHistory covers every edge case perfectly. It's whether it helps you move faster when building AI features in Laravel applications you already maintain. If you've been putting off adding AI capabilities because the integration overhead seemed too high, this might lower that barrier enough to start experimenting.&lt;/p&gt;

&lt;p&gt;Try it out, see what works for your use case, and let me know what could be better. The framework improves when people building real applications share what they learn.&lt;/p&gt;

&lt;p&gt;Subscribe to the &lt;a href="https://neuron-ai.dev" rel="noopener noreferrer"&gt;Neuron AI Newsletter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>laravel</category>
      <category>ai</category>
    </item>
    <item>
      <title>Building Multi-Agent Systems in Laravel – A Practical Demo</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Sat, 20 Sep 2025 13:44:15 +0000</pubDate>
      <link>https://dev.to/inspector/building-multi-agent-systems-in-laravel-a-practical-demo-ejh</link>
      <guid>https://dev.to/inspector/building-multi-agent-systems-in-laravel-a-practical-demo-ejh</guid>
      <description>&lt;p&gt;As PHP developers, we've watched the AI agent conversation happen around us rather than with us. While Python frameworks multiplied and JavaScript libraries emerged, PHP remained notably absent from the agentic application development landscape. The question isn’t whether PHP developers want to build intelligent applications—it's whether the tools exist to do it properly.&lt;/p&gt;

&lt;p&gt;The answer is increasingly yes, and a new Laravel travel planner application demonstrates exactly how accessible multi-agent development has become for PHP developers who prefer to stick with their existing expertise rather than retool their entire skillset.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Multi-Agent Architecture Challenge
&lt;/h2&gt;

&lt;p&gt;Building applications that coordinate multiple AI agents presents unique architectural challenges. Unlike single-agent systems that follow linear request-response patterns, multi-agent workflows require orchestration, state management, and coordination between different specialized components. Each agent needs to understand its role, communicate with others, and contribute to a larger objective without creating bottlenecks or conflicts.&lt;/p&gt;

&lt;p&gt;Traditional PHP applications handle these coordination patterns well—think about how Laravel’s job queues manage complex background processes or how service containers resolve dependencies. The missing piece has been frameworks that apply these familiar patterns to AI agent coordination.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Neuron's Workflow Component
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://docs.neuron-ai.dev/workflow/getting-started" rel="noopener noreferrer"&gt;Neuron framework's Workflow&lt;/a&gt; component addresses this gap by providing a structured approach to multi-agent orchestration that feels natural to PHP developers. Rather than forcing developers to learn entirely new paradigms, it builds on established patterns like dependency injection, event handling, and pipeline processing.&lt;/p&gt;

&lt;p&gt;A Workflow in Neuron defines how multiple agents collaborate to complete complex tasks. Each workflow consists of specialized nodes that handle specific responsibilities, with the framework managing communication and state between them. This approach separates concerns while maintaining the flexibility to handle dynamic, context-dependent decision making.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Travel Planner Agent: Multi-Agent Coordination in Practice
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkv05s9wt4em8m45rdpq.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkv05s9wt4em8m45rdpq.jpeg" alt="laravel ai agent schema" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The travel planner project demonstrates these concepts through a practical application that most developers can immediately understand. When a user requests travel recommendations, the system doesn’t rely on a single agent trying to handle flights, hotels, and attractions simultaneously. Instead, it coordinates specialized agents, each optimized for specific tasks.&lt;/p&gt;

&lt;p&gt;The architecture includes several key components:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TravelPlannerAgent&lt;/strong&gt; serves as the workflow orchestrator, managing the overall process and ensuring all components work together toward the final itinerary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Receptionist Node&lt;/strong&gt; handles initial user interaction, collecting destination preferences, dates, budget constraints, and other requirements. This separation ensures user input validation happens consistently, regardless of how complex the downstream processing becomes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Delegator Node&lt;/strong&gt; coordinates parallel research across three specialized areas—flights, hotels, and places to visit. Rather than processing these sequentially, the workflow can handle multiple research streams simultaneously, improving both performance and result quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GenerateItinerary Node&lt;/strong&gt; synthesizes all gathered information into a cohesive travel plan, ensuring recommendations work together rather than existing as isolated suggestions.&lt;/p&gt;

&lt;p&gt;This structure provides several advantages over monolithic approaches. Each agent can be developed, tested, and optimized independently. The system can scale specific components based on demand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Simplicity
&lt;/h2&gt;

&lt;p&gt;Despite the sophisticated coordination happening behind the scenes, the implementation remains straightforward for Laravel developers. The workflow definition looks familiar to anyone who has worked with Laravel's service providers or pipeline components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TravelPlannerAgent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Workflow&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @throws WorkflowException
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;ChatHistoryInterface&lt;/span&gt; &lt;span class="nv"&gt;$history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;?WorkflowState&lt;/span&gt; &lt;span class="nv"&gt;$state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;?PersistenceInterface&lt;/span&gt; &lt;span class="nv"&gt;$persistence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$workflowId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$persistence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$workflowId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Receptionist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Delegator&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Flights&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Hotels&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Places&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GenerateItinerary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each node handles its specific responsibility while the framework manages state transitions and inter-node communication. The result is code that’s both powerful and maintainable, without requiring developers to become experts in distributed systems or advanced AI orchestration patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring &amp;amp; Debugging
&lt;/h2&gt;

&lt;p&gt;When your application makes decisions based on LLM outputs and external API calls, understanding why specific choices were made becomes crucial for both debugging and optimization.&lt;/p&gt;

&lt;p&gt;The travel planner integrates with Inspector for comprehensive monitoring of agent interactions, decision points, and performance metrics. Feel free to try this experience, it's free and it can give you even more insights on how the system works behind the scenes.&lt;/p&gt;

&lt;p&gt;Just add the &lt;a href="https://inspector.dev/" rel="noopener noreferrer"&gt;Inspector&lt;/a&gt; ingestion key to your environment file and the agent will be automatically monitored:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSPECTOR_INGESTION_KEY=fwe45gtxxxxxxxxxxxxxxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Beyond Travel Planning
&lt;/h2&gt;

&lt;p&gt;While the travel planner serves as an accessible demonstration, the underlying patterns apply to numerous business applications. Content management systems could coordinate research agents, writing agents, and editorial agents to produce comprehensive articles. E-commerce platforms might coordinate inventory agents, pricing agents, and recommendation agents to optimize product suggestions.&lt;/p&gt;

&lt;p&gt;The key insight is that many complex business processes already involve coordination between specialized roles—Neuron’s Workflow component simply provides a framework for implementing these patterns helping AI agents collaborate with human operators.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;The travel planner project provides a complete, runnable example that developers can clone, configure, and modify for their own use cases. Setting up requires standard Laravel dependencies plus API keys for language models and external services like SerpAPI for travel data.&lt;/p&gt;

&lt;p&gt;Installation follows familiar Laravel patterns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer install

npm run build

php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configuration happens through environment variables, making it straightforward to swap different language models or external services without code changes.&lt;/p&gt;

&lt;p&gt;If you want to learn more about how to get started your AI journey in PHP check out the &lt;a href="https://docs.neuron-ai.dev/overview/fast-learning-by-video" rel="noopener noreferrer"&gt;learning section in the documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>php</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Monitoring Laravel Livewire Components</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Thu, 11 Sep 2025 16:07:40 +0000</pubDate>
      <link>https://dev.to/inspector/monitoring-livewire-components-2hfa</link>
      <guid>https://dev.to/inspector/monitoring-livewire-components-2hfa</guid>
      <description>&lt;p&gt;&lt;a href="https://livewire.laravel.com/" rel="noopener noreferrer"&gt;Livewire&lt;/a&gt; is a full-stack framework in Laravel that makes it easy to create reactive interfaces without writing any Javascript, just using PHP. This means developers can leverage the power of Laravel and Blade templates to build dynamic UIs. You can respond to user’s actions such as form submissions, scrolling, mouse movements, or button clicks, using PHP classes and methods.&lt;/p&gt;

&lt;p&gt;After the initial rendering of the page containing the Livewire component, Livewire binds some javascript event listeners to its components and watches for every action. Each action is sent to the server as an asynchronous API request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyqw8ysbmw3ks258f3tqn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyqw8ysbmw3ks258f3tqn.png" alt="Monitoring Laravel Livewire components" width="720" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;When the user clicks on a button in the UI, Livewire makes a network request to the server to interact with the PHP component associated. The server then performs the action, generates a new template and the current new state of the component, and sends it back to the client.&lt;/p&gt;

&lt;p&gt;Take a look at the example below that implement a simple counter:&lt;/p&gt;

&lt;p&gt;resources/views/livewire/counter.blade.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{{ $count }}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;wire:click=&lt;/span&gt;&lt;span class="s"&gt;"increment"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;+&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;wire:click=&lt;/span&gt;&lt;span class="s"&gt;"decrement"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;-&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;app/Livewire/Counter.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;decrement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'livewire.counter'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every click on the counter button generates an HTTP request handled by the associated PHP component. And this happen for all UI component you have in the user interface.&lt;/p&gt;

&lt;p&gt;All these HTTP requests are routed to the default Livewire URL: &lt;code&gt;/livewire/update&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's why you see tons of requests to the endpoint "POST /livewire/update" in your Inspector monitoring dashboard. So, everything under &lt;code&gt;/livewire/update&lt;/code&gt; it's like a grey area, because you don’t have any clue of what component is behing executed, what is its state, etc.&lt;/p&gt;

&lt;p&gt;This behaviour it’s also the reason many applications in performance sensible environments do not adopt this stack, and eventually go for a dedicated Javscript framework like Vue or React to manage reactivity entirely on the frontend side, offloading the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspector Trait
&lt;/h2&gt;

&lt;p&gt;To solve this problem the Inspector Laravel package includes the &lt;code&gt;LivewireInspector&lt;/code&gt; trait that you can attach to your Livewire PHP class.&lt;/p&gt;

&lt;p&gt;app/Livewire/Counter.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Inspector\Laravel\LivewireInspector&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;LivewireInspector&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;decrement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'livewire.counter'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A new transaction category, livewire, will now appear in the Inspector dashboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmhbqjazpt6jnos83asz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmhbqjazpt6jnos83asz.png" alt="Inspector Laravel Livewire component monitoring" width="800" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the transaction name is the name of the component class. This way, you’ll have all the components monitored individually.&lt;/p&gt;

&lt;p&gt;From the individual component’s detail page, you can access the history of every time that component has been run. Any exceptions will also be attached to the component’s transaction, so everything remains clear.&lt;/p&gt;

&lt;p&gt;Here the link to the documentation: &lt;a href="https://docs.inspector.dev/guides/laravel/livewire" rel="noopener noreferrer"&gt;https://docs.inspector.dev/guides/laravel/livewire&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitor your Laravel application for free
&lt;/h2&gt;

&lt;p&gt;Inspector is a Code Execution Monitoring tool specifically designed for PHP developers. You don't need to install anything on the server level, just install the &lt;a href="https://github.com/inspector-apm/inspector-laravel" rel="noopener noreferrer"&gt;Laravel package&lt;/a&gt; and you are ready to go.&lt;/p&gt;

&lt;p&gt;If you are looking for HTTP monitoring, database query insights, and the ability to forward alerts and notifications into your preferred messaging environment try Inspector for free. &lt;a href="https://app.inspector.dev/register" rel="noopener noreferrer"&gt;Register your account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Or learn more on the website: &lt;a href="https://inspector.dev" rel="noopener noreferrer"&gt;https://inspector.dev/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp6vz2so94ybstsj79p26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp6vz2so94ybstsj79p26.png" alt="Inspector Laravel Monitoring" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>webdev</category>
      <category>livewire</category>
    </item>
    <item>
      <title>Keeping Your AI Agents Under Control: Tool Max Tries in Neuron V2</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Mon, 08 Sep 2025 08:20:28 +0000</pubDate>
      <link>https://dev.to/inspector/keeping-your-ai-agents-under-control-tool-max-tries-in-neuron-v2-5m7</link>
      <guid>https://dev.to/inspector/keeping-your-ai-agents-under-control-tool-max-tries-in-neuron-v2-5m7</guid>
      <description>&lt;p&gt;When you're building AI agents in PHP, one question keeps surfacing in production environments: what happens when your agent gets stuck in a loop? Whether it's an external API that's down, an LLM that's having an off day, or a tool that's returning unexpected responses, runaway tool calls can quickly turn a helpful agent into a resource-draining problem.&lt;/p&gt;

&lt;p&gt;Neuron V2 introduces &lt;a href="https://docs.neuron-ai.dev/getting-started/tools#max-tries" rel="noopener noreferrer"&gt;Tool Max Tries&lt;/a&gt;, a straightforward guardrail that puts you back in control of your agent's behavior. This feature sets a hard limit on how many times an agent can invoke any single tool during a conversation, preventing the cascading failures that can occur when AI reasoning goes sideways.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: When AI Gets Stuck
&lt;/h2&gt;

&lt;p&gt;Picture this scenario: you've built an agent that helps customers track their orders. It uses a GetOrderStatus tool to fetch information from your backend API. Everything works perfectly in testing, but in production, your API occasionally returns a 500 error. Instead of gracefully handling the failure, your agent decides the best course of action is to keep trying the same tool call, over and over.&lt;/p&gt;

&lt;p&gt;Without proper constraints, you might see something like this in your logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2024-09-04 10:15:23] Tool call: getOrderStatus(order_id: 12345)
[2024-09-04 10:15:24] API Error: Internal Server Error
[2024-09-04 10:15:25] Tool call: getOrderStatus(order_id: 12345)
[2024-09-04 10:15:26] API Error: Internal Server Error
[2024-09-04 10:15:27] Tool call: getOrderStatus(order_id: 12345)
// ... continues indefinitely
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't just annoying—it's dangerous. Each failed tool call still consumes tokens, and if you're paying per API call to your LLM provider, those costs add up quickly. More importantly, it creates a terrible user experience as customers wait for responses that never come.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple but Effective Solution
&lt;/h2&gt;

&lt;p&gt;Tool Max Tries addresses this by letting you set a maximum number of attempts for each tool in your agent's toolkit. Here's how you configure it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;YouTubeAgent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toolMaxTries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Max number of calls for each tool&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="c1"&gt;// It takes precedence over the global setting&lt;/span&gt;
            &lt;span class="nc"&gt;GetOrderStatus&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setMaxTries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ToolMaxTriesException&lt;/span&gt; &lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// do something&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default the limit is 5 calls, and it count for each tool individually. You can customize this value with the &lt;code&gt;toolMaxTries()&lt;/code&gt; method at agent level, or use setMaxTries() on the tool level. Setting max tries on single tool takes precedence over the global setting.&lt;/p&gt;

&lt;p&gt;Now when your agent encounters that problematic API, it will attempt the call up to three times before giving up and informing the user that the service is currently unavailable. The conversation continues, but within reasonable bounds.&lt;/p&gt;

&lt;p&gt;You can also apply this configuration for tools included in toolkit using the with method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyAgent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mf"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="nc"&gt;MySQLToolkit&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nc"&gt;MySQLSchemaTool&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ToolInterface&lt;/span&gt; &lt;span class="nv"&gt;$tool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$tool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setMaxTries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Setting up Tool Max Tries is straightforward, and you can configure different limits for different tools based on their risk profiles and expected behavior. A tool that performs simple calculations might never need retries, while one that calls external APIs might benefit from two or three attempts.&lt;/p&gt;

&lt;p&gt;The beauty of this approach is that it's opt-in and granular. You can set limits only where you need them, and adjust them based on your actual usage patterns. If you find that five attempts aren't enough for a particular tool, you can increase the limit. If you want to be more aggressive about preventing loops, you can set it to one or two. &lt;/p&gt;

&lt;p&gt;The framework handles the operational complexities while letting you focus on solving business problems.&lt;/p&gt;

&lt;p&gt;If you want to learn more about how to get started your AI journey in PHP check out the learning section in the documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring &amp;amp; Debugging
&lt;/h2&gt;

&lt;p&gt;Many of the Agents you build with Neuron will contain multiple steps with multiple invocations of LLM calls, tool usage, access to external memories, etc. As these applications get more and more complex, it becomes crucial to be able to inspect what exactly your agent is doing and why.&lt;/p&gt;

&lt;p&gt;The Deep Research Agent integrates with &lt;a href="https://inspector.dev" rel="noopener noreferrer"&gt;Inspector&lt;/a&gt; for comprehensive observability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSPECTOR_INGESTION_KEY=fwe45gtxxxxxxxxxxxxxxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This monitoring reveals the complete execution timeline, showing which agents made decisions, how long each phase took, and where any issues occurred. For multi-agent systems, this visibility proves essential for optimization and debugging.&lt;/p&gt;

</description>
      <category>php</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Neuron V2 – Is PHP Ready For Agentic Application Development?</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Thu, 04 Sep 2025 09:15:51 +0000</pubDate>
      <link>https://dev.to/inspector/neuron-v2-is-php-ready-for-agentic-application-development-nn9</link>
      <guid>https://dev.to/inspector/neuron-v2-is-php-ready-for-agentic-application-development-nn9</guid>
      <description>&lt;p&gt;Since the beginning of my journey building Neuron I challenged myself with a simple question: "Is PHP ready for agentic application development?" &lt;/p&gt;

&lt;p&gt;For months, developers have been asking whether they need to switch to Python to build production-grade AI systems, or if they can leverage their existing PHP expertise. More and more discussions have been &lt;a href="https://github.com/inspector-apm/neuron-ai/discussions" rel="noopener noreferrer"&gt;posted in the forum&lt;/a&gt; about coordinating multiple agents or how to implement complex scenarios.&lt;/p&gt;

&lt;p&gt;Neuron v2 provides a definitive answer. This release fundamentally changes how PHP developers can approach complex AI workflows, introducing an event-driven architecture that makes building sophisticated agentic systems both practical and performant.&lt;/p&gt;

&lt;p&gt;If you are curious about the beginning of this journey you can read the article of the first launch:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://inspector.dev/introduction-to-neuron-ai-create-full-featured-ai-agents-in-php/" rel="noopener noreferrer"&gt;https://inspector.dev/introduction-to-neuron-ai-create-full-featured-ai-agents-in-php/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrade guide
&lt;/h2&gt;

&lt;p&gt;Before moving forward you can bookmark the Upgrade guide on the documentation to learn more about the latest changes, and how they impact your application upgrading your implementations to V2: &lt;a href="https://docs.neuron-ai.dev/overview/readme/upgrade-guide" rel="noopener noreferrer"&gt;https://docs.neuron-ai.dev/overview/readme/upgrade-guide&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changes in Neuron V2
&lt;/h2&gt;

&lt;p&gt;Aside from removing "AI" from the name, the core advancement in v2 centers around a complete rearchitecture of the Workflow system. In v1 Workflow was marked as experimental. The previous implementation relied on a combination of nodes and edges to define the path workflow must follow to navigate through nodes. V2 introduces an event-driven model that uses only nodes as entities that handle incoming events and emit other events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Neuron&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Workflow\Node&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Workflow\StartEvent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Workflow\WorkflowState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InitialOne&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;StartEvent&lt;/span&gt; &lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;WorkflowState&lt;/span&gt; &lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;FirstEvent&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'node_one_executed'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FirstEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'First complete'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shift &lt;strong&gt;eliminates the Edge class entirely&lt;/strong&gt; and opens up possibilities that weren’t feasible with the graph-like workflows. Nodes now trigger and respond to events, creating dynamic execution paths based on runtime conditions rather than predetermined sequences. It’s very easy now to create and maintain workflows with loops and braches. Here is an example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.neuron-ai.dev/workflow/loops-and-branches" rel="noopener noreferrer"&gt;https://docs.neuron-ai.dev/workflow/loops-and-branches&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-Time Streaming in multi-agent systems
&lt;/h2&gt;

&lt;p&gt;The most immediate impact developers can notice is streaming capability. V2 workflows can stream intermediate results to clients in real-time, transforming user experience from "loading…" states to live progress updates even in multi-agent systems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$workflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Workflow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$workflow&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addNodes&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodeOne&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodeTwo&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodeForSecond&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Draw the workflow graph&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$workflow&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$workflow&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;streamEvents&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;ProgressEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;- &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$finalState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getResult&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// It should print "Second complete"&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$finalState&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'final_second_message'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out this example: &lt;a href="https://github.com/inspector-apm/neuron-ai/blob/2.x/examples/workflow/workflow-stream.php" rel="noopener noreferrer"&gt;https://github.com/inspector-apm/neuron-ai/blob/2.x/examples/workflow/workflow-stream.php&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This streaming architecture means users see planning complete, watch research queries execute, and observe content generation happen step by step. For applications where users need to understand what the AI system is doing, this visibility builds confidence in the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Human-in-the-Loop Without Complexity
&lt;/h2&gt;

&lt;p&gt;One of the most practical features v2 reinforced is seamless human intervention. Workflows can pause execution, request human input, and resume exactly where they stopped. This capability makes AI systems viable for sensitive business processes where human oversight is required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$persistence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FilePersistence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$workflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Workflow&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WorkflowState&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$persistence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'test_workflow'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addNodes&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodeOne&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InterruptableNode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodeForSecond&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Draw the workflow graph&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$workflow&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Run the workflow and catch the interruption&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$finalState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$workflow&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getResult&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WorkflowInterrupt&lt;/span&gt; &lt;span class="nv"&gt;$interrupt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Verify interrupt was saved&lt;/span&gt;
    &lt;span class="nv"&gt;$savedInterrupt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$persistence&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'test_workflow'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Workflow interrupted at "&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$savedInterrupt&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getCurrentNode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Resume the workflow providing external data&lt;/span&gt;
&lt;span class="nv"&gt;$finalState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$workflow&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'approved'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getResult&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// It should print "approved"&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$finalState&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'received_feedback'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out this example: &lt;a href="https://github.com/inspector-apm/neuron-ai/blob/2.x/examples/workflow/workflow-interrupt.php" rel="noopener noreferrer"&gt;https://github.com/inspector-apm/neuron-ai/blob/2.x/examples/workflow/workflow-interrupt.php&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The workflow state persists during these pauses, meaning the system can wait hours or days for human feedback before continuing. This persistence enables complex approval processes that span multiple stakeholders and time zones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance at the Foundation
&lt;/h2&gt;

&lt;p&gt;Under the hood, v2 addresses performance from the ground up. Large dataset iterations automatically chunk data, file access uses generators for better performance and memory management, and the strong type system helps PHP’s engine optimize reference lookups.&lt;/p&gt;

&lt;p&gt;These optimizations aren't visible in the API but it makes PHP applications handling large AI workloads with easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Neuron CLI – Enhanced Developer Tools
&lt;/h2&gt;

&lt;p&gt;V2 ships with practical developer experience improvements that address common friction points. The CLI tool brings the new "make" command that helps you scaffold common classes reducing boilerplate fatigue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php vendor/bin/neuron make:agent App\\Neuron\\MyAgent

php vendor/bin/neuron make:rag App\\Neuron\\MyChatBot

php vendor/bin/neuron make:workflow App\\Neuron\\MyWorkflow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Seeing It in Action – Deep Research Agent
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/neuron-core/deep-research-agent" rel="noopener noreferrer"&gt;deep-research-agent&lt;/a&gt; demo project demonstrates these capabilities in practice. This implementation creates comprehensive research reports by orchestrating multiple AI services through an event-driven workflow that includes planning, research, content generation, and formatting phases.&lt;/p&gt;

&lt;p&gt;The demo shows how complex agentic workflows can remain readable and maintainable while handling real-world requirements like API calls, result aggregation, and structured output formatting. Developers can examine the complete workflow implementation and see how each node contributes to the overall process.&lt;/p&gt;

&lt;p&gt;Check out the GitHub repository &amp;gt;&amp;gt; &lt;a href="https://github.com/neuron-core/deep-research-agent" rel="noopener noreferrer"&gt;https://github.com/neuron-core/deep-research-agent&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Is PHP Ready For Agentic Application Development?
&lt;/h2&gt;

&lt;p&gt;The release of Neuron V2 makes me feel one step closer toward answering whether PHP is ready for serious agentic application development. The event-driven architecture, streaming capabilities, and production-focused performance optimizations create a foundation for building AI systems that can compete with implementations in other languages.&lt;/p&gt;

&lt;p&gt;For teams with substantial PHP expertise, v2 removes the primary arguments for switching to Python for AI development. Complex agentic workflows are now feasible within the PHP ecosystem, using familiar patterns and deployment infrastructure.&lt;/p&gt;

&lt;p&gt;The framework maintains a general backward compatibility while introducing advanced capabilities. Teams can adopt v2 features without requiring full rewrites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started With Neuron
&lt;/h2&gt;

&lt;p&gt;The most effective way to understand v2's capabilities is to experiment with the Deep Research Agent at &lt;a href="https://github.com/neuron-core/deep-research-agent" rel="noopener noreferrer"&gt;https://github.com/neuron-core/deep-research-agent&lt;/a&gt;. This implementation demonstrates real-world workflow patterns and provides a starting point for building custom agentic systems.&lt;/p&gt;

&lt;p&gt;For developers ready to explore how quickly ideas can become working applications, Neuron v2 offers the tools to turn concepts into production-ready AI systems without leaving the PHP ecosystem. The question isn't whether PHP is ready for agentic development anymore – it's what you’ll build with it.&lt;/p&gt;

&lt;p&gt;Check out the official &lt;a href="https://docs.neuron-ai.dev/v2" rel="noopener noreferrer"&gt;Neuron Documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>php</category>
      <category>webdev</category>
    </item>
    <item>
      <title>AI Coding Agents Meet Production Environment with the Inspector MCP Server</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Wed, 27 Aug 2025 13:29:25 +0000</pubDate>
      <link>https://dev.to/inspector/ai-coding-agents-meet-production-environment-with-the-inspector-mcp-server-1cka</link>
      <guid>https://dev.to/inspector/ai-coding-agents-meet-production-environment-with-the-inspector-mcp-server-1cka</guid>
      <description>&lt;p&gt;Software development has undergone a profound transformation in the past two years, one that even the most forward-thinking developers didn't anticipate. Coding assistants have evolved from experimental curiosities to powerful development partners, fundamentally changing how we approach problem-solving, debugging, and architectural decisions.&lt;/p&gt;

&lt;p&gt;I've witnessed this evolution firsthand, initially approaching AI coding tools with the healthy skepticism that comes from a navigated software engineer. However, after integrating Claude Code into my daily workflow, I've experienced a productivity leap that genuinely surprised me. The ability to delegate complex refactoring tasks, explore alternative architectural approaches, and receive intelligent suggestions for optimization has transformed my development process in ways that traditional tooling never achieved.&lt;/p&gt;

&lt;p&gt;This experience sparked the idea to create the Inspector MCP server to allow these programming assistants to access production errors and monitoring data in real-time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Context Gap in AI-Assisted Development
&lt;/h2&gt;

&lt;p&gt;Yet this transformation has revealed a critical gap that becomes apparent only when you actually try AI assistance for coding. They can analyze code, but they remain blind to the runtime behavior that ultimately determines application success or failure. A coding assistant might suggest elegant solutions to theoretical problems while remaining completely unaware that your production system is currently experiencing a cascade of database timeouts that renders those suggestions irrelevant.&lt;/p&gt;

&lt;p&gt;Error patterns that emerge in production often reveal architectural assumptions that seemed reasonable during development but prove problematic at scale. Performance bottlenecks frequently manifest in ways that static code analysis, however sophisticated, simply cannot predict.&lt;/p&gt;

&lt;p&gt;As the creator of Inspector, I've spent years building observability solutions that help developers understand their applications' runtime behavior. This perspective has made the gap between AI coding assistance and production awareness particularly stark. Developers using advanced AI tools were still context-switching between their development environment and monitoring dashboards, manually correlating code suggestions with production telemetry. The inefficiency was obvious, but more importantly, it represented a missed opportunity for truly integrated development workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bridging Development and Production with MCP
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/inspector-apm/mcp-server" rel="noopener noreferrer"&gt;Inspector MCP Server&lt;/a&gt; emerged from this recognition that AI coding assistants need production context to reach their full potential. By implementing the Model Context Protocol, we've created a bridge that allows AI agents to access real-time error data, performance metrics, and system behavior directly from Inspector's monitoring infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/inspector-apm/mcp-server" rel="noopener noreferrer"&gt;https://github.com/inspector-apm/mcp-server&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From a practical standpoint, the Inspector MCP Server enables workflows that were previously impossible. Developers can now ask their AI assistant to analyze recent production errors, identify common failure patterns, and suggest preventive measures based on actual error frequencies and contexts. Performance optimization becomes a collaborative process where AI analysis combines with real telemetry to identify bottlenecks and propose solutions. Error triage transforms from manual investigation to intelligent analysis that can rapidly distinguish between critical issues requiring immediate attention and noise that can be addressed systematically.&lt;/p&gt;

&lt;p&gt;This production-aware approach becomes even more compelling when combined with the broader ecosystem we've built around Inspector and the Neuron AI framework. PHP developers have historically been underserved in the AI tooling space, despite PHP powering the majority of web applications. The combination of Inspector's observability capabilities, Neuron's AI agent framework, and now the MCP server creates an integrated development experience specifically designed for the PHP ecosystem’s unique characteristics and deployment patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started with Inspector MCP server
&lt;/h2&gt;

&lt;p&gt;You can install the server as a dev-dependency in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require inspector-apm/mcp-server --dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to provide the MCP client with the configuration to connect to this server and use the tools. The MCP client is your coding assistant like Claude Code, Gemini Code Assist, or an agentic IDE like Jetbrains, Visual Studio Code, Cursor, or similar.&lt;/p&gt;

&lt;p&gt;This is the configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inspector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"php"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"absolute-path-to-your-app-vendor-folder/inspector-apm/mcp-server/server.php"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"INSPECTOR_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XXX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"INSPECTOR_APP_ID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XXX"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need three information to complete this configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Absolute path of the vendor folder&lt;/strong&gt;: This is the root path where the vendor folder of your project is located in your computer. The next part is the path to point to the file that runs the MCP server (&lt;code&gt;inspector-apm/mcp-server/server.php&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;INSPECTOR_API_KEY&lt;/strong&gt;: Click Here to generate a new API key&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;INSPECTOR_APP_ID&lt;/strong&gt;: This is the unique identifier of your application inside Inspector. You can get this information in the Application Settings menu in the &lt;a href="https://inspector.dev/register" rel="noopener noreferrer"&gt;Inspector dashboard&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Claude Code Configuration&lt;br&gt;
Once you have the information above you can connect the Inspector MCP server to Claude Code with the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;claude mcp add inspector --env INSPECTOR_API_KEY=YOUR_KEY --env INSPECTOR_APP_ID=YOUR_APP_ID -- php [absolute_path_to_your_app_vendor_folder]/inspector-apm/mcp-server/server.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For other agents check out their documentation on how to connect to local (STDIO) MCP servers.&lt;/p&gt;

&lt;p&gt;Now you can ask a simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hey Claude, what happened overnight in the production environment?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Transforming Development Workflows
&lt;/h2&gt;

&lt;p&gt;The timing of this integration reflects a broader maturation in how we think about AI-assisted development. Sustainable productivity gains require deeper integration with the entire development lifecycle.&lt;/p&gt;

&lt;p&gt;Consider the qualitative difference this integration creates. Instead of an AI assistant suggesting generic solutions to abstract problems, it can now analyze actual production errors with full context about frequency, impact, and environment conditions. When debugging becomes a collaborative process between developer intuition and AI analysis backed by real telemetry data, the speed and accuracy of problem resolution can improve dramatically. The assistant can identify patterns across multiple errors, correlate issues with recent deployments, and suggest targeted fixes based on actual system behavior rather than theoretical best practices.&lt;/p&gt;

&lt;p&gt;As AI coding assistants continue to evolve, their effectiveness will increasingly depend on access to the contextual information that production systems provide. The Inspector MCP Server establishes this foundation for the PHP ecosystem.&lt;/p&gt;

&lt;p&gt;The future of AI-assisted development lies not in more sophisticated code generation, but in more intelligent integration with the complete software lifecycle. By bridging the gap between development environment and production telemetry, we're enabling a new class of development workflows where artificial intelligence becomes truly valuable for real-world application development and maintenance.&lt;/p&gt;

&lt;p&gt;Connect Inspector with your coding agent now: &lt;a href="https://github.com/inspector-apm/mcp-server" rel="noopener noreferrer"&gt;https://github.com/inspector-apm/mcp-server&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>ai</category>
      <category>webdev</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Introducing NeuronAI Workflow: The future of agentic PHP applications</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Fri, 04 Jul 2025 14:38:04 +0000</pubDate>
      <link>https://dev.to/inspector/introducing-neuronai-workflow-the-future-of-agentic-php-applications-24pe</link>
      <guid>https://dev.to/inspector/introducing-neuronai-workflow-the-future-of-agentic-php-applications-24pe</guid>
      <description>&lt;p&gt;Three months ago, when I started building the Workflow component for NeuronAI, I knew it would be complex. What I didn't anticipate was that it would become the most technically challenging development of my entire career—alongside Neuron itself.&lt;/p&gt;

&lt;p&gt;The core challenge wasn't just about creating another workflow engine. It was about enabling true human-in-the-loop patterns while maintaining clean architecture, readable code organization, and building on interoperable components that developers could easily extend and interchange—especially the persistence layer.&lt;/p&gt;

&lt;p&gt;Sounds interesting? Support the project starring the GitHub repository: &lt;a href="https://github.com/inspector-apm/neuron-ai" rel="noopener noreferrer"&gt;https://github.com/inspector-apm/neuron-ai&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Workflow
&lt;/h2&gt;

&lt;p&gt;Think of a Workflow as a smart flowchart that describes how your AI applications should work. Instead of your AI making every decision independently, a Workflow lets you create a step-by-step process where AI handles what it does best, and humans step in when judgment or oversight is needed.&lt;/p&gt;

&lt;p&gt;Here's what makes NeuronAI Workflows special: they're built around interruption and human-in-the-loop capabilities. This means your agentic system can pause mid-process, ask for human input, wait for feedback, and then continue exactly where it left off – even if that’s hours or days later.&lt;/p&gt;

&lt;p&gt;Imagine you're building a content moderation system. Instead of having AI make final decisions about borderline content, your Workflow can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analyze the content using AI&lt;/li&gt;
&lt;li&gt;Flag anything uncertain&lt;/li&gt;
&lt;li&gt;Pause and ask a human moderator for review&lt;/li&gt;
&lt;li&gt;Wait for the human decision&lt;/li&gt;
&lt;li&gt;Continue processing based on that feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key breakthrough is that interruption isn't a bug – it's a feature. Your Workflow remembers exactly where it stopped, what data it was working with, and what question it needs answered.&lt;/p&gt;

&lt;p&gt;Why Use NeuronAI Workflow Instead of Regular Scripts?&lt;br&gt;
You might be thinking: "This sounds great, but why can't I just write a regular PHP script with some if-statements and functions?" It's a fair question, and one I heard a lot while building NeuronAI. The answer becomes clear when you consider what happens when your process needs to pause, wait, and resume exactly where it left off.&lt;/p&gt;

&lt;p&gt;Another scenario that is practically impossible to reproduce with a procedural approach is when you need complex workflows with many branches, several loops and intermediate checkpoints, etc. When you are at the beginning of a project and your use case is yet quite simple, it’s not easy to see the real potential of Workflow, and it’s normal. Keep in mind that if things hit the fan, NeuronAI already has a solution to help you scale.&lt;/p&gt;

&lt;p&gt;Create a Workflow&lt;br&gt;
A Workflow in NeuronAI is made up of two elements:&lt;/p&gt;

&lt;p&gt;Nodes, with each node responsible for handling a unit of execution (manipulate data, call an agent, etc.).&lt;/p&gt;

&lt;p&gt;Edges, responsible to define how the workflow must move from one node to the next. They can be conditional branches or fixed transitions.&lt;/p&gt;

&lt;p&gt;In short: Nodes do the work, Edges tell what to do next.&lt;/p&gt;

&lt;p&gt;As an illustrative example, let’s consider a simple workflow with two nodes. The connection (Edge) tells the workflow to go from A to B to C.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Neuron\Workflow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Neuron\Workflow\InitialNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Neuron\Workflow\MiddleNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Neuron\Workflow\FinishNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Workflow\Edge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Workflow\Workflow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleWorkflow&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Workflow&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InitialNode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MiddleNode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FinishNode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="c1"&gt;// Tell the workflow to go to MiddleNode after InitialNode&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InitialNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MiddleNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

            &lt;span class="c1"&gt;// Tell the workflow to go to FinishNode after MiddleNode&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MiddleNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;FinishNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;InitialNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="nc"&gt;FinishNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fle4csjfxy7udtivqbprm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fle4csjfxy7udtivqbprm.png" alt="AI Agent workflow php" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learn all this concept in details on the documentation: &lt;a href="https://docs.neuron-ai.dev/workflow/getting-started" rel="noopener noreferrer"&gt;https://docs.neuron-ai.dev/workflow/getting-started&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Workflow Structure: Nodes and Edges
&lt;/h2&gt;

&lt;p&gt;Before diving into the interruption capabilities, it's important to understand how Workflows are structured. Think of a Workflow as a graph made up of two key components: &lt;strong&gt;nodes&lt;/strong&gt; and &lt;strong&gt;edges&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;**Nodes **are where the actual work happens – they're like individual functions or operations in your Workflow. A node might analyze text, make an API call, process data, or request human input. Each node has a specific job and produces some output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edges&lt;/strong&gt; are the connections between nodes – they define the flow of your Workflow. But here's where NeuronAI gets interesting: edges aren't just simple arrows pointing from one node to the next. They can be conditional, and make decisions about where to route your data based on conditions, outcomes, or even dynamic logic.&lt;/p&gt;

&lt;p&gt;For example, imagine a content moderation Workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An analysis node examines a piece of content&lt;/li&gt;
&lt;li&gt;Multiple edges lead out from this node: one for "clearly safe content," another for "clearly problematic content", and a third for "needs human review"&lt;/li&gt;
&lt;li&gt;The edge that gets taken depends on the confidence level of the AI analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means your Workflow can automatically branch into different paths based on real-time conditions. An edge might route high-confidence decisions straight to approval, while routing uncertain cases through human review nodes. You can even have edges that loop back to previous nodes, creating iterative processes where content gets refined through multiple rounds of AI analysis and human feedback.&lt;/p&gt;

&lt;p&gt;The real power comes from conditional edges – connections that evaluate the output of a node and decide which path to take next. This lets you build sophisticated decision trees where the Workflow adapts its behavior based on what it discovers along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Human In The Loop
&lt;/h2&gt;

&lt;p&gt;NeuronAI Workflows flip this paradigm. Instead of building AI systems that try to be perfect, you build systems that are intelligently imperfect. They know their limitations and actively seek help when they need it.&lt;/p&gt;

&lt;p&gt;Here's how it works technically:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interruption Points&lt;/strong&gt;: Any node in your Workflow can request an interruption by specifying what kind of human input it needs. This could be a simple yes/no decision, a content review, data validation, or creative input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State Preservation&lt;/strong&gt;: When an interruption happens, NeuronAI automatically saves the complete state of your Workflow – all variables, processed data, and context. Your Workflow essentially goes to sleep, waiting for human input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resume Capability&lt;/strong&gt;: Once a human provides the requested input, the Workflow wakes up exactly where it left off. No data is lost, no context is forgotten. It's like the AI was never paused at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;External Feedback Integration&lt;/strong&gt;: The human input becomes part of the Workflow's data, available to all subsequent nodes. This means later steps can make better decisions based on both AI analysis and human judgment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$persistence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FilePersistence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$workflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Workflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$persistence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'test_workflow'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$workflow&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addNodes&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BeforeInterruptNode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InterruptNode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AfterInterruptNode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addEdges&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BeforeInterruptNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;InterruptNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterruptNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AfterInterruptNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BeforeInterruptNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setEnd&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nc"&gt;AfterInterruptNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$workflow&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WorkflowState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'value'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WorkflowInterrupt&lt;/span&gt; &lt;span class="nv"&gt;$interrupt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Catch interruption as a normal exception&lt;/span&gt;

    &lt;span class="c1"&gt;// Verify interrupt signal was saved&lt;/span&gt;
    &lt;span class="nv"&gt;$savedInterrupt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$persistence&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'test_workflow'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Workflow interrupted at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$savedInterrupt&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getCurrentNode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Resume passing the human feedback&lt;/span&gt;
&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$workflow&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;resume&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'approved'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'final_value'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Beyond One Shot Interactions
&lt;/h2&gt;

&lt;p&gt;Single AI Agents work like this: you give them input, they process it using their tools or external information, and they give you output. That's it. If the AI makes a mistake, you only find out after the fact.&lt;/p&gt;

&lt;p&gt;Working on NeuronAI, we've seen developers struggle with this limitation. They’d build sophisticated agents, but couldn't deploy them in high-stakes situations because there was no safety net. No way to verify output before they mattered. No way to inject human feedback when the Agent reached the limits of its abilities.&lt;/p&gt;

&lt;p&gt;Traditional approaches to solving this usually involve building separate review systems, complex approval processes, or having humans check everything after the fact. These solutions are clunky, expensive, and often too slow for real-world applications.&lt;/p&gt;

&lt;p&gt;From a developer perspective, NeuronAI Workflow solves several painful problems:&lt;/p&gt;

&lt;p&gt;Model and maintain complex iterations: With these simple building blocks you will be able to create simple processes with a few steps, up to complex workflows with iterative loops and intermediate checkpoints.&lt;/p&gt;

&lt;p&gt;Human in the Loop: Seamlessly incorporate human oversight. You can deploy AI in sensitive areas because humans are always in the loop for critical decisions.&lt;/p&gt;

&lt;p&gt;Debugging with inspector: Instead of wondering why your AI made a particular decision, you can see exactly how humans and AI collaborated at each step.&lt;/p&gt;

&lt;p&gt;User Trust: When users know a human reviewed important decisions, they’re more likely to trust and adopt your AI system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future of AI Development
&lt;/h2&gt;

&lt;p&gt;Creating the NeuronAI Workflow component has convinced me that the future of AI isn’t about building systems that never need human help. It's about building systems that know exactly when and how to ask for help.&lt;/p&gt;

&lt;p&gt;Instead of trying to replace human judgment, we're amplifying it. Instead of fearing AI mistakes, we’re building systems that catch and correct them in real-time.&lt;/p&gt;

&lt;p&gt;The most successful AI applications of the next decade won’t be the ones that are most autonomous. They'll be the ones that are most collaborative – seamlessly blending artificial intelligence with human wisdom, creativity, and oversight.&lt;/p&gt;

&lt;p&gt;NeuronAI Workflows it's the first step to make this collaboration not just possible, but efficient, all in PHP. &lt;/p&gt;

&lt;p&gt;The best part? Your users will trust these systems more because they'll know a human was involved in the important decisions. And you'll sleep better at night knowing your AI can't make critical mistakes without human oversight.&lt;/p&gt;

&lt;p&gt;That's the power of building AI systems that know when to ask for help. Build the future of intelligent PHP applications with NeuronAI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;If you are getting started with AI Agents, or you simply want to elevate your skills to a new level here is a list of resources to help you go in the right direction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How to create a RAG Agent&lt;/strong&gt;: &lt;a href="https://inspector.dev/how-to-create-a-rag-agent-with-neuron-adk-for-php/" rel="noopener noreferrer"&gt;https://inspector.dev/how-to-create-a-rag-agent-with-neuron-adk-for-php/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Introducing Toolkits: Composable AI Agent Capabilities In PHP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Newsletter&lt;/strong&gt;: &lt;a href="https://neuron-ai.dev" rel="noopener noreferrer"&gt;https://neuron-ai.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E-Book (Start With AI Agents In PHP)&lt;/strong&gt;: &lt;a href="https://www.amazon.com/dp/B0F1YX8KJB" rel="noopener noreferrer"&gt;https://www.amazon.com/dp/B0F1YX8KJB&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>Vector Store &amp; AI Agents – Beyond The Traditional Data Storage</title>
      <dc:creator>Valerio</dc:creator>
      <pubDate>Fri, 04 Jul 2025 08:30:31 +0000</pubDate>
      <link>https://dev.to/inspector/vector-store-ai-agents-beyond-the-traditional-data-storage-56c4</link>
      <guid>https://dev.to/inspector/vector-store-ai-agents-beyond-the-traditional-data-storage-56c4</guid>
      <description>&lt;p&gt;When I first encountered a vector store while working on &lt;a href="https://inspector.dev/langchain-alternative-for-php-developers/" rel="noopener noreferrer"&gt;Neuron AI&lt;/a&gt;, the ADK (Agent Development Kit) for PHP, I'll admit I made the same assumptions that many web developers make when they hear the term "database". The natural inclination is to think in familiar terms – tables, rows, columns, SQL queries, user records, and all the structured data patterns we've grown comfortable with over years of building web applications. But vector stores represent something fundamentally different, and understanding this difference is crucial for anyone stepping into the world of AI agent development.&lt;/p&gt;

&lt;p&gt;The confusion often begins with how vector databases are marketed and discussed in AI circles. You'll frequently hear them described as "the database for AI agents", which immediately triggers our existing mental models. If you’re building an AI-powered customer service agent, for instance, your first instinct might be to think you need to store your customer records, user preferences, and application data in a vector store. This seems logical – after all, if it's the database for AI agents, shouldn’t it hold the same kind of structured information that powers your traditional applications?&lt;/p&gt;

&lt;p&gt;This misconception runs deeper than just terminology. When we think about databases in the context of web development, we think about storing records, relationships, and structured information that we can query with precision. We ask questions like "Show me all users who signed up in the last month" or "Find all orders over $100 for customer ID 12345". These queries have definitive, binary answers – either a record matches our criteria or it doesn't. The database returns exact matches based on explicit conditions we’ve defined.&lt;/p&gt;

&lt;p&gt;Vector databases operate on an entirely different principle. Rather than storing structured facts about your users or application data, they store the semantic meaning of text chunks – the conceptual essence of information rather than the information itself. When you insert text into a vector store, the system doesn't care about the literal words it contains in the way a traditional search index might. &lt;/p&gt;

&lt;p&gt;Instead, it requires that text to be transformed into a mathematical representation that captures its meaning, context, and conceptual relationships to other pieces of text. This representation consists of a series of numbers called vector embeddings.&lt;/p&gt;

&lt;p&gt;For developers who have spent years thinking about data in terms of strings, integers, and relational tables, the idea that we can somehow capture the “meaning” of text in an array of floating-point numbers feels almost mystical.&lt;/p&gt;

&lt;p&gt;The struggle is understandable. In traditional web development, we've grown accustomed to exact matches and structured queries. When a user searches for "red shirt" in an e-commerce application, we look for products where the description contains exactly those words, perhaps with some basic stemming or fuzzy matching. The relationship between the query and the data is transparent and predictable. But vector embeddings operate on an entirely different principle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction To Vector Embeddings
&lt;/h2&gt;

&lt;p&gt;To grasp vector embeddings, we need to abandon our attachment to exact string matching and embrace a fundamentally different way of thinking about text similarity. Imagine trying to explain to someone why "automobile" and "car" mean essentially the same thing, or why "happy" is more similar to "joyful" than to "purple". These relationships exist in the realm of meaning rather than literal character sequences, and vector embeddings are the mathematical tool to perform these queries.&lt;/p&gt;

&lt;p&gt;Vector embeddings work by representing each piece of text as a point in a high-dimensional mathematical space—typically containing hundreds or even thousands of dimensions. &lt;/p&gt;

&lt;p&gt;You probably remember how to represent a point on a chart with the classical two dimentìsions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1ljf7wvtrmwk36030xt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1ljf7wvtrmwk36030xt.png" alt="vector embeddings point - neuron adk inspector" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the case of a multidimensional vector it's an array of thousands of numbers that ideally represents a lot of axes. It’s a mathematical concept since it doesn’t make so much sense because in the real world we can represent basically anything in a 3D space.&lt;/p&gt;

&lt;p&gt;The more dimensions (aka more numbers) the vector has, the more accurately the meaning of a piece of text can be represented.&lt;/p&gt;

&lt;p&gt;While we cannot visualize these spaces directly, we can think of them as vast landscapes where semantically similar concepts cluster together. In this space, "dog" and "wolf" end up positioned close to each other, not because they share letters, but because they appear in similar contexts across the vast corpus of text used to train the embedding model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxw855qe6c0m2bslh2cu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxw855qe6c0m2bslh2cu.jpg" alt="vector embeddings space - neuron adk inspector" width="735" height="751"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This contextual understanding is what makes vector embeddings so powerful for AI agents. When a user asks your agent about "troubleshooting connection issues", the system doesn't just look for documents containing those exact words. Instead, it finds content about "network problems", "connectivity failures", or "debugging communication errors"—all of which occupy nearby regions in the embedding space despite using completely different terminology.&lt;/p&gt;

&lt;p&gt;This fundamental shift from storing data to storing meaning changes everything about how you interact with the database. Instead of asking "Find all documents with the exact phrase 'customer complaint'", you might ask something more nuanced like "Find content that expresses customer dissatisfaction or frustration". The vector database doesn't look for literal matches but rather searches for text that shares similar semantic space – content that means something similar, even if it uses completely different words.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vector Store Performs Retrieval – Not Queries
&lt;/h2&gt;

&lt;p&gt;During my work with &lt;a href="https://github.com/inspector-apm/neuron-ai" rel="noopener noreferrer"&gt;Neuron AI ADK&lt;/a&gt;, I've seen countless developers struggle with this conceptual leap. They approach vector stores with SQL-like thinking, trying to create precise queries for exact matches, when the real power lies in the system's ability to understand and match meaning across different expressions of similar concepts. A customer might say "This product is terrible", "I'm not happy with my purchase", or "This didn’t meet my expectations", and a well-configured vector store will recognize these as semantically similar expressions of dissatisfaction, even though they share no common keywords.&lt;/p&gt;

&lt;p&gt;The queries you perform against vector stores are fundamentally different beasts altogether. Rather than the precise, boolean logic of SQL where conditions are either true or false, vector queries operate in the realm of similarity and proximity. You're not asking “Does this record exactly match my criteria?” but rather "What stored information is most similar in meaning to what I’m looking for?" The database returns results ranked by their conceptual closeness to your query, opening up possibilities for discovery and connection that traditional databases simply cannot provide.&lt;/p&gt;

&lt;p&gt;This semantic approach becomes particularly powerful when working with AI agents because it mirrors how human understanding actually works. &lt;/p&gt;

&lt;p&gt;When someone asks your customer service agent about "billing issues", they might actually be referring to payment problems, invoice discrepancies, subscription concerns, or pricing confusion. A traditional database would require you to anticipate and explicitly map all these variations, but a vector store naturally understands the conceptual relationships between these different expressions of the same underlying concern.&lt;/p&gt;

&lt;p&gt;This contextual awareness becomes the foundation for building AI agents that can understand not just what users are saying, but what they actually mean.&lt;/p&gt;

&lt;p&gt;As we prepare to dive deeper into the internal mechanics of vector databases and the sophisticated algorithms that power their similarity searches, it's important to hold onto this fundamental understanding: you’re not just adopting a new type of database, you're embracing an entirely different paradigm for how information is stored, organized, and retrieved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vector Store Similarity Search
&lt;/h2&gt;

&lt;p&gt;Understanding similarity search requires us to think about how machines can mathematically represent the concept of "closeness" between ideas. In traditional databases, we're accustomed to exact matches – either two values are identical or they’re not. But in the realm of vector databases, we’re dealing with degrees of similarity.&lt;/p&gt;

&lt;p&gt;The actual search process operates through various distance metrics, with cosine similarity being perhaps the most intuitive to understand. Imagine each piece of text as a point in space, with the angle between any two points representing how similar their meanings are. When you perform a query, the system calculates these angles between your search vector and every stored vector, returning the ones with the smallest angles – essentially finding the content that points in the most similar semantic direction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbu644p8nhxv383ot068.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbu644p8nhxv383ot068.png" alt="vector similarity search - neuron adk inspector" width="791" height="707"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What makes this particularly powerful for AI agent development is how similarity search handles the messiness of human language. Traditional keyword search would miss the connection between "I can't access my account" and "login problems", but similarity search recognizes these as variations of the same underlying issue. The mathematical representation captures not just the words themselves, but the relationships, context, and intent behind them, allowing for discovery of relevant information even when the surface-level language is completely different.&lt;/p&gt;

&lt;p&gt;The performance characteristics of similarity search also differ dramatically from traditional database queries. Instead of the binary speed of indexed lookups, you're dealing with computational complexity that scales with the size of your vector space and the dimensionality of your embeddings. This is where the sophisticated algorithms we'll explore next become crucial – techniques like approximate nearest neighbor search that make similarity search practical at scale while maintaining the semantic richness that makes vector databases so powerful for AI applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Optimization Indexing Around Centroids
&lt;/h2&gt;

&lt;p&gt;Vector stores clusters the index vectors according to their relative proximity. For each cluster, they then identify its centroid, the center of gravity of that cluster, a high-dimensional point minimizing the distance with every vector in the cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmhx9rnv9e8t4ansyryip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmhx9rnv9e8t4ansyryip.png" alt="vector similarity search algorithm - neuron adk inspector" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We then structure the data on storage by placing each vector in a file named like the centroid it is closest to.&lt;/p&gt;

&lt;p&gt;When processing a query, we then can then focus on relevant vectors by looking only in the centroid files closest to that query vector, effectively pruning the search space.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;If you are getting started with AI Agents, or you simply want to elevate your skills to a new level here is a list of resources to help you go in the right direction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Neuron AI – Agent Development Kit for PHP&lt;/strong&gt;: &lt;a href="https://github.com/inspector-apm/neuron-ai" rel="noopener noreferrer"&gt;https://github.com/inspector-apm/neuron-ai&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Newsletter&lt;/strong&gt;: &lt;a href="https://neuron-ai.dev/" rel="noopener noreferrer"&gt;https://neuron-ai.dev/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E-Book (Start With AI Agents In PHP)&lt;/strong&gt;: &lt;a href="https://www.amazon.com/dp/B0F1YX8KJB" rel="noopener noreferrer"&gt;https://www.amazon.com/dp/B0F1YX8KJB&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The journey from traditional web development to AI agent development requires more than just learning new syntax or frameworks – it demands a fundamental shift in how we think about data, search, and user interaction. Vector databases represent one of the most significant paradigm shifts in this transition, moving us away from the rigid precision of SQL queries toward the fluid, contextual understanding that mirrors human cognition.&lt;/p&gt;

&lt;p&gt;If you're ready to put these concepts into practice, I encourage you to explore implementing your first Retrieval-Augmented Generation (RAG) system using Neuron AI ADK for PHP. The framework provides an accessible entry point for PHP developers to experiment with vector databases and semantic search without getting overwhelmed by the underlying complexity. &lt;/p&gt;

&lt;p&gt;Create a RAG with Neuron AI: &lt;a href="https://docs.neuron-ai.dev/rag" rel="noopener noreferrer"&gt;https://docs.neuron-ai.dev/rag&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>php</category>
      <category>webdev</category>
      <category>adk</category>
    </item>
  </channel>
</rss>
