Increasingly we are allowing AI to be the interpreter, consumer and actor.

For decades we built software for a reader who could fill in the blanks. With AI, we introduced an entity that can’t, not without help.

A human engineer looking at a Subscription carries a model of it that never appears in the code. They know it’s a contract, not a row. They know who owns the decision to cancel it, that there’s a notice period buried in a legal document, that “active” in the status enum doesn’t mean “billable” this month.

None of that lives in the API. It lives partly in a developer portal, partly in an SDK’s type hints, partly in a wiki page nobody has touched since the last reorg, partly in a Slack thread from last quarter, and partly in the one engineer who remembers why. The human stitches it back together every time, for free, so we never paid to make the surfaces or the system carry it.

More and more, the thing consuming that software isn’t a person. We plan with AI, design with AI, and build with AI, and more of the work every month is engineering the context a model needs to understand what we’re actually doing and what our business actually is. The agent is the new consumer of the system. It reads exactly what’s written, with none of the model behind it.

A central glowing cube, the object, linked by flowing lines to four surrounding panels: a network graph, code, data tables, and a dashboard. The four partial views that never add up to the whole.

The surfaces describe shape and events, never identity

Ask what the object is, the business entity the system is actually about, the Subscription or the Invoice or the Account, not the class or the database row but the thing those are projections of, and the system hands back four partial answers, none of which is the object.

The API tells you it has a POST /subscriptions/{id}/cancel. That cancellation is possible. Not whether it’s permitted right now, or who’s allowed to invoke it.

The schema tells you the record has a status of active, past_due, or canceled. The shape of the data. Not what those states oblige.

The logs tell you a cancellation fired at 2:14am and which service called it. The event. Not whether a contract required thirty days’ notice first. The dashboard tells you churn ticked up afterward. The aggregate. Not how the metric is defined, or which underlying thing moved it.

The agent is left to interpret. It has to decide what the object is from four partial views that don’t add up to one.

Take the same scenario and run it across three billing systems and the interpreter’s problem gets worse. A subscription in Stripe, a recurring contract in Adyen, a rate plan hung off an account in Zuora: the same business object, three shapes, three vocabularies.

An experience dev looks at all three and says, correctly, these are the same thing wearing different clothes. Nothing in the wire format says so. The identity that ties them together lives in the integrator’s head.

The risk arrives when the interpreter becomes an actor. A cancellation can clear every readable check, the endpoint exists, the status enum allows it, the caller’s role passes the permission test, and it can still be wrong, because the thing that forbids it, a notice period set in the governing contract, lives on none of those surfaces. Once an agent invokes the call, this mismatch becomes a real consequence.

This shows up everywhere we point machines at meaning. BI computes “revenue” without exposing how revenue is defined across the systems feeding it. Observability fires when a number moves but can’t say whether the policy, contract, or data definition moved underneath it. Governance writes decisions into immutable logs with no durable link back to the object being governed. The machine can act on a record and still not know what the record is.

This isn’t the Semantic Web again, and the difference is scope

It’s fair to ask whether we’ve been here before. People talk about the W3C push for RDF and OWL in the early 2000s like it was a lost golden age. Honestly? I lived through that period and didn’t give a shit about it. It wasn’t part of my world. Designers weren’t invited to the semantic web’s first party. It was an ivory-tower engineering project that felt completely detached from the codebases we were actually shipping. But looking back, the failure wasn’t only ambition. It was scope and timing.

That vision aimed at meaning between organizations. The idea was that if every company described its data with shared, standard vocabularies, one company’s software could understand another’s automatically, with no custom integration in between. It was a plan for the whole web to agree.

The meaning problem most teams actually have is smaller and closer to home. Before any cross-company agreement matters, your own services have to agree on what your own Subscription is: what state it’s in, what’s allowed to happen to it, who owns it. Your agents have to agree on it too, now that they’re acting on it. That agreement doesn’t exist in most systems, and it never crosses a company line. The Semantic Web reached for a coordination problem most teams didn’t have yet and stepped over the one sitting in their own repository.

It also arrived before the ground was ready. There was no cheap graph storage, no ordinary way to attach a stable identifier to an object inside a normal codebase, no standard for carrying typed meaning in a payload. So the ideas survived where someone could afford to curate them by hand, in knowledge graphs and a few enterprise projects, and the everyday codebase never got a meaning layer it could utilize.

Things are different now. JSON makes typed meaning cheap to carry inside a payload. Content-addressable storage gives data a stable handle. MCP-style tool contracts already train services to declare what they do, not just how to call them. The missing piece is a place to put identity and meaning on the object itself, where any agent reads the same thing.

A stack of translucent layered planes with a glowing object-cube on a lower layer connected up to the surface. A meaning layer beneath the visible surfaces.

What an object-native layer carries

That place has to live in the runtime, with the object, not in a wiki or a prompt context the next service never sees. It now exists as an installable package: @kneelinghorse/semantic-protocol, version 3.3.1, MIT, zero dependencies, Node 18+. The claim stops being architectural. It can be tested.

A manifest gives an object one stable, version-aware identity and attaches the things humans used to carry in their heads, its ownership, its policy, the contract it answers to, as first-class fields:

import { createSemanticProtocol, createSemanticCatalog }
  from '@kneelinghorse/semantic-protocol';

const subscription = createSemanticProtocol({
  id: 'acme-subscription',
  element: { type: 'commercial_agreement', name: 'Acme Monthly Plan' },
  context: {
    domain: 'billing',
    protocolBindings: {
      api: ['urn:proto:api:[email protected]'],
      data: ['urn:proto:data:[email protected]']
    }
  },
  governance: { owner: '[email protected]', classification: 'pii' },
  relationships: {
    edges: [{
      type: 'governed_by',
      to: 'urn:proto:semantic:[email protected]',
      reason: 'cancellation terms and notice period',
      via: 'legal'
    }]
  }
});
subscription.manifest().urn; // 'urn:proto:semantic:[email protected]'
subscription.validate().ok;  // true

The URN is the part the four surfaces never gave us. urn:proto:semantic:[email protected] is deterministic and version-aware, so any agent referencing this object knows it’s the same entity across an API bump, a UI rewrite, or a migration. That’s the anchor a human supplied silently and the machine never had. The protocol bindings under context aren’t comments; the package folds them into the object’s graph, so the API contract and the stored record are known to describe this one object. And the governed_by edge carries the thing the cancel scenario was missing: this subscription answers to a master agreement, the reason is recorded, and it’s a traversable edge, not prose in a wiki.

Add the contract as its own object and the agent walks to it instead of inferring it:

const msa = createSemanticProtocol({
  id: 'msa-acme-2026',
  element: { type: 'legal_contract', name: 'Acme Master Agreement 2026' },
  governance: { owner: '[email protected]', classification: 'confidential' }
});

const catalog = createSemanticCatalog([subscription, msa]);
const [contractUrn] = catalog.neighbors(
  'urn:proto:semantic:[email protected]',
  { types: ['governed_by'] }
); // 'urn:proto:semantic:[email protected]'
const governing = catalog.get(contractUrn);
governing.governance.owner; // '[email protected]'

Before the agent touches cancel, its first move stops being “does the endpoint accept this” and becomes “what governs this.” It follows one governed_by edge to the contract, reads that cancellation terms and a notice period live there, and finds out legal owns it. The constraint that was invisible is one hop away and machine-readable.

Be exact about the boundary, because the boundary is the point. The package ships validators that check the manifest’s shape, its bindings, its edges, and its vectors. It doesn’t ship a policy engine. The decision to block the cancel is still your code, reading governance and the edges and applying your rules.

The protocol guarantees the inputs to that decision are explicit, stable, and the same for every agent that looks. It removes the need to guess. It doesn’t make the call for you, and a layer that quietly made the call for you would be the wrong layer. This is the shape of agent-native software: not old endpoints wrapped in a cleaner format for a model to scrape, but the object stating what it is to the machine that’s going to act on it.

It also tells the interpreter when meaning actually moved, which the dashboard couldn’t:

const revised = subscription.set('element.type', 'usage_based_plan');
subscription.diff(revised); // { changes, significant, breaking }

Changing the type from a fixed commercial agreement to a usage-based plan comes back under breaking, because it is. An observability tool would have shown you a number twitch. The diff tells you the object changed identity, which is the thing you needed to know.

This is an architecture problem, not a model problem

The reflex, when an agent does something dumb in production, is to reach for a better model. Sometimes that’s the answer. Usually it isn’t. A more capable model pointed at the same four surfaces is a smarter reader handed the same book with the binding torn out. It will infer more confidently, which is not the same as being more right.

Say it plainly: no amount of downstream reasoning compute compensates for missing upstream semantic structure. The model was never going to reconstruct what no one wrote down. You can’t infer a contract’s notice period from a status enum. If the fact isn’t recorded somewhere the machine can read, intelligence doesn’t invent it, it fills the hole with a plausible guess. We never wrote it down because, for a long time, the human in the loop carried it for free. That consumer isn’t the primary one anymore. The fix isn’t a smarter machine. It’s giving the object a place to state its own identity, its own governing relationships, its own policy context, next to the object, in something built to be read.

We’re not waiting on a smarter reader. We’re behind on giving the one we have something true to read.