Blog /
Apps as Abilities deep dive: building a real-estate vertical pack
The earlier Apps as Abilities post explained the mechanism: a DSGo App’s manifest can declare abilities.publishes, the plugin registers each ability with WordPress’s Abilities API, and the site’s AI agent can invoke them.
This post is the worked example I should have written earlier. A real-estate vertical pack: ten DSGo Apps, each one publishing two to three abilities, all installable as one bundle. Together they turn a generic WordPress site into a real-estate-aware assistant. The AI agent in wp-admin can answer “what listings are over a million dollars in this neighborhood” or “calculate the mortgage on this property at 6.5% for 30 years” or “draft a follow-up to the lead who toured the Kensington property” without the operator knowing which app did which.
This is the second moat I keep talking about. Here’s what it looks like in practice.
The pack
Ten apps, each focused on a single real-estate concept:
| App | Abilities published |
|---|---|
listings-search |
listings/search, listings/get-detail |
mortgage-calculator |
mortgage/calculate-payment, mortgage/amortization-schedule |
area-stats |
area/median-price, area/days-on-market, area/sales-trend |
school-data |
area/school-ratings, area/school-distance |
commute-calculator |
area/commute-time, area/commute-modes |
lead-tracker |
leads/list, leads/get-context, leads/log-interaction |
tour-scheduler |
tours/list-availability, tours/book |
comp-analyzer |
comps/find-similar, comps/price-suggestion |
email-templates |
email/render-followup, email/render-listing-blast |
disclosure-checker |
disclosure/check-required, disclosure/list-jurisdictions |
Each app is small (a few hundred lines of HTML/JS each). Each one publishes two or three abilities. None of them are visible as URLs the user navigates to; they’re all hidden-iframe ability publishers. The agency installs one bundle; ten apps register quietly; twenty-six abilities show up in the site’s Abilities registry.
Twenty-six abilities, ten apps, one install. A ZIP bundle the agency drops into the site. The agent on the site now knows real-estate.
What the agent does with this
Imagine a real-estate agency’s site agent (running in wp-admin) gets prompts from the operator like:
Operator: I have a buyer interested in 3-bedroom homes under $850K in the 78704 zip code. Show me the recent listings, what comparable homes have sold for, and the median days on market.
The agent (without the pack installed) would respond with a generic “I don’t have access to listing data on this site.” With the pack installed, the agent’s ability list now includes listings/search, comps/find-similar, and area/days-on-market. The agent reasons:
- “I should call
listings/searchwithbedrooms: 3, max_price: 850000, zip: 78704.” - “Then
comps/find-similarfor each result, to know what they could be priced at.” - “Then
area/days-on-marketfor that zip to understand the market context.”
The agent runs all three. Each ability invocation mounts the corresponding app’s hidden iframe handler. Each handler returns structured JSON. The agent composes the response: a table of listings with their prices, comparable sales, and the area’s days-on-market trend.
The operator didn’t tell the agent which apps to use. The agent picked them based on the ability descriptions, the input/output schemas, and the prompt’s intent. Each app worked in isolation. The composition was the agent’s job. The operator’s experience is that they asked a question and got a structured, useful answer; the apps are invisible to them.
What makes the pack work
A few patterns the pack relies on, explicitly:
Namespaced ability names. Every ability in the pack starts with listings/, mortgage/, area/, leads/, etc. The agent picks tools by name, and the namespace makes the intent obvious. listings/search is for searching listings; the model never confuses it with comps/find-similar (which finds comparable sales of past sold properties). Without the namespace, the agent would have to disambiguate from descriptions alone, which works less reliably.
Specific input/output schemas. Each ability declares a typed input schema and a typed output schema. The agent reads these to figure out what it can pass and what it gets back. Vague schemas produce sloppy compositions; specific schemas produce reliable ones. A listings/search schema with bedrooms: integer, max_price: number, zip: string, status: enum[active,pending] is the kind of schema the agent can use confidently. A schema with query: string, options: object is the kind that produces “agent passed nonsense and got nonsense back” failures.
Read-only by default. Most of the abilities in the pack have readonly: true annotations. The agent knows it can call them freely without risk of side effects. The handful that aren’t (leads/log-interaction, tours/book) are explicitly marked destructive: true, which signals to the agent that it should confirm before invoking. This is the difference between an agent that calls fifty tools in sequence to answer a question (fine, all read-only) and one that books fifty tours by accident (catastrophe, all destructive).
Idempotent where possible. mortgage/calculate-payment is idempotent: same inputs, same output, no state change. The agent can call it ten times without consequence, which means it can use it in tool-call chains without bookkeeping. Mark idempotent abilities as such; the agent’s planning improves when it can rely on the marker.
Each app handles one thing. No app publishes seven abilities; the upper bound (eight) exists but the pack stays under it. Apps that try to do too much get unwieldy; apps that do one thing well are easy for the agent to reason about, easy to update independently, and easy to deprecate if needed. The pack’s ten-apps split is deliberate; it could have been five apps with five abilities each, but the smaller apps version is more maintainable.
What the operator buys
This is the real-estate-agency value prop:
- A general-purpose AI agent that knows their data, their domain, and their tools.
- No bespoke agent integration work. The agency installed the pack. The agent picked it up. There was no engineering project to “teach the agent about our business.”
- A low-cost moat over generic agencies. A competing real-estate site running the default WP AI surface gets a generic agent. This agency’s agent answers questions theirs can’t. Over time, that compounds into “everyone in the office prefers our internal tools to the public ones,” which is the kind of subtle advantage that doesn’t show up in a sales deck but shows up in retention.
- Composability with other plugins. Yoast’s SEO abilities are still available. WooCommerce’s commerce abilities (if Woo is installed) are still available. The pack adds, doesn’t replace.
The vertical-pack model means an agency can pay for one bundle that does ten things, instead of paying for ten separate plugins. The bundle is one install, one update, one trust decision in the install dialog (the dialog lists all the published abilities in one place under a “this pack publishes 26 abilities” expandable group).
What the developer buys (if they make the pack)
This is the developer-of-the-pack value prop:
- A clean unit of distribution. A pack is a collection of DSGo Apps in one bundle. The developer writes ten small apps; the user installs one ZIP.
- Separately versionable apps. The developer can update
mortgage-calculatorwithout touchinglistings-search. Each app’s version is independent. The pack version is a meta-version that pins specific app versions for consistency. - A runtime that handles the agent integration. The developer doesn’t write any agent-integration code. They write each app’s logic, declare the ability in the manifest, and the rest is the runtime’s problem.
- A revenue path. Sell the pack to real-estate agencies as a subscription. Sell different packs (legal-services, fitness-studios, restaurants, art galleries) to other verticals. The runtime is the same; the registry of patterns and the abilities are what each pack contributes.
The vertical-pack model is, structurally, an app store on top of WordPress. Different from the existing plugin directory because the unit of distribution is “abilities the agent can use,” not “settings panels and shortcodes.” The agency’s agent gets smarter with each pack installed; the marketplace gets denser with each pack published.
What’s hard about this
Honest list of where the model breaks down or has rough edges:
Browser-context-only execution. Published abilities run in hidden iframes, which means they only resolve when there’s an active browser session. Server-side callers (WP-CLI, cron, PHP-context invocations) get a structured client_only_ability error. v2 might change this; v1 doesn’t. For most agency use cases the agent runs in the browser anyway, but if you wanted to schedule an “every morning, summarize yesterday’s leads” cron, that abilities call would fail in v1.
Iframe startup cost is real. When the agent calls many different abilities in quick succession, the publisher mounts the corresponding hidden iframes. There’s a startup cost per mount: the iframe has to load the bundle, run its startup script, and register its implement() handlers. The publisher caches recently mounted iframes so back-to-back calls to the same app are cheap, but switching across many apps in one agent turn adds up. For most use cases this is invisible; for high-volume agent workflows it’s a real budget item worth watching.
Schemas are easy to write badly. A vague description, a non-required field that should have been required, an output schema that doesn’t actually match what the handler returns: any of these produce agent compositions that fail mid-flight. Writing good schemas is a skill we underpay attention to in our docs. If your pack’s abilities are flaky in agent use, the first place to look is your schemas.
Eight publishes per app, max. Forces some packs to split into more apps than they otherwise would. This is a deliberate cap to keep individual apps focused, but it can feel arbitrary at the boundary. The pack above respects it by design; some natural decompositions don’t.
The agent’s tool selection is probabilistic. With 26 abilities in the pack, the agent might pick the wrong one occasionally. A mortgage/calculate-payment abilities call when the operator asked about mortgage/amortization-schedule is structurally an agent error, not a pack error, but it shows up to the operator as “the pack didn’t work.” The fix is on the model side; the agent’s tool selection is getting more reliable with each frontier-model release, but it isn’t deterministic.
Where this goes
The vertical-pack model is, in my opinion, the second-most underrated thing about DSGo Apps after the WP 7.0 architecture itself. The first one is straightforward to explain in a tweet. This one takes a deeper walk through the use case before the value lands.
I expect the pack model to be where the most interesting third-party DSGo work happens over the next year. People building real-estate packs, legal-document packs, recipe-site packs, ecommerce-recovery packs, agent-onboarding packs. The runtime is the same for all of them; the registries are different. The first vertical-specific pack from an outside developer that we feature will be a big moment for the platform, because it’ll demonstrate that the pack model isn’t just our internal vision.
If you build a pack and ship it, tell me. I want to feature good ones. The bar isn’t “polished marketing site”; the bar is “this pack genuinely makes the site’s agent smarter for a specific vertical.” If you’ve cleared that bar, I want to hear about it.
Where to go next
- The original Apps as Abilities post for the architectural primer.
- The AI content companion tutorial for a concrete single-app example of publish-side abilities.
- The Bridge API reference for the full
abilities.implementsurface.
Nealey