DEV Community

Cover image for STF: from semantic inference to semantic publication
bswvladimir-beep
bswvladimir-beep

Posted on

STF: from semantic inference to semantic publication

The web was built for one reader: a human. You open a store, see a product card, a price, a button, and you instantly know what it is. The browser renders it, you interpret it.

Agents have it harder. To compare prices or click the right button, an agent first has to reconstruct the meaning of an interface from its markup - through the DOM, an accessibility tree, a screenshot, or some mix of all three. The tools for doing this keep getting better. But there's a simple question worth asking: if the application already knows what its interface means, why make the agent re-derive that meaning from the markup every single time?

What follows is a different architectural proposal: instead of extracting semantics from the presentation layer, publish them directly. That takes two layers.

STF (Semantic Text Format) is a representation language: a way to write down objects, relationships, and data provenance, independent of what's actually being described.

SIL (Semantic Interface Layer) is an application-level profile of that language for the web: the specific way an application publishes its state, actions, and events on top of STF.

The distinction is simple. STF is a language you can use to write down more or less anything. SIL is what a given web application actually writes down with it. This isn't a replacement for HTML, REST, or MCP - it's an additional contract between an application and an agent.


Extraction or publication

Take a pricing card. To the application, 399 EUR is a price, Pro is a plan name, and the Buy button is a purchase action. In HTML it usually looks like this:

 class="card pricing-card flex flex-col gap-4">
     class="text-xl font-bold">Pro
class="price">399.00EUR
class="btn btn-primary">Buy
Enter fullscreen mode Exit fullscreen mode

A human reads this in a fraction of a second. An agent has to guess which div is the card, where the price is, what period it applies to, whether the button is active, what happens after the click.

Tools like Plasmate handle this reasonably well: they take the HTML, run the JS through V8, build a semantic model of the page out of the result, and hand that to the agent. It genuinely cuts down the work of parsing markup. But at its core, this is still extraction: the agent gets the application and reconstructs its meaning on its own.

HTML / DOM → semantic extraction → structure → agent
Enter fullscreen mode Exit fullscreen mode

The alternative is publication: the application hands over the semantics of its own state, because it already has them - in domain objects, business rules, access permissions. Not because there's some separate "semantic snapshot" sitting around somewhere, but because the server already holds everything needed to produce one.

Application → HTML → human
            → SIL  → agent
Enter fullscreen mode Exit fullscreen mode

Neither option is universally better. But this is a different class of architecture, and it's worth looking at on its own terms.


Where the real line is

As long as we're talking about Button and Price, that's not really SIL's strength yet - it's just a tidier way of writing down what you could already pull from the DOM. A good semantic browser like Plasmate handles that just fine.

The gap becomes real once the semantics stop being UI semantics and start being domain semantics. Here's a fragment from an actual .sil endpoint on a live application (ais-platform.dev/revizor/pricing.sil):

PlanIndieSubscription
    Type: Card
    Role: PricingCard
    Caption: Indie
    State: Disabled
    Actions: Activate (authentication required)
    Price: $138.73
    FullPrice: $149.00
    Trial: 14 days free
    LockIn: Buy now and this price becomes your maximum subscription renewal price.
    Pricing: Early-user price (ramp active). Full price will apply from September 1, 2026.
Enter fullscreen mode Exit fullscreen mode

And a bit further down, in a general block on the same page:

Sunday Unlimited
    Content: Every Sunday, all operations are free for everyone -
    regardless of tier.
Enter fullscreen mode Exit fullscreen mode

None of this is required to show up in an HTML card. A scraper can get you $138.73, at best. It won't tell you that this is a ramp-period price, that buying now locks it in permanently, that the full price kicks in on September 1st, or that everything's free on Sundays regardless of tier - simply because the frontend has no obligation to render any of that on screen, pixel for pixel. The application knows it. It can just say it.

This is the point where a semantic browser can't recover the same information from the DOM, if the application never put it there in the first place - not because it reads the DOM worse, but because part of the semantics an agent needs simply doesn't exist in the DOM.


How this is built

STF splits into three layers. Syntax - nesting, properties, values, escaping; a parser at this level has no idea what Button even means. Object model - this is where Type, Role, Id, Actions, State come in. Provenance and trust boundaries - where a claim came from: Application, Backend, Agent, Human, External. STF is deliberately text-based: you can carry it as part of an HTTP response, drop it in a log, version it in git, feed it to a model with no fine-tuning - while a parser validates the structure independently of whatever LLM is reading it.

SIL is how a given web application actually uses this language: publishing state, actions, constraints, and events. Discovery is straightforward:

GET /.well-known/sil
[{ "path": "/.sil", "profile": "core forms events agent-spaces" }]
Enter fullscreen mode Exit fullscreen mode

The JSON here is just a transport envelope for one utility request - not STF itself. The application's actual state (Product, Context, events) is written in STF syntax; JSON only shows up where you need a minimal protocol layer on top of HTTP.

A hamburger menu is just an icon to a human. To an agent, it's a MainNavigation object in a Collapsed state with an available Expand action. No guessing whether it's a

Top comments (0)