<?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: Simon Griffiths</title>
    <description>The latest articles on DEV Community by Simon Griffiths (@simongriffiths).</description>
    <link>https://dev.to/simongriffiths</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%2Fuser%2Fprofile_image%2F3892825%2F401ecb2a-94d9-424f-9877-ec036dc4e1e2.jpg</url>
      <title>DEV Community: Simon Griffiths</title>
      <link>https://dev.to/simongriffiths</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/simongriffiths"/>
    <language>en</language>
    <item>
      <title>The Agent at the Gate — Why Agentic Access Breaks the Unwritten Rules of Database Security</title>
      <dc:creator>Simon Griffiths</dc:creator>
      <pubDate>Thu, 18 Jun 2026 19:32:19 +0000</pubDate>
      <link>https://dev.to/simongriffiths/the-agent-at-the-gate-why-agentic-access-breaks-the-unwritten-rules-of-database-security-3ble</link>
      <guid>https://dev.to/simongriffiths/the-agent-at-the-gate-why-agentic-access-breaks-the-unwritten-rules-of-database-security-3ble</guid>
      <description>&lt;p&gt;The API series looked at the contract problem from the outside: what happens when agents call interfaces that were designed around known consumers, shared context, and human judgement. This series looks from the other direction. What happens when the data boundary itself was relying on the application layer to enforce rules the database never knew?&lt;/p&gt;

&lt;p&gt;There is an assumption buried deep in almost every enterprise data architecture. It is so fundamental that most organisations have never written it down, let alone questioned it. The assumption is this: the application is the gatekeeper.&lt;/p&gt;

&lt;p&gt;Everything that stands between an end user and raw data — the business rules, the validation logic, the integrity checks, the transactional boundaries, the data quality controls — lives in the application layer. The database stores the data. The application controls what happens to it.&lt;/p&gt;

&lt;p&gt;That assumption is about to be tested as it has never been tested before.&lt;/p&gt;




&lt;h2&gt;
  
  
  This Is Not a New Idea — We Abandoned It
&lt;/h2&gt;

&lt;p&gt;It is worth remembering that this was not always the accepted model. Thirty or forty years ago, in the early era of enterprise relational databases, the database &lt;em&gt;was&lt;/em&gt; the control layer. Business rules lived in stored procedures. Constraints enforced data quality. Triggers maintained integrity. The logic was close to the data, and the database was the authority.&lt;/p&gt;

&lt;p&gt;I remember dealing with a version of this in the old Visual Basic client-server days, before REST APIs and middle tiers became the normal shape of enterprise systems. A VB front end would connect to the database over ODBC, often using a schema username and password embedded somewhere in the application configuration or code. Because the application needed to update data, the obvious answer was to give that schema write access to the tables.&lt;/p&gt;

&lt;p&gt;It worked, but it was a security nightmare. If those credentials leaked, the database was effectively open. The mitigation was to remove direct table updates and force all changes through PL/SQL procedures. The VB application could call governed operations, but it could not simply write whatever it liked to the underlying tables. We also used a token check to make sure the call was coming through an expected path.&lt;/p&gt;

&lt;p&gt;That was not elegant by modern standards, but the principle was sound: the database did not trust the caller with raw write access. It exposed controlled operations instead.&lt;/p&gt;

&lt;p&gt;That model was deliberately dismantled, and not without reason. Stored procedures were difficult to test, painful to version control, and resistant to the kind of agile development that application frameworks enabled. As distributed architectures emerged, database-centric logic became a bottleneck — hard to scale, hard to change, hard to own across teams. The application layer offered speed, flexibility, and separation of concerns. Moving logic out of the database was a conscious, reasoned decision made by architects who understood the trade-offs.&lt;/p&gt;

&lt;p&gt;The consequence, largely invisible at the time, was that the database became thinner. Schemas relaxed. Constraints were dropped in favour of application-layer validation. Business rules migrated into service layers and APIs. The database became very good at storing and retrieving data, and progressively less involved in deciding what that data should look like or how it should behave.&lt;/p&gt;

&lt;p&gt;For decades, this worked. The application, or later the middle tier, was always there. It was the only door into the data, and it was a door with rules. But the old lesson did not disappear. If the middle tier is the thing enforcing the rules, then anything that bypasses it reopens the same class of risk.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Application Layer Is No Longer Guaranteed
&lt;/h2&gt;

&lt;p&gt;AI agents change this fundamentally — not as a theoretical risk, but as a practical architectural reality that is already unfolding.&lt;/p&gt;

&lt;p&gt;An agent operating autonomously may not follow the workflow the application was designed to enforce. It may not submit a form, trigger a validation routine, or invoke the service layer in the expected sequence. Depending on how it has been integrated, it may query and write to data through tools, service credentials, generated SQL, or APIs that expose lower-level operations than the original application ever intended. The orchestration layer that manages the agent may impose some constraints, but it is not the application that encoded your business rules. It knows little about your data model's history, your organisation's integrity requirements, or the assumptions baked into your schema over twenty years of development.&lt;/p&gt;

&lt;p&gt;This is not a security problem alone, though security is part of it. It is a much broader loss of control. Consider what actually lives in the application layer of a typical enterprise system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Business rules&lt;/strong&gt; — eligibility checks, approval workflows, state transition logic, pricing rules. None of this is in the database. The database will accept a record that violates every one of these rules if the application does not intercept it first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data quality controls&lt;/strong&gt; — format validation, referential checks beyond foreign keys, cross-field consistency rules. An agent writing directly to the database bypasses all of them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transactional boundaries&lt;/strong&gt; — the application defines what constitutes a complete operation. The database enforces atomicity within a transaction, but it is the application that decides what belongs in that transaction. An agent may write partial state without ever completing the logical operation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit and compliance hooks&lt;/strong&gt; — in many systems, compliance logging is implemented in application code. Direct database access is invisible to it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End user identity&lt;/strong&gt; — perhaps most critically, the database typically sees a single application credential. It has no knowledge of which end user is behind a given operation. The application knew. The agent, acting autonomously through a service account or API credential, strips that context away entirely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these, individually, represents a gap. Together, they represent a control framework that simply ceases to function when the application layer is bypassed.&lt;/p&gt;




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

&lt;p&gt;The risk is compounded by a decade of architectural choices made in the name of flexibility. The shift toward flexible schemas — JSON columns, document stores, schema-on-read, EAV patterns — was a legitimate response to the pace of change that modern development demands. If the application is controlling what goes in, some schema flexibility is manageable. The application provides the structure that the schema does not.&lt;/p&gt;

&lt;p&gt;Remove the application, and flexible schema becomes a liability. An agent writing to a document store or a loosely-typed column meets almost no structural resistance. Nothing breaks at write time. The data will be accepted. The damage will be silent, cumulative, and potentially very difficult to detect or reverse.&lt;/p&gt;

&lt;p&gt;There is a contrarian case worth making here: the organisations that resisted schema flexibility — that maintained strong, constrained, relational data models even as the industry moved away from them — may now find themselves better protected. Rigid schemas, often criticised as obstacles to agility, turn out to be a form of structural defence. They cannot enforce business rules, but they can at least reject structurally invalid data.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Wheel Turns
&lt;/h2&gt;

&lt;p&gt;The irony is sharp. We are rediscovering the value of database-enforced logic at the precise moment the application layer is being dismantled. The thick database model — constraints, rules, integrity enforcement close to the data — is looking considerably more prescient than it did in 2010.&lt;/p&gt;

&lt;p&gt;The historical objections to that model were real, but they are weakening. The two most powerful arguments against embedding logic in the database were the development cost and the rigidity of strong schemas. Both depended on the assumption that humans, working at human pace, would bear the cost of writing and maintaining that logic.&lt;/p&gt;

&lt;p&gt;AI-assisted development changes that calculus. Complex constraints, validation rules, and schema definitions that would once have taken significant time to write and maintain can now be generated, tested, and evolved far more rapidly. The friction that made database-enforced logic impractical is reducing precisely when the need for it is increasing. Even strong, well-defined schemas — historically the enemy of development speed — become less of an obstacle when the tooling can absorb much of the cost of evolving them.&lt;/p&gt;

&lt;p&gt;This does not mean returning to monolithic stored-procedure architectures. It means taking seriously the question of where control should live when the application can no longer be assumed to be in the loop.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Question Organisations Need to Ask Now
&lt;/h2&gt;

&lt;p&gt;How much of what you believe to be data integrity actually lives in your database — and how much lives in the application you are about to bypass?&lt;/p&gt;

&lt;p&gt;For most organisations, the honest answer requires some clarity about intent. Application architects knew exactly how thin the database was — thinning it was the goal. Moving logic into the application layer was deliberate, considered, and successful on its own terms. This was not an oversight; it was a design philosophy prosecuted with discipline over many years.&lt;/p&gt;

&lt;p&gt;The problem is not that those decisions were wrong. The problem is that they were right for a world in which the application could be assumed to remain in the loop. That assumption is weaker now. The context that made a thin database the correct answer has shifted, and decisions that were rational then need to be revisited now.&lt;/p&gt;

&lt;p&gt;The subsequent articles in this series examine the specific dimensions of this problem — identity and accountability, transactional integrity, schema and storage models, governance and compliance — and what the database management system needs to become in order to meet it. But the starting point is recognising that the problem exists, that it is structural, and that it has been building for thirty years.&lt;/p&gt;

&lt;p&gt;The agent is at the gate. The gate was not designed for this.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>database</category>
      <category>api</category>
      <category>programming</category>
    </item>
    <item>
      <title>Your Email Account Is the Master Key</title>
      <dc:creator>Simon Griffiths</dc:creator>
      <pubDate>Wed, 17 Jun 2026 06:58:50 +0000</pubDate>
      <link>https://dev.to/simongriffiths/your-email-account-is-the-master-key-14df</link>
      <guid>https://dev.to/simongriffiths/your-email-account-is-the-master-key-14df</guid>
      <description>&lt;p&gt;Most people think of email as somewhere messages arrive.&lt;/p&gt;

&lt;p&gt;That is no longer the important part.&lt;/p&gt;

&lt;p&gt;Your main email account is the place other systems use to decide whether you are still you. Banks, shopping sites, cloud services, insurance companies, phone providers, password managers, social networks, travel companies and government services all use email as part of the recovery chain. If you forget a password, reset an account, confirm a device, receive an alert or prove ownership, the route often comes back through email.&lt;/p&gt;

&lt;p&gt;That makes your email account much more important than an inbox. It has become recovery infrastructure for the rest of your digital life.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Learnt This The Awkward Way
&lt;/h2&gt;

&lt;p&gt;My original primary email address was &lt;code&gt;s.griffiths@virgin.net&lt;/code&gt;, from the dial-up days.&lt;/p&gt;

&lt;p&gt;At the time, that was perfectly normal. Your internet provider gave you an email address, you used it, and over time it became part of your life. It went on forms. It became the address friends knew. It became the place services used to contact you.&lt;/p&gt;

&lt;p&gt;Then I moved away from the dial-up service and discovered the catch: my primary email address depended on that service continuing.&lt;/p&gt;

&lt;p&gt;Fortunately, my parents still used Virgin.net for dial-up, so I managed to keep the address alive for a few more years through their account. That bought me time to move. Unfortunately, I moved to Yahoo next.&lt;/p&gt;

&lt;p&gt;That solved the immediate problem, but it was not a permanent answer. As Yahoo declined, I realised I needed to move again, this time to Gmail, which felt like a more durable long-term home for my digital identity.&lt;/p&gt;

&lt;p&gt;Years later, I hit the ghost of that first decision. I tried to sign up to a service using my phone number and was rejected because the number was still linked to my old &lt;code&gt;virgin.net&lt;/code&gt; email address. Virgin.net was long gone. I could not access the mailbox. The vendor insisted on using the non-existent email account as the proof point, so I had no easy way to disconnect the phone number.&lt;/p&gt;

&lt;p&gt;That is the problem. An email address can disappear from your life but remain embedded in someone else's recovery process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Email Became The Spare Key Everyone Trusts
&lt;/h2&gt;

&lt;p&gt;The shift happened gradually enough that most of us did not notice.&lt;/p&gt;

&lt;p&gt;Email started as correspondence. Losing access was annoying, but not always catastrophic. You might miss messages, lose old conversations, or have to tell people your new address.&lt;/p&gt;

&lt;p&gt;Now email is part of the machinery of identity.&lt;/p&gt;

&lt;p&gt;If someone controls your primary email account, they may not need to know where you bank. They can search your inbox and find out. They may not need to guess which cloud service you use. The alerts, receipts and old sign-up messages will tell them. They may not need to break into every account at once. They can reset one, wait, read the notifications, and move carefully.&lt;/p&gt;

&lt;p&gt;That is why this matters. A compromised email account is not only a privacy problem. It can become a map of your digital life and, in many cases, a route into it.&lt;/p&gt;

&lt;p&gt;The risk is not always dramatic. An attacker may not lock you out immediately. They may add a forwarding rule, keep reading quietly, and wait for useful messages to arrive. They may delete warnings before you see them. They may use old receipts and account emails to build a picture of where to try next.&lt;/p&gt;

&lt;p&gt;This is why I would treat your main email account as one of the foundations of your digital life, not just somewhere messages arrive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Email Accounts Are Too Fragile For This Job
&lt;/h2&gt;

&lt;p&gt;This is where I am going to be opinionated.&lt;/p&gt;

&lt;p&gt;For most people, the main recovery email for banking, cloud storage, phone accounts, government services and password managers should sit with a provider that has strong modern account protection and is likely to be around for the long term.&lt;/p&gt;

&lt;p&gt;In practice, that often means Google, Microsoft or Apple. Not because they are perfect, and not because you should trust any large technology company blindly. This is not a brand recommendation. It is a judgement about security maturity, recovery processes, passkeys or strong two-factor options, device alerts, and the likelihood that the account will still exist in the form you need a decade from now.&lt;/p&gt;

&lt;p&gt;I would be much more cautious about using an ISP mailbox, an old work address, an old Yahoo-style account, a small provider you barely think about, or a custom domain you set up years ago and now only half remember.&lt;/p&gt;

&lt;p&gt;Some of those services can be secured. That is not the point. The question is whether they are strong enough, durable enough and recoverable enough to act as the foundation for everything else.&lt;/p&gt;

&lt;p&gt;An email account that still works is not necessarily an email account you should trust as your digital master key.&lt;/p&gt;

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

&lt;p&gt;There is another version of this problem that catches technically aware people more often than non-technical ones: the old personal domain.&lt;/p&gt;

&lt;p&gt;If your main email address is something like &lt;code&gt;you@yourdomain.com&lt;/code&gt;, then your security does not only depend on the mailbox. It also depends on the domain name, the renewal payment, the account where the domain is managed, and whoever still knows how it is configured.&lt;/p&gt;

&lt;p&gt;That sounds technical, but the risk is simple.&lt;/p&gt;

&lt;p&gt;If the domain expires, is misconfigured, or falls under someone else's control, email for that domain may stop reaching you. Worse, it may eventually start reaching someone else. If that address is used for password resets, bank alerts, cloud accounts or your password manager, the domain has become part of your identity system.&lt;/p&gt;

&lt;p&gt;For a newsletter address, that may be fine. For the account that protects your bank, cloud storage, phone provider and family photos, it is only safe if you actively manage the domain, protect the registrar account, and know exactly how recovery works.&lt;/p&gt;

&lt;p&gt;The test is simple: if losing that domain would make it hard to prove who you are to important services, either manage it as critical infrastructure or do not use it as your keystone email address.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five Things To Do Today
&lt;/h2&gt;

&lt;p&gt;This does not need to become a weekend project. Start with the account that matters most.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Choose Your Keystone Email Account
&lt;/h3&gt;

&lt;p&gt;Decide which email account should be the recovery address for your important services.&lt;/p&gt;

&lt;p&gt;That means your bank, credit card, phone provider, cloud storage, password manager, government services, insurance, main shopping accounts and anything you would panic about losing.&lt;/p&gt;

&lt;p&gt;For most people, this should be one strong mainstream account, not a collection of old addresses accumulated over twenty years.&lt;/p&gt;

&lt;p&gt;There is a reasonable argument for having a separate account used only for these critical services, rather than using the same address for everyday mail, newsletters and shopping receipts. I have considered doing this myself. It reduces noise and makes the account's purpose very clear.&lt;/p&gt;

&lt;p&gt;But it only works if you actually look after it. A separate account that you rarely check, forget how to recover, or leave tied to an old phone number is not safer. For most households, the practical answer is one properly secured main account, or one dedicated keystone account that is protected strongly and checked regularly. What I would avoid is a half-forgotten spare mailbox that quietly becomes the recovery route for everything important.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Move Critical Accounts Away From Fragile Addresses
&lt;/h3&gt;

&lt;p&gt;If important accounts still point to an ISP email address, an old work address, a forgotten domain, or a mailbox you would struggle to recover, move them.&lt;/p&gt;

&lt;p&gt;Do not try to fix everything at once. Start with the accounts that matter most: banking, phone provider, password manager, cloud storage and government services.&lt;/p&gt;

&lt;p&gt;Keep the old address for newsletters, receipts and low-risk services if you want. Just stop using it as proof of identity.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Turn On Strong Sign-In Protection
&lt;/h3&gt;

&lt;p&gt;Your keystone email account should have more than a password protecting it.&lt;/p&gt;

&lt;p&gt;Use a passkey if the provider supports it. If not, use an authenticator app or a physical security key. SMS codes are better than nothing, but I would not choose them as the main protection for the account that protects everything else.&lt;/p&gt;

&lt;p&gt;Also save recovery codes somewhere offline. Printed and stored with important documents is good enough for many households. The point is that you should not need access to the same email account to recover the email account.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Check For Quiet Ways Someone Could Still Be Reading
&lt;/h3&gt;

&lt;p&gt;Changing the password is not always enough.&lt;/p&gt;

&lt;p&gt;Check whether your email account has forwarding rules you do not recognise. Look at the devices currently signed in. Review old connected apps and mail clients. Remove old app passwords if your provider shows them.&lt;/p&gt;

&lt;p&gt;You do not need to understand every technical detail. The question is simple: is there any route by which someone, or some old app, could still be reading this mailbox without you noticing?&lt;/p&gt;

&lt;p&gt;If you do not recognise it, remove it.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Fix Recovery Before You Need It
&lt;/h3&gt;

&lt;p&gt;Check the recovery phone number and recovery email address on your keystone account.&lt;/p&gt;

&lt;p&gt;Make sure they are current and under your control. If the recovery address points to an old mailbox you barely use, you have just moved the weakness one step sideways.&lt;/p&gt;

&lt;p&gt;Also think about your password manager. If you need your email to recover your password manager, and your password manager to recover your email, you have built a loop. Break that loop with offline recovery codes, an emergency kit, or a written record stored safely at home.&lt;/p&gt;

&lt;h2&gt;
  
  
  Good Enough For A Household
&lt;/h2&gt;

&lt;p&gt;Good enough does not mean perfect.&lt;/p&gt;

&lt;p&gt;For most households, good enough looks like this: one strong main email account, protected with a passkey or proper two-factor authentication, with clean recovery details, no unknown forwarding rules, no mystery devices, and recovery codes stored somewhere offline.&lt;/p&gt;

&lt;p&gt;That is not glamorous. It is not advanced cyber security. It is basic household resilience.&lt;/p&gt;

&lt;p&gt;If you secure only one account properly this week, make it your main email account.&lt;/p&gt;

&lt;p&gt;Because your bank may hold your money, your cloud account may hold your photos, and your phone may hold your messages. But your email account is often the place they all turn to when they need to decide whether you are still you.&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>digitalworkplace</category>
    </item>
    <item>
      <title>APIs Expose Data, Not Meaning</title>
      <dc:creator>Simon Griffiths</dc:creator>
      <pubDate>Thu, 11 Jun 2026 17:43:34 +0000</pubDate>
      <link>https://dev.to/simongriffiths/apis-expose-data-not-meaning-3g8g</link>
      <guid>https://dev.to/simongriffiths/apis-expose-data-not-meaning-3g8g</guid>
      <description>&lt;h1&gt;
  
  
  APIs Expose Data, Not Meaning
&lt;/h1&gt;

&lt;p&gt;The previous article drew a line from SOA to the present. Structural contracts were never enough, because they defined how services communicated, not what they meant.&lt;/p&gt;

&lt;p&gt;Agents push that gap into the foreground.&lt;/p&gt;

&lt;p&gt;This article is about what the gap looks like in practice, and why it is harder to close than it appears.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Schema Isn't The Contract
&lt;/h2&gt;

&lt;p&gt;When we talk about API quality, we tend to talk about schemas.&lt;/p&gt;

&lt;p&gt;Is the response well structured? Are the types correct? Is the contract versioned? Is there an OpenAPI specification? These things matter. They are part of the discipline. But they are not the whole contract.&lt;/p&gt;

&lt;p&gt;A schema defines shape. It does not define meaning.&lt;/p&gt;

&lt;p&gt;That difference is easy to miss when the consumer is a human developer. Developers read documentation, ask questions, infer context, and notice when something does not behave as expected. They build a mental model of the system over time. The API may be incomplete, but the human fills in some of the missing meaning.&lt;/p&gt;

&lt;p&gt;Agents do not have that same feedback loop. They operate on what is exposed. If what is exposed is structurally valid but semantically ambiguous, the result can be plausible and wrong at the same time. Worse, it can be wrong consistently, at speed, and without anyone noticing until a decision has already been made.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Field Called Gender
&lt;/h2&gt;

&lt;p&gt;Take a field that appears in many enterprise systems: &lt;code&gt;gender&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It looks straightforward. The schema validates. Values come back as &lt;code&gt;M&lt;/code&gt;, &lt;code&gt;F&lt;/code&gt;, or perhaps &lt;code&gt;Other&lt;/code&gt;. There are no errors, no failed calls, and nothing obviously broken in the payload.&lt;/p&gt;

&lt;p&gt;But which gender is it?&lt;/p&gt;

&lt;p&gt;In an HR system, it may be the employee's self-reported gender identity, used for inclusion reporting and pronoun preferences in internal tooling. In a payroll system, it may be the legal sex recorded on government tax documents, constrained by statutory reporting requirements. In a healthcare benefits platform, it may represent biological sex for insurance categories, clinical screening, or medication rules. In a CRM, it may not be identity at all, but an inferred marketing segment derived from behavioural signals.&lt;/p&gt;

&lt;p&gt;The field name is the same. The values may look similar. The meaning is not the same.&lt;/p&gt;

&lt;p&gt;That difference is not pedantry. It changes governance, privacy, acceptable use, and the decisions that can safely be made from the value. An agent composing across these systems does not just risk getting the value wrong. It risks using the right value in the wrong context, which is often more dangerous.&lt;/p&gt;

&lt;p&gt;A value that is accurate in one domain can produce a decision that is structurally sound and substantively incorrect in another.&lt;/p&gt;

&lt;p&gt;The API exposed data. It did not expose meaning.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Same Problem Appears Everywhere
&lt;/h2&gt;

&lt;p&gt;The gender example is vivid, but it is not unusual. Most large organisations have the same problem in less sensitive and less obvious forms.&lt;/p&gt;

&lt;p&gt;A field called &lt;code&gt;status&lt;/code&gt; might describe whether a customer is active, whether an account is billable, whether a workflow has completed, or whether access should be allowed. A field called &lt;code&gt;type&lt;/code&gt; might represent a product category in one system, a regulatory classification in another, and an internal routing hint somewhere else. The schema may be valid in each case, but the semantics do not travel cleanly between systems.&lt;/p&gt;

&lt;p&gt;Dates create a similar problem in a less sensitive but very familiar form. I have seen APIs where the date format was perfectly defined, but a business convention sat outside the schema: a timestamp with the time set to midnight meant "this is a whole-day value", not "this happened at exactly midnight". Structurally, the value was valid. Semantically, it carried an assumption the caller had to know.&lt;/p&gt;

&lt;p&gt;That kind of convention causes real problems downstream, especially in analytics. If one system uses midnight to mean "no time component", another uses it as an actual event time, and a third applies local business-day rules, then a simple question like "show me everything for Tuesday" stops being simple. The data shape is consistent. The meaning is not.&lt;/p&gt;

&lt;p&gt;The same issue applies to operations. An endpoint called &lt;code&gt;updateCustomer&lt;/code&gt; may sound simple, but what does it actually do? Does it only change a record? Does it trigger a notification? Does it alter audit state? Does it start a downstream workflow? Does it have different behaviour depending on who called it, which channel the request came from, or which state the customer is already in?&lt;/p&gt;

&lt;p&gt;These are not edge details. They are part of the real contract.&lt;/p&gt;

&lt;p&gt;The missing meaning sits in several places at once: field semantics, operation intent, domain context, provenance, side effects, idempotency, consistency, ordering, and authority. Some of that can be documented. Some of it needs to be designed into the API surface. Some of it belongs in governance and access control. But it cannot be left as tribal knowledge if the caller is an agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Got Away With It
&lt;/h2&gt;

&lt;p&gt;Human developers are good at closing semantic gaps.&lt;/p&gt;

&lt;p&gt;They read between the lines. They ask for clarification. They test unexpected cases. They learn which systems are reliable, which fields are overloaded, which APIs are safe to compose, and which ones require care. Over time, that knowledge becomes distributed across teams, conventions, runbooks, and the memory of people who have integrated with the system before.&lt;/p&gt;

&lt;p&gt;It is slow and fragile, but it works up to a point.&lt;/p&gt;

&lt;p&gt;What it really means is that the full contract was never in the API. It was partly in the schema, partly in the documentation, partly in the code that called it, and partly in the institutional knowledge around the system.&lt;/p&gt;

&lt;p&gt;Agents inherit very little of that.&lt;/p&gt;

&lt;p&gt;They do not know which field is politically sensitive, which status value is overloaded, or which endpoint has a side effect that everyone on the team remembers but nobody put in the schema. When the formal contract is incomplete, they fill the gap with inference.&lt;/p&gt;

&lt;p&gt;Inference from incomplete contracts is where the risk concentrates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Better Semantics Is Not Just More Documentation
&lt;/h2&gt;

&lt;p&gt;The obvious response is to document more. That helps, but it is not enough.&lt;/p&gt;

&lt;p&gt;If meaning sits only in prose beside the API, it is still separate from the thing being called. A human may read it. A generated client may ignore it. An agent may summarise it incorrectly, overweight the wrong part, or fail to connect it to the specific operation being performed.&lt;/p&gt;

&lt;p&gt;Richer semantics has to affect the design of the API itself.&lt;/p&gt;

&lt;p&gt;That means names should reflect business intent rather than implementation convenience. &lt;code&gt;approveClaim&lt;/code&gt;, &lt;code&gt;suspendAccount&lt;/code&gt;, or &lt;code&gt;issueRefund&lt;/code&gt; carry more meaning than a generic update operation with a status field buried in the payload. Enumerated values should describe what they mean, not just which strings are valid. Side effects should be explicit at the point of call. Provenance and governance context should be part of what is exposed when the meaning of a value depends on where it came from.&lt;/p&gt;

&lt;p&gt;It also means separating concepts that only look similar. If legal sex, gender identity, biological sex, and marketing inference mean different things, they should not collapse into one generic field just because the values happen to overlap. If customer status means different things in billing, fulfilment, support, and access control, the API should not pretend there is one universal truth called &lt;code&gt;status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is not just better schema design. It is domain modelling.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Question
&lt;/h2&gt;

&lt;p&gt;If SOA taught us that structural contracts are not enough, and the semantic gap shows us that data without meaning is not a complete contract, then the next question is straightforward.&lt;/p&gt;

&lt;p&gt;What would an API look like if it were designed from the start to carry meaning, not just data?&lt;/p&gt;

&lt;p&gt;Not a larger schema. Not a thicker PDF beside the endpoint. A different model of the API itself: one where business capability, domain intent, authority, provenance, and behavioural guarantees are first-class concerns rather than things the consumer has to reconstruct from structure alone.&lt;/p&gt;

&lt;p&gt;That is what an agent-ready API requires.&lt;/p&gt;

&lt;p&gt;It is also a much richer definition of an API than the technical contract we have been working with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading For The Series
&lt;/h2&gt;

&lt;p&gt;For readers who want to follow the standards and security background behind this argument:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://modelcontextprotocol.io/docs/getting-started/intro" rel="noopener noreferrer"&gt;Model Context Protocol: Introduction&lt;/a&gt; and &lt;a href="https://modelcontextprotocol.io/specification/2025-06-18/server/tools" rel="noopener noreferrer"&gt;MCP Tools&lt;/a&gt;, for the current tool-exposure model used by agentic applications.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://spec.openapis.org/oas/latest" rel="noopener noreferrer"&gt;OpenAPI Specification&lt;/a&gt; and &lt;a href="https://learn.openapis.org/specification/paths.html" rel="noopener noreferrer"&gt;OpenAPI Paths and Operations&lt;/a&gt;, for the dominant modern way of describing HTTP API structure.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.oasis-open.org/standard/uddi/" rel="noopener noreferrer"&gt;OASIS UDDI v3.0.2&lt;/a&gt;, for the SOA-era registry model.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/submissions/WSDL-S/" rel="noopener noreferrer"&gt;W3C WSDL-S&lt;/a&gt; and &lt;a href="https://www.w3.org/TR/sawsdl/" rel="noopener noreferrer"&gt;W3C SAWSDL&lt;/a&gt;, for standards-era attempts to add semantic annotations to Web service descriptions.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://owasp.org/www-project-top-10-for-large-language-model-applications/" rel="noopener noreferrer"&gt;OWASP Top 10 for Large Language Model Applications&lt;/a&gt;, especially the material on excessive agency and tool/plugin risk.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>We've Seen This Before: What SOA Teaches Us About APIs in the Age of Agents</title>
      <dc:creator>Simon Griffiths</dc:creator>
      <pubDate>Wed, 10 Jun 2026 11:37:31 +0000</pubDate>
      <link>https://dev.to/simongriffiths/weve-seen-this-before-what-soa-teaches-us-about-apis-in-the-age-of-agents-5lm</link>
      <guid>https://dev.to/simongriffiths/weve-seen-this-before-what-soa-teaches-us-about-apis-in-the-age-of-agents-5lm</guid>
      <description>&lt;p&gt;In the &lt;a href="https://simongriffiths.io/2026/06/02/agents-dont-replace-apis-they-expose-how-weak-most-apis-already-are/" rel="noopener noreferrer"&gt;first article in this series&lt;/a&gt;, I argued that agents do not replace APIs. They expose the quality of the APIs underneath them.&lt;/p&gt;

&lt;p&gt;That should feel familiar, because we have been here before.&lt;/p&gt;

&lt;p&gt;The current wave of AI agents, MCP, and tool-driven architectures follows a recognisable pattern. We are being told that systems will become more composable, more interoperable, and more reusable. Software will call other software dynamically. Capabilities will be discovered and invoked at runtime. Integration will become less rigid because the caller can decide what to use as it goes.&lt;/p&gt;

&lt;p&gt;That sounds new because the tooling is new. The architecture story is not.&lt;/p&gt;

&lt;p&gt;We said much the same thing about Service-Oriented Architecture.&lt;/p&gt;

&lt;p&gt;SOA, at least in its enterprise form, did not deliver on that promise. The easy explanation is to blame the technology: SOAP, XML, WS-* and all the ceremony around them. That is convenient, but it misses the more useful lesson. The problem was not simply how services communicated. The problem was how they were designed, and what we thought a contract actually meant.&lt;/p&gt;

&lt;p&gt;That matters now, because agents are pushing us back into the same territory, only faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  SOA Didn't Fail At Interfaces
&lt;/h2&gt;

&lt;p&gt;SOA gave us strong interface definitions. WSDL could describe operations, inputs, outputs, schemas, and types. For the time, that was a serious attempt to make enterprise systems talk to each other in a more formal way.&lt;/p&gt;

&lt;p&gt;On paper, it looked like interoperability.&lt;/p&gt;

&lt;p&gt;In practice, it often wasn't.&lt;/p&gt;

&lt;p&gt;The contract could tell you the shape of the message, but not enough about the meaning of the message. It could tell you that an operation existed, but not always what business intention sat behind it. It could describe fields and types, but not the assumptions the service was making, the states it expected, or how it behaved once you stepped outside the happy path.&lt;/p&gt;

&lt;p&gt;Two systems could integrate perfectly at a structural level and still misunderstand each other completely.&lt;/p&gt;

&lt;p&gt;That was the deeper failure. SOA did not fail because interfaces were useless. It failed because the interfaces were not rich enough to survive outside the context in which they had been created.&lt;/p&gt;

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

&lt;p&gt;Many SOA services were not really general-purpose capabilities. They were services extracted from, or designed for, a particular application, process, or integration.&lt;/p&gt;

&lt;p&gt;That meant the formal interface was only part of the contract. The rest lived in shared context. The consuming system knew the expected sequence. The teams knew which fields were safe to use. The people involved understood which status values were meaningful, which edge cases mattered, and which calls were technically possible but operationally foolish.&lt;/p&gt;

&lt;p&gt;The service looked reusable because the interface was published. But reuse outside the original context still required human negotiation.&lt;/p&gt;

&lt;p&gt;This is the same problem we see with many APIs today. The interface is technically available, but its correct use depends on assumptions that were never made explicit. Once the consumer is no longer the one you designed for, the weakness becomes visible.&lt;/p&gt;

&lt;p&gt;A specific example from the SOA period has stayed with me. Architects designed what should have been a public CRM capability: a customer API that could have served as a stable enterprise surface for more than one consumer. In practice, it was shaped around the first integration. The request model, sequencing, optional fields, and error handling reflected the needs of the two systems being connected rather than the wider business capability.&lt;/p&gt;

&lt;p&gt;It had the language of a reusable service, but the design of a point-to-point connector.&lt;/p&gt;

&lt;p&gt;Agents make that weakness more serious because they are, by definition, not the original known consumer.&lt;/p&gt;

&lt;p&gt;One concrete version of this is the end-to-end customer journey. I have written before about &lt;a href="https://dev.to/2019/12/03/microservices-and-business-processes/"&gt;lead-to-cash&lt;/a&gt; as a process that looks tidy on a diagram but crosses marketing, fulfilment, billing, payments, operations, and multiple system owners. In the SOA and ESB world, the process model could give the impression that the journey had a single contract. In practice, the contract often lived in the routing rules, service assumptions, ownership boundaries, and exception handling around the services.&lt;/p&gt;

&lt;p&gt;The interface did not carry all of that. The process did.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structure Is Not Meaning
&lt;/h2&gt;

&lt;p&gt;The most important distinction is between structural precision and semantic clarity.&lt;/p&gt;

&lt;p&gt;SOA was often structurally precise. A schema could be strict. A service could reject invalid messages. Types could be checked. The system could be correct in a narrow technical sense.&lt;/p&gt;

&lt;p&gt;But a field called &lt;code&gt;status&lt;/code&gt; could still be ambiguous. Does it describe the current business state, the last completed process step, the result of a validation check, or the state visible to a particular user role? What transitions are valid? What side effects happen when it changes? Which system is the source of truth?&lt;/p&gt;

&lt;p&gt;Those answers were rarely in the contract. They were in documentation, project memory, support teams, or the heads of people who had been around long enough to know.&lt;/p&gt;

&lt;p&gt;That is not a small gap. It is the difference between being able to call a service and being able to use it correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Governance And Operational Reality Parted Ways
&lt;/h2&gt;

&lt;p&gt;SOA also teaches a second lesson, which is that governance cannot just be process layered on top of weak contracts.&lt;/p&gt;

&lt;p&gt;Organisations recognised that service reuse and change management were difficult, so they introduced versioning rules, approval boards, central registries, and service governance processes. The intention was sensible: bring order to a growing service estate.&lt;/p&gt;

&lt;p&gt;The deeper problem was that governance and operational reality parted ways.&lt;/p&gt;

&lt;p&gt;The SOA registry was supposed to be the source of truth, but it could not express enough of the contract. It could describe the service, the endpoint, the schema, and perhaps some ownership metadata. It could not reliably express the business meaning, assumptions, side effects, operational constraints, or safe usage patterns.&lt;/p&gt;

&lt;p&gt;So architects and teams did what they had to do: they wrote documentation around the registry.&lt;/p&gt;

&lt;p&gt;That helped for a while, but it created a new problem. The API, the registry, and the documentation were now three separate representations of the same contract. They changed at different speeds, were owned by different people, and predictably began to drift.&lt;/p&gt;

&lt;p&gt;Once that happened, governance stopped being a reliable description of reality. It became another artefact to reconcile.&lt;/p&gt;

&lt;p&gt;I saw the operational version of this in audit and compliance work. The specialists I worked with were not interested in the service diagram as the final truth. They wanted the raw data, because committed data in the database was the only durable evidence of what had happened. Queue state, process state, and integration logs mattered, but they were not a substitute for a governed source of record.&lt;/p&gt;

&lt;p&gt;The lesson is not that governance is bad. The lesson is that governance has to live in the design of the contract itself. If meaning, authority, behaviour, and change expectations are not part of the interface, a process document will not rescue it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Illusion Of Reuse
&lt;/h2&gt;

&lt;p&gt;SOA promised reusable services. What many organisations got instead were services that were technically reusable but practically tied to their first use case.&lt;/p&gt;

&lt;p&gt;That distinction matters.&lt;/p&gt;

&lt;p&gt;Technical reusability means another system can call the service. Practical reusability means another system can call it safely, understand what it means, depend on its behaviour, and evolve with it over time. SOA often delivered the first and assumed the second would follow.&lt;/p&gt;

&lt;p&gt;It did not follow.&lt;/p&gt;

&lt;p&gt;Reuse still depended on humans understanding the semantics, uncovering hidden assumptions, and negotiating change. The contract had not carried enough of the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Agents Make The Old Problem New Again
&lt;/h2&gt;

&lt;p&gt;Agents change the consumption model.&lt;/p&gt;

&lt;p&gt;Instead of a known front end or a controlled integration, we now have consumers that may discover tools dynamically, compose operations at runtime, and act without the shared background knowledge of the teams that built the API. An agent does not know what you meant. It knows what you exposed.&lt;/p&gt;

&lt;p&gt;That turns old weaknesses into more immediate risks. Ambiguous fields become incorrect decisions. Hidden assumptions become failed workflows. Unclear behaviour becomes unpredictable action. A contract that was merely inconvenient for human developers can become dangerous when an autonomous caller starts composing it with other capabilities.&lt;/p&gt;

&lt;p&gt;This is why the move from SOAP to REST, from XML to JSON, or from WSDL to OpenAPI does not by itself solve the problem. The modern stack is cleaner and more pleasant to work with, but most API contracts still describe structure better than meaning. They tell you about endpoints, payloads, response codes, and schemas. They say much less about intent, domain context, behavioural guarantees, authority boundaries, and side effects.&lt;/p&gt;

&lt;p&gt;That is the pattern we risk repeating.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Lesson
&lt;/h2&gt;

&lt;p&gt;SOA standardised how services talk. It did not standardise what they mean.&lt;/p&gt;

&lt;p&gt;That is the lesson worth carrying forward.&lt;/p&gt;

&lt;p&gt;Agents are not sending us into an entirely new architectural problem. They are making an old one harder to ignore. If the contract does not contain enough meaning to survive outside its original context, then dynamic composition will not make the system more reliable. It will make the misunderstanding faster.&lt;/p&gt;

&lt;p&gt;The next question is therefore not whether we need APIs. We do.&lt;/p&gt;

&lt;p&gt;The question is what an API contract needs to contain when the caller is no longer a known application, a known team, or a known workflow.&lt;/p&gt;

&lt;p&gt;And beneath that, there is a deeper issue: our APIs expose data structures, but not meaning.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>api</category>
      <category>mcp</category>
    </item>
    <item>
      <title>What AI Changes About Building Blogs - Migrating from Wordpress to GitHub Pages</title>
      <dc:creator>Simon Griffiths</dc:creator>
      <pubDate>Wed, 03 Jun 2026 16:37:45 +0000</pubDate>
      <link>https://dev.to/simongriffiths/what-ai-changes-about-building-blogs-migrating-from-wordpress-to-github-pages-33f8</link>
      <guid>https://dev.to/simongriffiths/what-ai-changes-about-building-blogs-migrating-from-wordpress-to-github-pages-33f8</guid>
      <description>&lt;p&gt;WordPress powers around 43% of the web. For years it was the default answer to "how do I start a blog?" It was mine too.&lt;/p&gt;

&lt;p&gt;This is not a post about why WordPress is bad. It is about something its pricing quietly depends on: the belief that leaving is expensive.&lt;/p&gt;

&lt;p&gt;For most of the web's history that belief was correct. Migration meant days or weeks of work: exporting content, rebuilding themes, fixing images, redesigning layouts, and repairing formatting. So people stayed.&lt;/p&gt;

&lt;p&gt;AI has changed that calculation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Final Straw
&lt;/h2&gt;

&lt;p&gt;I had been on WordPress.com for years. Mixed content, inconsistent posting: a burst of twenty articles back in 2019, then a long gap before I started writing seriously again this year.&lt;/p&gt;

&lt;p&gt;The friction accumulated slowly. Themes locked behind higher-tier plans. Limited customisation unless you paid more. None of that was unreasonable on its own. Platforms cost money.&lt;/p&gt;

&lt;p&gt;What finally pushed me over the edge was much smaller.&lt;/p&gt;

&lt;p&gt;I wanted a staging environment to test changes before pushing them live. WordPress.com charges for a second site, then charges again for the tooling to sync changes between them. Staging does carry real cost, but the pricing made a routine workflow feel disproportionately expensive for an individual blog. It stopped feeling like infrastructure and started feeling like a toll booth.&lt;/p&gt;

&lt;p&gt;The question stopped being "should I stay?" and became "how long would it take to leave?"&lt;/p&gt;

&lt;p&gt;The answer turned out to be: a few hours of AI-assisted work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Migration
&lt;/h2&gt;

&lt;p&gt;To WordPress.com's credit, the export is excellent: one XML file containing posts, pages, metadata, and media references.&lt;/p&gt;

&lt;p&gt;From there, I handed the problem to AI.&lt;/p&gt;

&lt;p&gt;I used the OpenAI Codex app, a macOS coding agent that works across a local development environment. I gave it the export, pointed it at my existing site, and asked it to recreate the blog in Hugo with roughly the same visual feel.&lt;/p&gt;

&lt;p&gt;What came back was not a scaffold or a starter template. It was a functioning site: migrated content, working structure, and a recognisable design language. Separately, I used Claude to build a colour palette and refine the visual direction.&lt;/p&gt;

&lt;p&gt;Then I iterated. Better typography. Cleaner layouts. Simpler navigation. Things I had wanted to fix for years but had never got around to inside the WordPress editor.&lt;/p&gt;

&lt;p&gt;Export to deployment took a couple of hours. Another few refined the design.&lt;/p&gt;

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

&lt;p&gt;The export solved content migration, but not presentation. Some posts had inline images. Some had none. The older 2019 articles were visually weak: written quickly, published with little thought for consistency.&lt;/p&gt;

&lt;p&gt;I wanted every article to have a proper hero image.&lt;/p&gt;

&lt;p&gt;So I described the problem to Codex: identify posts missing hero images, promote suitable inline images where possible, and flag the gaps. Then I used AI image generation to create artwork for the rest.&lt;/p&gt;

&lt;p&gt;Something useful happened in the process. Without planning it, I started developing a visual identity. The generated images began sharing a palette, a mood, a texture. That consistency now carries forward into new writing.&lt;/p&gt;

&lt;p&gt;The result is the thing WordPress never made worth my time: a consistent visual identity across the whole archive, old and new, without editing it post by post. I will revisit the weakest of the early images eventually, but the archive already hangs together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Hugo and GitHub Pages
&lt;/h2&gt;

&lt;p&gt;Hugo is fast and simple. There is no database. Content lives as Markdown files in Git. Deployment is a push. There are far fewer moving parts than a dynamic CMS.&lt;/p&gt;

&lt;p&gt;GitHub Pages hosts it for free, with HTTPS and custom domains.&lt;/p&gt;

&lt;p&gt;The trade-off is real: you lose WordPress's browser-based editor and plugin ecosystem. For non-technical creators who value integrated editing, plugins, memberships, forms, and low-friction publishing, WordPress still makes a great deal of sense.&lt;/p&gt;

&lt;p&gt;But for technical writers, and increasingly for anyone comfortable with AI-assisted tooling, static publishing is far more accessible than it used to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Actually Means
&lt;/h2&gt;

&lt;p&gt;The shift here is not Hugo specifically. It is that AI has collapsed migration friction.&lt;/p&gt;

&lt;p&gt;Work that used to require significant developer time, such as rebuilding layouts, transforming content, repairing formatting, auditing media, and iterating on design, now compresses into a few hours of directed work with coding agents.&lt;/p&gt;

&lt;p&gt;That changes the balance of power between platforms and users. Platforms have always benefited from inertia: even mildly dissatisfied users stayed because leaving felt expensive and risky. Much of that friction has now gone. For technically comfortable users, the barrier is less about implementation and more about clarity of intent.&lt;/p&gt;

&lt;p&gt;I am not suggesting everyone should move to Hugo and GitHub Pages. The right answer depends on your audience, your workflow, and your tolerance for technical tooling.&lt;/p&gt;

&lt;p&gt;AI does not remove the need for judgement, taste, or technical understanding. What it removes is the implementation cost of acting on them. And once that cost falls far enough, "it is not worth the effort to move" stops being a reason and starts being an excuse.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Haven't Solved Yet
&lt;/h2&gt;

&lt;p&gt;The migration is done. The design is where I want it, and the site now sits on the kind of infrastructure I prefer: static files, GitHub Pages, a custom domain, and Cloudflare in front.&lt;/p&gt;

&lt;p&gt;But there are still things Jetpack handled on WordPress that need replacing properly: analytics, subscriber capture, automatic emails, and newsletters. When I started looking at this, it became clear that there are limited low-cost integrated toolsets for the GitHub Pages blogger. There is no direct equivalent of what Jetpack offered WordPress users.&lt;/p&gt;

&lt;p&gt;The components all exist. Nobody has bundled them in quite the same way.&lt;/p&gt;

&lt;p&gt;That is the next problem to solve.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>wordpress</category>
      <category>github</category>
      <category>hugo</category>
    </item>
    <item>
      <title>Agents Don't Replace APIs. They Expose How Weak Most APIs Already Are</title>
      <dc:creator>Simon Griffiths</dc:creator>
      <pubDate>Tue, 02 Jun 2026 07:06:36 +0000</pubDate>
      <link>https://dev.to/simongriffiths/agents-dont-replace-apis-they-expose-how-weak-most-apis-already-are-255p</link>
      <guid>https://dev.to/simongriffiths/agents-dont-replace-apis-they-expose-how-weak-most-apis-already-are-255p</guid>
      <description>&lt;h1&gt;
  
  
  Agents Don't Replace APIs. They Expose How Weak Most APIs Already Are
&lt;/h1&gt;

&lt;p&gt;There is a growing narrative that AI agents, often coupled with things like Model Context Protocol, will replace APIs.&lt;/p&gt;

&lt;p&gt;It is easy to see why that idea has taken hold. Agents can discover tools, reason about which one to call, and assemble workflows at runtime. That feels very different from the static integrations we have lived with for years, where one system calls another through a fixed endpoint, with a fixed payload, in a fixed sequence.&lt;/p&gt;

&lt;p&gt;But the conclusion does not hold.&lt;/p&gt;

&lt;p&gt;Agents do not replace APIs. They depend on them. What they really do is expose how fragile many APIs already are.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Illusion of Replacement
&lt;/h2&gt;

&lt;p&gt;Model Context Protocol and similar approaches change the control plane. They give agents a way to discover available tools, inspect descriptions, decide what looks relevant, and make calls based on inferred intent.&lt;/p&gt;

&lt;p&gt;That is useful. It is also easy to mistake for something bigger than it is.&lt;/p&gt;

&lt;p&gt;Underneath the agent-facing description, the work is still being done by the same kinds of things we already understand: HTTP endpoints, structured payloads, authenticated operations, services, data stores, and event streams. The agent may decide what to call dynamically, but the thing being called still has to behave deterministically.&lt;/p&gt;

&lt;p&gt;This is the first important distinction. MCP standardises how agents find and call tools. It does not remove the execution layer underneath those tools. If anything, it makes that layer more important, because the caller is now less predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Most APIs Were Never Designed To Be Open
&lt;/h2&gt;

&lt;p&gt;The uncomfortable truth is that many APIs are not really general-purpose interfaces. They are backends for a known application.&lt;/p&gt;

&lt;p&gt;That is not an insult. It is how most systems have been built for perfectly understandable reasons. A React front end needs data in a certain shape. A mobile app has a known journey. A partner integration follows a negotiated flow. The API evolves around those consumers, and over time the contract absorbs assumptions that everyone involved understands without needing to write them down.&lt;/p&gt;

&lt;p&gt;The caller is known. The sequence is known. The context is shared.&lt;/p&gt;

&lt;p&gt;That works well enough when the API is really part of a larger application boundary. It becomes much more brittle when the consumer is an agent that has not inherited the surrounding context.&lt;/p&gt;

&lt;p&gt;An agent does not know which endpoint was built only for a particular screen. It does not know that a field is only valid after a previous call has initialised some state. It does not know that an operation is safe only because the front end normally prevents users from reaching it in the wrong sequence. It sees a tool, a name, a description, and a schema. Then it reasons from what has been exposed.&lt;/p&gt;

&lt;p&gt;I saw this pattern directly on a &lt;code&gt;modifyCustomer&lt;/code&gt; API I once worked with. It had originally been designed as a universal back-end operation: one customer modification surface that could be used by more than one channel. In practice, the contract was gradually shaped around the assumptions of a particular front end. The input model included fields only that front end had access to, and it relied on context that existed in the screen flow rather than in the API itself.&lt;/p&gt;

&lt;p&gt;The result was an API that still looked universal from the outside, but could not be safely called from anywhere else. The contract had absorbed the assumptions of its first consumer.&lt;/p&gt;

&lt;p&gt;That is where APIs that looked clean suddenly become fragile. Not because they were badly engineered in the narrow sense, but because they were designed inside a relationship of shared assumptions. Agents weaken that relationship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open APIs Are A Different Discipline
&lt;/h2&gt;

&lt;p&gt;Designing an API that can be safely used by any caller is different from building an application backend.&lt;/p&gt;

&lt;p&gt;The difference is not just documentation. It is the level of explicitness in the contract. A genuinely open API has to carry more of its own meaning. It needs operation names that reflect business intent, not just implementation convenience. It needs payloads that are stable and understandable outside the original client. It needs predictable behaviour, clear failure modes, narrow authority, and minimal reliance on hidden sequence or surrounding UI logic.&lt;/p&gt;

&lt;p&gt;In other words, the API has to stand on its own.&lt;/p&gt;

&lt;p&gt;That is much closer to building a platform surface than exposing the internal workings of an application. It is harder work, and it is one reason genuinely reusable APIs are rarer than most organisations like to admit.&lt;/p&gt;

&lt;p&gt;We have often treated "API" as if it were a transport choice. Put JSON over HTTP, publish a schema, and the system has an API. But the transport was never the hard part. The hard part is whether the interface expresses enough meaning for an unknown consumer to use it correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agents Move The Burden Onto The Contract
&lt;/h2&gt;

&lt;p&gt;Agents introduce probabilistic orchestration into systems that were mostly designed around deterministic flows.&lt;/p&gt;

&lt;p&gt;That matters because the API can no longer rely on the caller behaving in the expected way. A human-written integration usually follows a known path. It was tested against the intended use case. It encodes a set of assumptions made by developers on both sides.&lt;/p&gt;

&lt;p&gt;An agent composes at runtime. It may call tools in combinations the API designer did not anticipate. It may infer intent from an incomplete prompt. It may treat two operations as equivalent because their descriptions sound similar. It may be perfectly well intentioned and still be wrong.&lt;/p&gt;

&lt;p&gt;When that happens, the burden shifts to the API contract. The contract has to be predictable enough, explicit enough, and narrow enough that misuse is either prevented or fails safely.&lt;/p&gt;

&lt;p&gt;This is where common weaknesses become much more visible. Ambiguous names matter more. Overloaded endpoints matter more. Loose schemas matter more. Broad security models matter more. They were always architectural problems, but human developers often compensated for them with judgement, local knowledge, and testing. Agents remove much of that safety net.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Changes
&lt;/h2&gt;

&lt;p&gt;The shift is not "APIs versus agents". That is the wrong framing.&lt;/p&gt;

&lt;p&gt;The real shift is from static integration to dynamic composition. Instead of a predefined workflow calling a known set of services in a known order, we now have systems where the choice of tool may be made at runtime. The orchestration layer becomes more flexible, but the execution layer still has to do the real work.&lt;/p&gt;

&lt;p&gt;That execution layer remains APIs, services, data stores, queues, and event streams. Nothing about agents makes those responsibilities disappear. If anything, agents make the quality of those interfaces more important, because more of the system's behaviour now depends on whether they can be safely understood and composed.&lt;/p&gt;

&lt;p&gt;This is why the replacement narrative is misleading. It focuses attention on the agent framework, when the more important question is whether the systems underneath are fit to be called by something operating without the assumptions of the original application.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Uncomfortable Conclusion
&lt;/h2&gt;

&lt;p&gt;Agents are not a shortcut around architecture.&lt;/p&gt;

&lt;p&gt;They are a forcing function.&lt;/p&gt;

&lt;p&gt;They force us to confront weak API design, poorly defined data boundaries, inconsistent contracts, and security assumptions that depended too heavily on a well-behaved caller. They expose the difference between an API that works for a known client and an API that can be safely used as a general capability.&lt;/p&gt;

&lt;p&gt;That distinction is going to matter more as agentic systems move from demos into real enterprise environments.&lt;/p&gt;

&lt;p&gt;If you are building for an agent-driven world, the priority is not the agent framework. It is the execution layer behind it.&lt;/p&gt;

&lt;p&gt;Because agents do not replace APIs. They make it impossible to ignore how good, or bad, those APIs really are.&lt;/p&gt;

&lt;p&gt;But even if APIs remain central, the way we design them is starting to break. We have seen that pattern before, and the lesson is older than the current agent wave. It starts with SOA.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>mcp</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Why You Should Change Your Debit Card Now</title>
      <dc:creator>Simon Griffiths</dc:creator>
      <pubDate>Mon, 01 Jun 2026 16:24:45 +0000</pubDate>
      <link>https://dev.to/simongriffiths/why-you-should-change-your-debit-card-now-2764</link>
      <guid>https://dev.to/simongriffiths/why-you-should-change-your-debit-card-now-2764</guid>
      <description>&lt;p&gt;There’s a piece of advice you won’t hear from your bank. Not because they don’t know — their security teams absolutely do — but because saying it out loud is uncomfortable when you’re also in the business of reassuring people that everything is fine.&lt;/p&gt;

&lt;p&gt;So I’ll say it instead: if your debit card is more than a couple of years old and you’ve used it on smaller websites, you should replace it. Now, not eventually.&lt;/p&gt;

&lt;p&gt;Here’s why.&lt;/p&gt;




&lt;h2&gt;
  
  
  Something just changed
&lt;/h2&gt;

&lt;p&gt;In April 2026, Anthropic — the AI company behind the Claude family of models — quietly announced something significant. Their latest model, Claude Mythos Preview, had been used internally to find thousands of previously unknown security vulnerabilities across every major operating system and every major web browser. Many of these bugs had survived for decades undetected. One was 27 years old.&lt;/p&gt;

&lt;p&gt;That’s notable, but not the part that matters most for you.&lt;/p&gt;

&lt;p&gt;What matters is this: the model didn’t just find the vulnerabilities. It wrote working exploit code. Autonomously. On the first attempt, more than 83% of the time. And it can do the same thing with closed-source software — taking a compiled binary with no source code available, reverse-engineering it, and finding the holes.&lt;/p&gt;

&lt;p&gt;This isn’t a research curiosity. It represents a fundamental shift in who can attack what, and at what cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  The assumption that kept you relatively safe
&lt;/h2&gt;

&lt;p&gt;For most of the internet’s commercial history, there was an implicit triage happening in the world of cybercrime. Sophisticated attacks — the kind that could exploit subtle vulnerabilities in obscure software — required serious skill and time. That meant attackers focused on high-value targets: large retailers, payment processors, banks.&lt;/p&gt;

&lt;p&gt;The small online shop running an older version of WooCommerce, or the regional business with a custom checkout built in Node.js five years ago and touched infrequently since — these weren’t worth the effort. Not because they were secure. Because exploiting them required more skilled attacker time than the return justified.&lt;/p&gt;

&lt;p&gt;That constraint has now effectively gone.&lt;/p&gt;

&lt;p&gt;The economics of targeting have collapsed. What previously required a skilled security researcher working for days now takes an AI model a few minutes and costs a fraction of a penny per attempt. Mass automated scanning and exploitation of long-tail targets — the thousands of small sites that collectively hold a lot of card data — is now viable at industrial scale.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this means for your debit card specifically
&lt;/h2&gt;

&lt;p&gt;Every time you’ve used your debit card on a smaller website, you’ve trusted that site’s security. Some of those sites were fine. Some were running software with known vulnerabilities they hadn’t patched. Some may have been quietly compromised without ever knowing it — or without it ever making the news.&lt;/p&gt;

&lt;p&gt;Your card details from those transactions may already exist somewhere they shouldn’t. You have no way of knowing.&lt;/p&gt;

&lt;p&gt;The four-year-old debit card in your wallet carries four years of that history.&lt;/p&gt;

&lt;p&gt;And debit cards carry a specific risk that credit cards don’t: fraud hits your actual bank balance. You’re not disputing a charge on borrowed money while your life continues normally. You’re potentially short on real funds while a dispute resolves — and disputes take time.&lt;/p&gt;




&lt;h2&gt;
  
  
  The practical response
&lt;/h2&gt;

&lt;p&gt;None of this requires paranoia. It requires a modest update to your habits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replace the card.&lt;/strong&gt; Call your bank and request a replacement. It’s free, it takes a few days, and it closes the window on any previously harvested card number. Whatever exists in the wild from your old transactions becomes useless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Switch to Apple Pay or Google Pay for online purchases where you can.&lt;/strong&gt; When you pay via these services, the merchant receives a one-time token — not your actual card number. There is nothing reusable to steal. This is the single most effective change most people can make.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the occasional site that doesn’t accept digital wallets&lt;/strong&gt;, consider a prepaid or virtual card with a low limit — something like a Revolut disposable card — as a sacrificial layer. Your real card stays out of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Move online spend to a credit card rather than debit&lt;/strong&gt; where possible. The consumer protections are equivalent, but fraud on a credit card doesn’t drain your bank account while the dispute works through the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check haveibeenpwned.com&lt;/strong&gt; — enter your email address and it will tell you which known data breaches your details have appeared in. It won’t tell you everything, but it gives you a factual baseline rather than uncertainty.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why your bank isn’t telling you this
&lt;/h2&gt;

&lt;p&gt;Partly institutional lag — this shift is recent and bank customer communications move slowly. Partly because the advice implies their merchant ecosystem has a problem, which is an uncomfortable thing to say when those merchants are also customers. And partly because telling you to use Apple Pay is, from their perspective, endorsing a competitor’s product.&lt;/p&gt;

&lt;p&gt;Their fraud teams know the landscape has changed. That awareness has not yet reached the leaflet in your online banking app.&lt;/p&gt;

&lt;p&gt;The advice here is about twelve to eighteen months ahead of what mainstream consumer guidance will eventually catch up to. Acting on it now costs you nothing except a few minutes on the phone to your bank.&lt;/p&gt;

&lt;p&gt;That seems like a reasonable trade.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
    </item>
    <item>
      <title>Building Your First Real GPT Is Not a Prompting Exercise</title>
      <dc:creator>Simon Griffiths</dc:creator>
      <pubDate>Fri, 29 May 2026 10:58:31 +0000</pubDate>
      <link>https://dev.to/simongriffiths/building-your-first-real-gpt-is-not-a-prompting-exercise-2p30</link>
      <guid>https://dev.to/simongriffiths/building-your-first-real-gpt-is-not-a-prompting-exercise-2p30</guid>
      <description>&lt;p&gt;I recently built my first non-trivial GPT.&lt;/p&gt;

&lt;p&gt;The interesting lesson was not about clever prompting. It was almost the opposite.&lt;/p&gt;

&lt;p&gt;The GPT only started to become useful when I stopped treating it as something I could configure with a good instruction and a pile of documents, and started treating it as a small software project: source material, structure, behaviour, tests, iteration, version control.&lt;/p&gt;

&lt;p&gt;That sounds obvious after the event. It was not obvious at the start.&lt;/p&gt;

&lt;h2&gt;
  
  
  The First Attempt Failed in a Familiar Way
&lt;/h2&gt;

&lt;p&gt;My first attempt was probably the default path most people take.&lt;/p&gt;

&lt;p&gt;I uploaded a set of existing documents, wrote a reasonably sensible instruction, and expected the GPT to work out the rest.&lt;/p&gt;

&lt;p&gt;It did not.&lt;/p&gt;

&lt;p&gt;The answers were not terrible. That was part of the problem. They were plausible, broadly relevant, and occasionally useful. But they were also vague, inconsistent, and too willing to drift away from the standards I was trying to enforce.&lt;/p&gt;

&lt;p&gt;The real warning sign was repeatability. Ask the same question more than once and the answer would shift in ways that mattered. Nothing was obviously broken, but it was not dependable.&lt;/p&gt;

&lt;p&gt;Looking back, the reason is clear. The documents were written for humans, not retrieval. Important guidance was buried inside larger documents. Some assumptions were implicit. The prompt was trying to compensate for weak source material. Behaviour and knowledge were mixed together.&lt;/p&gt;

&lt;p&gt;At that point I stopped tuning and started again.&lt;/p&gt;

&lt;p&gt;That was the right decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Knowledge Base Matters More Than the Prompt
&lt;/h2&gt;

&lt;p&gt;The second attempt started with the documents, not the GPT instructions.&lt;/p&gt;

&lt;p&gt;I took the source material and converted it into Markdown. Then I stripped out noise, removed irrelevant sections, and reorganised the content around topics rather than original documents.&lt;/p&gt;

&lt;p&gt;That distinction matters.&lt;/p&gt;

&lt;p&gt;A document written for a human reader usually has a narrative structure. It explains, introduces, repeats, and provides context. That is useful when someone is reading from start to finish. It is much less useful when a GPT is trying to retrieve the right fragment of knowledge in response to a specific question.&lt;/p&gt;

&lt;p&gt;For retrieval, the unit of structure needs to be smaller and sharper.&lt;/p&gt;

&lt;p&gt;Instead of preserving large documents, I split the material into focused modules: one for each area of knowledge that needed to be used accessed and used together - essentially split into topics. Each file had a job. Each one answered a class of question. This was especially important if similar informaiton was split over many source files.&lt;/p&gt;

&lt;p&gt;This was the first real improvement. Not a better prompt. Better source structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Restructuring Exposes the Gaps
&lt;/h2&gt;

&lt;p&gt;Once the material was split into modules, the gaps became much easier to see.&lt;/p&gt;

&lt;p&gt;Some processes were missing steps. Some terms were used inconsistently. Some guidance depended on knowledge that had never been written down because, in the original context, everyone involved already knew it.&lt;/p&gt;

&lt;p&gt;That is the awkward thing about turning human knowledge into machine-usable knowledge. You find out how much of the contract was never in the text.&lt;/p&gt;

&lt;p&gt;So I added missing sections, standardised terminology, and made assumptions explicit. I did not try to make the documents longer. I tried to make them less ambiguous.&lt;/p&gt;

&lt;p&gt;This made a bigger difference than I expected.&lt;/p&gt;

&lt;p&gt;The GPT became more stable not because it had been told to be stable, but because the material it retrieved was clearer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Codex Became the Build Tool
&lt;/h2&gt;

&lt;p&gt;This was not a manual editing exercise.&lt;/p&gt;

&lt;p&gt;I used Codex to do the heavy lifting: converting source material into Markdown, splitting files, reorganising sections, identifying missing topics, and checking consistency across the knowledge base.&lt;/p&gt;

&lt;p&gt;That changed the economics of the work.&lt;/p&gt;

&lt;p&gt;Manually doing this across many files would have been slow and error-prone. With Codex, the work became iterative. I could ask it to restructure a set of files, inspect the result, correct the direction, and run another pass.&lt;/p&gt;

&lt;p&gt;This is where the process started to feel less like writing a prompt and more like shaping a codebase.&lt;/p&gt;

&lt;p&gt;The files mattered. The structure mattered. The naming mattered. Repetition and ambiguity mattered. The same instincts you use when cleaning up software applied here too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Prompt Is the Control Layer
&lt;/h2&gt;

&lt;p&gt;Only after the knowledge base was in reasonable shape did I write the main instruction.&lt;/p&gt;

&lt;p&gt;This is the opposite of how I started.&lt;/p&gt;

&lt;p&gt;The main prompt should not duplicate the knowledge base. If it tries to do that, it becomes bloated, fragile, and hard to reason about. Its job is to define behaviour:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the GPT is for&lt;/li&gt;
&lt;li&gt;how it should answer&lt;/li&gt;
&lt;li&gt;when it should use the knowledge files&lt;/li&gt;
&lt;li&gt;what it should do when the answer is uncertain&lt;/li&gt;
&lt;li&gt;what standards it should not compromise&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I kept the instruction deliberately constrained. The more knowledge I pushed into the prompt, the worse the design became. The prompt is not the application. It is the control layer.&lt;/p&gt;

&lt;p&gt;That separation between behaviour and knowledge is probably the most important design principle I took from the exercise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Has to Start Earlier Than Feels Natural
&lt;/h2&gt;

&lt;p&gt;The other mistake I made was leaving test questions too late.&lt;/p&gt;

&lt;p&gt;I eventually built a small test set covering normal questions, edge cases, ambiguous requests, and questions where the GPT should refuse to invent an answer.&lt;/p&gt;

&lt;p&gt;That should have existed earlier.&lt;/p&gt;

&lt;p&gt;Without a test set, you are just having a conversation with the GPT and deciding whether it feels better. That is not enough. The model can improve in one area while regressing in another. It can produce one excellent answer and still fail the same class of question five minutes later.&lt;/p&gt;

&lt;p&gt;Testing gave me a way to see whether the system was becoming more reliable, not just more impressive.&lt;/p&gt;

&lt;p&gt;I also found it useful to test in Codex before moving into the GPT builder. Codex was faster for file-level iteration, easier for inspecting the knowledge base, and better suited to making structural changes. But that did not remove the need to test again in the actual GPT runtime.&lt;/p&gt;

&lt;p&gt;The two environments behaved differently enough to matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Codex and GPT Runtime Are Not the Same Thing
&lt;/h2&gt;

&lt;p&gt;This was one of the more practical lessons.&lt;/p&gt;

&lt;p&gt;Something that worked well in Codex did not always behave identically once deployed as a GPT. Retrieval could differ. Tone could shift. A file that seemed obvious in the build environment might not be used in the way I expected at runtime.&lt;/p&gt;

&lt;p&gt;So the workflow became a loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build and restructure in Codex&lt;/li&gt;
&lt;li&gt;Test in Codex&lt;/li&gt;
&lt;li&gt;Deploy to the GPT&lt;/li&gt;
&lt;li&gt;Test again&lt;/li&gt;
&lt;li&gt;Fix the source material, not just the prompt&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last point matters.&lt;/p&gt;

&lt;p&gt;When a GPT gives a weak answer, the temptation is to add another instruction. Sometimes that is right. More often, the problem is lower down: the relevant knowledge file is too vague, too large, badly named, or missing the thing the model needs.&lt;/p&gt;

&lt;p&gt;Prompt patches feel quick, but they accumulate into a mess.&lt;/p&gt;

&lt;p&gt;Fixing the source is slower in the moment and better over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Is Not Optional Once This Becomes Serious
&lt;/h2&gt;

&lt;p&gt;As soon as the GPT became a multi-file system, Git became necessary.&lt;/p&gt;

&lt;p&gt;I wanted version history for the knowledge files, the main instruction, and the test questions. I wanted to be able to experiment, roll back, compare approaches, and understand why the GPT had changed.&lt;/p&gt;

&lt;p&gt;Without Git, the process would have become guesswork very quickly.&lt;/p&gt;

&lt;p&gt;This is another reason the exercise felt more like software than prompting. Once you have source files, build steps, tests, and runtime behaviour, you are no longer just configuring a chatbot. You are maintaining a system.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Would Do Differently
&lt;/h2&gt;

&lt;p&gt;Next time, I would start with a module map.&lt;/p&gt;

&lt;p&gt;In this build, the modules emerged from the documents I already had. That worked, but it was backward. A better approach is to begin with the questions the GPT needs to answer, the domains it needs to understand, and the boundaries between them.&lt;/p&gt;

&lt;p&gt;Then the documents can be shaped to fit the model, rather than the model inheriting the accidental structure of the documents.&lt;/p&gt;

&lt;p&gt;I would also split files more aggressively. Some of my early modules were still too broad. Smaller files retrieved more cleanly and produced less noise in the answers.&lt;/p&gt;

&lt;p&gt;I would separate reference material from process material more deliberately. "How this works" and "how to do this" are different kinds of knowledge. Mixing them makes retrieval less predictable.&lt;/p&gt;

&lt;p&gt;And I would define the test cases at the same time as the module map, not after the first working version. Tests are not a final validation step. They are part of the design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Lesson
&lt;/h2&gt;

&lt;p&gt;The tooling makes GPT creation look simple.&lt;/p&gt;

&lt;p&gt;In a trivial case, it probably is.&lt;/p&gt;

&lt;p&gt;But if you want a GPT that behaves consistently, reflects a real body of knowledge, and gives answers you are prepared to rely on, the work is more structured than the interface suggests.&lt;/p&gt;

&lt;p&gt;You are not just writing a prompt.&lt;/p&gt;

&lt;p&gt;You are designing a knowledge base, a behaviour layer, and a feedback loop.&lt;/p&gt;

&lt;p&gt;That is much closer to software engineering than most of the current language around GPTs implies.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>chatgpt</category>
      <category>llm</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>The Microservice Debt Collectors Have Arrived</title>
      <dc:creator>Simon Griffiths</dc:creator>
      <pubDate>Wed, 27 May 2026 19:21:19 +0000</pubDate>
      <link>https://dev.to/simongriffiths/the-microservice-debt-collectors-have-arrived-1l1j</link>
      <guid>https://dev.to/simongriffiths/the-microservice-debt-collectors-have-arrived-1l1j</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://simongriffiths.io/2026/05/27/the-microservice-debt-collectors-have-arrived/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real risk of AI agents in production systems is not that they write bad code. It is that they interact with systems whose integrity rules were moved out of shared infrastructure and into convention.&lt;/p&gt;

&lt;p&gt;I've been thinking about how AI Agents and Microservice Architectures interact, and there are some real challenges to address - follow the link for the full article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://simongriffiths.io/2026/05/27/the-microservice-debt-collectors-have-arrived/" rel="noopener noreferrer"&gt;The Microservice Debt Collectors Have Arrived&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>microservices</category>
      <category>agents</category>
      <category>api</category>
    </item>
  </channel>
</rss>
