kodyw.com

Kody Wildfeuer's blog

kodyw.com

When the Power Comes Back, the AI Estate Should Too

An overnight power outage interrupted my distributed AI estate. I lost progress across network devices, including Mac minis and a Windows battle station.

The recovery problem was bigger than turning the machines back on. A reachable device does not tell me which agent was working, what it had completed, which conversation belonged to it, or what should safely happen next.

That experience made a design question concrete:

How do we centrally restore an AI estate to its last verified recoverable state, rather than reconstructing every interrupted task by hand?

That requires backups, ownership controls, and runtime-specific recovery mechanisms. It also illustrates a broader pattern: data becomes more useful when we record its context and relationships in frames, then derive task-specific views through lenses.

The discipline is to keep source material identifiable and traceable, and derived views distinct from the original evidence.

Here, data augmentation means adding context, relationships, constraints, and useful representations. It does not mean fabricating facts. It also does not necessarily mean fine-tuning a model or applying transformations to training examples.

Start with the difference between data and usable context

This was a continuity problem, not just a dashboard problem. Across a network of AI workers, logs, native chat histories, code changes, runtime configuration, generated artifacts, and records of attempted actions can exist in different places. Having them does not, by itself, tell us how to recover the work.

Before resuming work, we need to establish:

  • Which records belong to the same agent, mission, and runtime instance?
  • Which code, data, and runtime versions were in use?
  • What is directly observed, and what is an interpretation?
  • Which actions have already happened?
  • What survived the outage, and what is safe and authorized to resume?

Those relationships are valuable information. They can make existing data more useful without adding a single invented observation.

The distinction matters especially when an AI system consumes the result. A large pile of text is not the same thing as a bounded, current, evidence-linked working context.

A frame gives the information a stable reference

A frame provides a way to identify a record, retain its version and ordering, and connect it to other records.

For an application using this pattern, the surrounding contract should make clear what the record represents, where its evidence came from, and which other artifacts are needed to interpret it.

Large artifacts do not need to be squeezed into every frame. A record can refer to separately stored material, provided the application can retrieve and verify the referenced bytes.

The important discipline is to keep several concepts separate:

  • Identity: which entity or logical thing this is.
  • Version: which particular content or state was used.
  • Provenance: where the information came from and how a result was derived.
  • Authority: who is allowed to make a particular claim or authorize an action.

RAPP/1’s identity, canonicalization, content-addressing, and frame rules provide a foundation for identifying and linking records. They do not, by themselves, establish truth or authority. A lens, as discussed here, is an application-layer design choice, not a protocol guarantee that a transformation is correct.

A lens makes the information useful for a job

A lens is a declared perspective or transformation over source material.

It selects relevant information, organizes it, and may derive an interpretation for a specific task. The useful part is not merely a different layout. It is an explicit relationship between the source, the purpose, the output, and the limitations.

The same estate records can support several lenses:

Lens Useful output Boundary to preserve
Operator Which machines and missions need attention, and the next safe action A reachable host is distinct from a resumed mission
Agent Its objective, relevant context, last completed step, and next action An old "working" label is not proof that execution survived
Recovery Available checkpoints, dependencies, native references, and unresolved actions A restore plan is not permission to execute it
Governance Decisions, approvals, evidence, and outstanding uncertainty A signature does not make an unsupported claim true

These views can share the same source references without becoming identical.

They also should not quietly rewrite the source. If a lens produces a new interpretation, that result should be a new artifact with explicit provenance. A reader should be able to distinguish “the logs show this” from “the analysis suggests this.”

The recovery experience should be central

The desired experience is not “SSH into every device and guess which command to run again.”

It is one recovery view, backed by explicit state, that can coordinate the estate:

  1. Identify verified surviving instances and reconnect to them without creating duplicates.
  2. Confirm a single current execution owner for each mission before allowing work to resume.
  3. Select a recoverable checkpoint whose required data and keys are actually available.
  4. Restore files, native conversation context, and declared runtime dependencies where needed.
  5. Reconcile actions that may have completed before the outage but lack a recorded result.
  6. Resume authorized work in dependency order and within the capacity of each target machine.
  7. Record what recovered, what remains uncertain, and what requires a human decision.

That is the use case driving RAPP Disaster Recovery.

This describes the recovery behavior we are building toward. Full-estate recovery is not yet operational, and the design does not imply that every device or workload supports automatic failover.

“Where it was” must mean the last durable, verified state plus explicit reconciliation. It cannot mean magically recreating lost RAM, inaccessible provider state, or an unrecorded external action.

If an agent may have sent a message, submitted a job, or changed an external system just before the outage, blindly repeating the step is not recovery. It can create a second incident.

Change the carrier, not the contract

An estate also needs to distinguish a failed communication route from a failed worker.

An emergency messaging carrier such as iMessage is one design option when the normal service connection is unavailable. Bidirectional iMessage control is still a design goal here, not an operational capability.

The fallback should preserve the same logical request, response, identity, authorization, and duplicate-protection rules rather than introduce a different kind of agent.

If a request arrives through the normal route and later appears through an emergency route, it must not execute twice. Human-readable sender labels help people follow the conversation, but they are not substitutes for cryptographic authentication of machine-control records.

This is a control-channel design, not a way to push an entire backup through text messages. It also is not an offline radio: iMessage still needs powered devices and a usable Internet path.

Where the augmentation happens

Context augmentation connects a log entry or observation to its mission, timeframe, runtime environment, and intended use.

Relationship augmentation links records that would otherwise remain isolated: a mission to its native conversation, a checkpoint to its required artifacts, or a decision to its evidence.

Constraint augmentation states what an output may be used for. A result suitable for an internal summary may not be sufficient for an automated production change.

Representation augmentation turns the same supported information into something another consumer can use: a human briefing, an agent’s working context, an audit view, or a recovery checklist.

The goal is to make information easier to use, not to imply that a derived output contains more evidence than its sources.

Reuse can compound value

Without explicit framing, each new workflow tends to reconstruct context from scratch.

A new agent receives a long prompt. A new dashboard copies fields into another schema. A new integration loses the reasons behind earlier decisions. Eventually, different consumers disagree because they are working from different versions or unstated assumptions.

A frame-and-lens approach can make some of that work reusable: the source remains referenceable, the lens declares its purpose, and the derived artifact records how it was produced. A later consumer can build on the result while checking the underlying evidence.

Feedback can become another traceable record rather than an invisible change to the original. That makes it possible to improve a lens without erasing the history of what earlier versions produced.

Portability must be demonstrated, not announced

Moving work from a Mac mini to a different host would make portability a practical concern. The pattern can help describe what a target needs, but it does not justify a blanket “write once, run anywhere” claim.

A target environment might lack a required tool, permission, state representation, or interaction model. Two frameworks can accept superficially similar inputs while producing meaningfully different behavior.

A lens should therefore declare:

  • Its supported input and output contracts.
  • The capabilities it requires from the target.
  • Any information it drops or transforms.
  • Which observable behaviors were evaluated.
  • What it refuses when the target cannot preserve the required meaning.

Compatibility evidence should be specific to the claim. Valid serialization is not evidence of equivalent execution.

Likewise, a frame hash is not a backup. The referenced data must exist, the recovery keys must be usable, and the selected copy must survive the failure being planned for. Two virtual machines on one physical host do not create two independent failure domains.

Keep the contract open without exposing every implementation

An interoperable contract and its implementation are different assets.

A public specification can explain how to describe a capability, represent a projection, link evidence, report limitations, and evaluate the required behavior.

It does not need to disclose every internal compiler decision, optimization, learned mapping, or proprietary evaluation asset.

That separation is valuable: others can understand the contract and build compatible implementations, while an implementation can retain its own engineering advantages.

Existing licenses and disclosures still matter. A public contract is not a mechanism for making already published code secret again.

Measure usefulness rather than output volume

A longer summary or a larger collection of generated artifacts is not automatically an improvement.

Better questions include:

  • Can someone recover the relevant context faster?
  • Can they trace an important claim to its source?
  • Are incompatible versions and unsupported capabilities visible?
  • Does the output reduce ambiguity about the next action?
  • Can another consumer reproduce the relevant interpretation or evaluate its limits?

These are properties to measure in the intended workflow, not benefits to assume.

The underlying idea

The most useful augmentation is often not “more data.”

It is a clearer relationship between evidence, purpose, constraints, and action.

Frames identify and connect records. Lenses help make those records useful in a particular setting. Keeping those responsibilities separate creates room for reuse without sacrificing traceability.

When the power comes back, I want more than reachable machines. I want recoverable work, with enough context to decide what can safely happen next.


Further reading: the public RAPP/1 specification.

This article describes a general architectural pattern. It is not a disclosure of a proprietary engine implementation or a claim of universal cross-framework equivalence.

The Personless Harness: Brainstem + Copilot

In 1895 you didn’t buy a car. You bought a horseless carriage — the new machine named for the animal it removed. The name is the whole lesson: the carriage didn’t change. The wheels, the seats, the cab — all still there. What changed was what pulled it. The horse went out, the engine went in, and the same carriage could suddenly run at a pace no stable could feed.

Here is the same swap, happening right now, in software.

Copilot is the carriage. It’s the vehicle everyone already has — the chat surface, the agents, the buttons, the place work actually rides. It is a genuinely good carriage.

You are the horse. Today, almost everything a copilot does, it does because a person is pulling: typing the prompt, clicking the button, checking the output, deciding what happens next, then pulling again. Call this configuration what it is — You + Copilot, a personed harness. It works exactly the way a horsed carriage worked: beautifully, at the pace of one animal’s attention, and it stops the moment the animal needs to sleep, eat, or attend a meeting.

The Brainstem is the engine. A brainstem — in my RAPP work that’s the literal name — is a persistent engine built out of your stuff: the agents you’ve written, the tools you’ve wired up, the memory of how you do things. It isn’t a smarter chat window. It’s the thing that can sit where you sit and pull what you pull. Put it in front of the same carriage — Brainstem + Copilot — and you have a personless harness: the carriage unchanged, the pulling replaced.

What the swap looks like in practice

This is not a story about testing. It’s a story about the new way of work — testing just happens to be the first seat the engine took from me, because testing is the purest form of person-as-horse: a human clicking through an app after every change to see what broke.

I had just finished a feature I believed was done. Instead of strapping myself into the harness — open the app, click the toggle, watch the panel, check the download — I handed the job to an agent with a real browser and a list of expectations, and went to work on something else.

It came back with five defects. One was a blocker: the page was loading with zero JavaScript, so the whole feature was a painting of itself. Another: the one control that half-worked was a switch that could be turned on but never off. A third: a checkbox had quietly stretched to 87 pixels wide and shoved its own label onto three lines. Nothing in my automated test suite could see any of this, because it all lived in the seam between “the code is right” and “the thing works when a hand touches it.” It was findable only by pulling the carriage — which until that day had meant me.

I fixed the five, sent the engine back in, and it returned a green table: thirty-three checks, no human involved. My report changed from “try it and tell me what breaks” to “it’s done, and here’s the run that proves it.”

What makes an engine trustworthy in the harness

A few things separate an engine you can trust from a demo that waves its hands:

  1. It pulls through the front door. Real clicks, real dialogs, real downloads — not API calls impersonating a user. The whole value of the person it replaced was that they used the product like a person.
  2. It expects the annoying things. A confirmation popup it didn’t predict is a failure, not a nuisance. Layout gets measured — “this control is at most 22 pixels” — not eyeballed.
  3. It checks what should be absent. The feature that must stay invisible until enabled, the panel that must vanish on disable. Human testers almost never verify that things are properly gone. An engine always can.
  4. It never fakes a pull. If it can’t run, it says so loudly. A green light that didn’t actually execute is worse than a red one.

The arithmetic: horsepower over personpower

James Watt invented the unit “horsepower” for a simple commercial reason: he was selling engines to people who owned horses, so he measured what a horse could sustain and priced his machine in the buyer’s own units. Let’s do the same. Define one personpower as one attentive power user at a browser — someone who knows the app, knows the checklist, and doesn’t dawdle.

My harness run is 33 checks across two surfaces. Hand-executed, the mix is unforgiving even for a fast operator: the simple look-and-click checks go at ten seconds or so, but verifying a prefilled URL’s query parameters takes half a minute, measuring whether a control is 13 pixels or 87 takes a trip into devtools, and confirming an exported file actually downloaded and contains what it should takes a minute of its own. Averaged across the mix, that’s a solid twenty minutes per full pass — and you have to do the pass again after every fix.

The engine’s measured time for the same 33 checks: 19.1 seconds. That’s roughly a 60:1 ratio on the stopwatch — the engine runs at about sixty personpower on this workload. But the stopwatch undersells it, because the honest denominator is attention: the twenty human minutes were twenty minutes of a person’s full focus, while the engine’s nineteen seconds cost zero. I ran it four times tonight without noticing.

The carriage stays; the horse retires

Notice what the swap does not ask of you. You don’t abandon the carriage. Copilot, the app, the surfaces you’ve already invested in — all of it stays. That’s why the horseless carriage won so fast: it didn’t ask the world to reinvent the wheel, only to stop feeding the horse.

And notice where the person goes. Ford’s engine didn’t remove people from travel; it moved them from pulling to steering. The Brainstem doesn’t remove you from the work; it moves you to the seat where you set the destination and read the verdict. You stop being the horse. You were never at your best as the horse.

“Horseless carriage” survived only as long as it took people to forget that carriages had ever needed horses. “Personless harness” will go the same way. For a while it will be the odd new practice with the odd new name — and then it will not be “the new way of testing” or even “the new way of automation.” It will just be work: Brainstem + Copilot, the engine pulling and the person steering. And the idea that a human being once hand-pulled every prompt, click, and check through their copilot will sound like keeping a horse for your commute.

The Ark Pattern

The Ark Pattern

Skills drift.

You write a capability, it works, you ship it. Six months later the same nominal skill produces a different answer — because the runtime moved, or someone edited a copy, or a dependency shifted underneath it, or four teams each forked it and none of them told the others. The name still matches. The behavior does not.

That is skill drift, and it is not hypothetical. In one session this week I watched a single bad idiom produce five separate false results across two tools and three agents before anyone noticed it was the same mistake wearing different clothes. Nothing announced it. Every copy looked fine in isolation.

The uncomfortable part: if the whole industry standardizes on skills, drift is the systemic risk. Not model collapse. Not capability overhang. Just a slow, quiet loss of agreement about what a given capability actually does, with no way to check.

So I want a backup. Something that survives even if the skill ecosystem rots.

The Ark

RAPP’s core idea is that a capability should be one portable file with a typed contract and a single entry point. Drop agent.py into a folder, it runs. No registration, no manifest, no restart.

The Ark pattern extends that one step: inline the agent into the SKILL.md itself, so the document that explains the capability also is the capability.

One file. It reads as prose to a human. It self-extracts to running code for a machine. It carries its own implementation, so it cannot silently diverge from its own documentation — there is no second copy to diverge from.

The point is not that RAPP hosts benefit. The point is that outsiders benefit without adopting RAPP. No brainstem. No runtime. No install. Any harness that can read a markdown file gets the full fidelity of the native form.

That is the claim. Claims are worthless unmeasured, so I measured it.

The trial by fire

Two forms of the same capability:

  • Native formagent.py inside a RAPP-style harness, with an agents/ package, a BasicAgent base class, and a runner. Four files.
  • Ark form — one SKILL.md, 20,382 bytes, nothing else in the directory.

Four experiments, five invocations each, covering every code path in the tool.

E3 — Provenance

Does the code in both forms hash to the same thing?

native agent.py  sha256[:16] = db907a26cc3ec142
ark   SKILL.md   sha256[:16] = db907a26cc3ec142
-> IDENTICAL

E1 — Fidelity

Same inputs, both forms, compared byte for byte. Not “looks the same” — the same bytes.

MATCH  rules     2502B  native=62a327afaf0407ac ark=62a327afaf0407ac
MATCH  plan       804B  native=102d09d6313990f2 ark=102d09d6313990f2
MATCH  seed      1732B  native=7e86b4a9e0b85f9c ark=7e86b4a9e0b85f9c
MATCH  critic    2202B  native=47fb87d9bb307b4f ark=47fb87d9bb307b4f
MATCH  gate      1759B  native=99f646e69457aa9b ark=99f646e69457aa9b

Five for five. A harness with no RAPP runtime produced output indistinguishable from a full host.

E2 — Determinism

Fidelity once could be luck. Five repeats per form, per case — fifty runs total.

STABLE rules   10 runs -> 1 distinct output
STABLE plan    10 runs -> 1 distinct output
STABLE seed    10 runs -> 1 distinct output
STABLE critic  10 runs -> 1 distinct output
STABLE gate    10 runs -> 1 distinct output

Fifty runs, five distinct outputs, one per case. Zero variance across forms.

E4 — Drift, deliberately induced

This is the one that matters. I edited the native copy in place — changed one rule’s text, exactly the way a well-meaning fork does — and then asked all three questions.

native output changed after edit:   True
ark output unaffected:              True
digest reveals the divergence:      True
  native bd381eb7975b209a  !=  ark db907a26cc3ec142

The native copy drifted. The Ark copy did not. And critically, the divergence was detectable — the digest changed, so a consumer can tell, rather than discovering it months later when two agents disagree about what a rule says.

That is the whole value proposition, reduced to a hash comparison.

Why this works

Three properties, none exotic:

The document is the implementation. There is no gap between what the skill claims and what it does, because there is only one artifact. Documentation drift and code drift become the same event, which means fixing one fixes both.

Content addressing makes divergence visible. Hash the extracted code. If your copy’s digest differs from the published one, you are not running what you think you are running. This is the property that turns drift from invisible to detectable.

No runtime dependency. The extraction is four lines of standard library. A harness that can read a file and run Python gets full fidelity. Nothing to version, nothing to install, nothing to break.

What it costs

Honestly: some ergonomics. A single file gets long, and you lose per-module testing. My inlined tool is about 270 lines, which is comfortable; ten times that would not be.

There is also a real failure mode I hit while building this, and it is worth naming because it is exactly the kind of thing that erodes trust. Embedding code inside markdown double-escaped the newline characters, so two of five commands printed literal \n instead of line breaks. The other three were fine, because they used a different string-building path.

A spot-check of one command would have shipped it broken. Only running every case caught it.

Which is the same lesson as always: the assertion is code too, and nobody reviews it. I only found my own bug because I tested all five paths instead of the one I happened to look at.

The pattern, stated plainly

Ship the capability as one self-extracting document. Publish its digest. Let anyone verify they are running the real thing.

If the skill ecosystem holds, you have lost nothing — the Ark form runs natively anyway, byte-identical, as measured above. If it drifts, you have a canonical copy that carries its own implementation and announces its own divergence.

That is a cheap hedge against a systemic risk. It is also, as far as I can tell, the only way to share a platform’s strengths with people who have no intention of adopting the platform.

Fifty runs. Zero variance. One file.

Update: the pattern generalizes

One capability proving equivalence is an anecdote. So I mechanized the conversion — a toast step that inlines an agent into a SKILL.md and refuses to write the file if the round-trip loses a single byte — and applied it to two more capabilities.

All three now ship in both forms, and all three were measured rather than assumed:

capability           cases   runtime      canonical sha[:12]
------------------------------------------------------------
buzzsaw              5       MATCH 5/5    db907a26cc3e
wp_publish           1       MATCH 1/1    d507eb26f76d
prompt_extractor     1       MATCH 1/1    65dbdc01b9e7

That the conversion is mechanical matters more than the result. If each capability had to be hand-toasted, the conversion itself would become a place for drift to enter — which is precisely what the pattern exists to prevent.

The sweep failed first, and the sweep was wrong

The parity run initially reported prompt_extractor as DIVERGED.

The code was identical. argparse derives its usage line from sys.argv[0], and I was running the two forms from files named a.py and b.py. The only difference in the entire output was the filename echoed back at me.

That is the eighth time in this stretch of work that a reported failure turned out to be the test rather than the code. I have started treating it as the base rate rather than the exception.

Both sides were worth fixing, and they are different kinds of fix. The harness now runs both forms under an identical filename, because comparing output that embeds the filename was simply a bad experiment. And the agent now sets prog= explicitly, because help text that changes depending on what you named the file is genuinely worse behavior — the test was wrong, but it was pointing at something real.


Methodology note: every number above came from a script that anyone can re-run. The experiment writes its results to JSON and exits non-zero if equivalence fails, so it works as a regression test rather than a one-time demo. If it had failed, this article would say so — that is the point of measuring before publishing.

The Buzzsaw

The Buzzsaw

I gave eight agents one file and told them to loop until it was perfect.

They found 21 real defects. They also produced six false ones — and three of those were mine.

That ratio is the whole lesson. The tests were wrong nearly as often as the code, and the only reason anyone knows is that somebody checked.

The pattern

The buzzsaw is a way of driving agents that assumes the builder cannot see its own blind spots. So you pay a separate adversary to be unimpressed, and you let a machine decide when to stop.

Five moves:

  1. Name a reference. “Make it good” is unfalsifiable. “Put it next to the real thing, blind, and say which is better” is not. Name the actual best-in-class thing you are chasing.
  2. Fan out builders over disjoint regions. This is the trick that makes parallelism work on a single artifact. Give each agent an explicit list of what it does not own, and warn it that line numbers shift while it works.
  3. Loop each item instead of making one pass and declaring victory.
  4. Add a harsh critic, read-only. Its entire job is to refuse to be impressed. It must never edit.
  5. Write the acceptance gate first. The loop ends when the gate exits zero. Not when the work looks good.

Most people already do some version of one through three. Four and five are where the value is.

The best finding was not a bug

An agent implemented ambient occlusion — the shading in corners that makes 3D geometry look solid. It did the work correctly. Then it verified its own work: 66.3% of surfaces carried the right vertex data, the material flag was set. It reported a win, with evidence.

The blind critic scored it 2 out of 10. The corners rendered perfectly flat.

The cause was upstream: the scene lighting was bright enough to clip the highlight, so multiplying by a shadow value barely moved a pixel that was already clamped to white. Every line of the implementation was correct. The data was in the buffer. It never reached the screen.

The builder measured the attribute. It never measured the pixel.

That is not a coding error. It is a verification error, and no amount of re-reading the source finds it.

The blocker nobody could see

A “click to play” overlay sat at one stacking layer. The toolbar sat below it. Every button in that toolbar was unreachable — clicking the settings icon captured the mouse instead of opening settings, and three panels had no keyboard fallback at all.

The buttons rendered at full opacity the entire time. It is invisible in a screenshot. It is invisible in the source, because the CSS is unremarkable and the click handlers are correctly registered.

It only appears if you put a real cursor on a real button and click.

It had already shipped.

Six times, the failure was the test

This is the part I did not expect, and it is now the reason I bother with the whole apparatus.

A check read a value through a method that did not exist. It got null. The code treated null as “not supported, skip,” and printed a tidy line. The single most important check in the suite never ran once. In a log, a skipped check and a passing check look nearly identical.

Another: I used a common DOM property as a visibility test. It returns null for any fixed-position element, which means correct code reads as broken. That one mistake produced five separate false results across two tools and three agents before anyone noticed it was the same error each time. It nearly caused a correct line of CSS to be changed to satisfy a broken assertion.

And my own test server sent a header that disables caching — while the thing under test was a caching feature. Every offline test I ran before that was measuring a fiction.

One agent found seven assertions in its own suite that were green without being correct. One of them had a body that returned true unconditionally. A placeholder, in a passing suite, reporting success forever.

Another measured a memory leak and had the numbers to prove it. Then it ran a control group with the feature disabled, watched the control climb identically, realized it had been measuring startup warm-up, and retracted its own finding.

The rules

Six, each earned by getting it wrong:

Check the assertion before you fix the implementation. When something reports a failure, the test is a suspect too.

Measure the output, not the intermediate. Verify the pixel, not the buffer. The user cannot see your vertex attributes.

Prove the tests can fail. “83 assertions passing” and “83 assertions that cannot fail” produce identical output. Break each invariant on purpose and confirm exactly one assertion goes red. That is the only evidence a green suite means anything.

A skipped check is more dangerous than a failing one. Any branch that turns “cannot measure” into anything other than a failure is a place where confidence goes to die quietly.

Measure after the system settles, and keep a control. A measurement taken during warm-up, with no baseline, will find a trend that isn’t there.

Never let one bad idiom spread. When the same surprising result shows up in unrelated places, stop and ask whether it is the same mistake wearing different clothes.

What it costs

Two of the eight agents wrote no production code at all. The critics took over an hour each, and spent it clicking every control, throttling the processor, and blind-ranking screenshots.

They also found the blocker, and the shipping bug that made the simulation run at a third of real time while every instrument agreed everything was fine.

The implication

The lesson is not “write more tests.”

It is that the assertion is code too, and nobody reviews it. Implementation gets scrutinized. Test code gets written once, goes green, and is never read again. So it rots silently, and a green suite becomes a claim nobody has audited.

The agents were good. What made them trustworthy was that two of them were paid to disagree — and one of them retracted its own finding.

The Synthetic Enterprise Data Plane (or: how we demo enterprise AI without waiting for anyone’s data)

Every enterprise AI project I’ve ever seen dies a little in the same place: waiting for data access. The use case is approved, the agent pattern is proven, and then everyone sits for six weeks while security reviews a service account for a demo.

So we stopped waiting. We publish the enterprise systems themselves as static APIs.

The pattern

A static API is a read-only API served entirely from files on a Git host — no server, no database, no runtime. GitHub’s raw CDN is the host: free, globally cached, CORS-open, forkable. One idempotent build script turns hand-authored seed data into responses shaped exactly like the real system’s wire format.

This week we added two new organs to the commons at kody-w.github.io/rapp-static-apis:

  • sap/ — an S/4HANA gateway simulation. OData v2 envelopes, __metadata per row,

real service names (API_COMPANYCODE_SRV, API_PLANT_SRV, API_BUSINESS_PARTNER). A client — a custom connector, an HTTP node, a RAG ingester — cannot tell it from a live gateway.

  • sharepoint/ — a Graph-flavored document library for a fictional S/4HANA transformation

program: charter, workstream directory with owners and backups, governance and escalation paths, per-stream one-pagers, a data-migration playbook, a cutover plan, an FAQ.

The company is Meridian Manufacturing Group. The program is Project Phoenix. Neither exists. Every name, plant, and risk register entry is invented — which is precisely why we can publish all of it.

Try it — no auth, no signup, any language:


RAW=https://raw.githubusercontent.com/kody-w/rapp-static-apis/main
curl -s $RAW/sap/registry.json
curl -s $RAW/sap/api/opu/odata/sap/API_PLANT_SRV/A_Plant.json
curl -s $RAW/sharepoint/api/v1/sites/phoenix/documents.json
curl -s $RAW/sharepoint/api/v1/sites/phoenix/docs/workstream-directory.md

What grounds on it

On top of those two sources we built a transformation knowledge companion — the classic MVP every large program asks for: “Who is responsible for this workstream?” “Who owns Procure-to-Pay?” “I’ve got a blocker — who do I escalate to, and who’s their backup?”

It’s two small Python files on the RAPP memory-agent platform (kody-w/rapp-ai): an ingest agent that walks the library listing, fetches each document, and chunks it by section; and a companion agent that scores chunks against the question and returns passages with citations — document title, section, author, URL. The LLM is instructed to compose only from those passages and cite its sources. Ask the escalation question and it merges the Data Migration Playbook with the Governance & Escalation doc into one answer — several sources, one clear response, every fact attributed.

The part that matters: repoint two URLs and the same agent grounds on a real SAP gateway and a real SharePoint site. The demo isn’t a mockup of the production system — it’s the production system with synthetic data behind it. The distance from demo to pilot is a config change.

Why static?

Because the data plane becomes infrastructure anyone can hold:

  • Forkable — fork the repo, edit the seed JSON, run build.py, and you have your industry’s

version in an afternoon.

  • Versioned — every state of the “enterprise” is a commit. Demos are reproducible forever.
  • Zero standing cost — nothing to patch, scale, or pay for.
  • Honest — it’s all synthetic by construction, so there is nothing to leak. The security

review takes as long as reading this sentence.

The loop that makes it fun

The platform loads its agents from cloud storage at runtime. So once the Microsoft 365 channel is wired up (a Copilot Studio solution, imported once), a new or changed agent file hot-deploys into the running app over HTTP and is answering in the M365 chat seconds later — no redeployment, no solution reimport. Iterating on an agent in front of the people who’ll use it, in their own Copilot, is a genuinely different way of building.

Fork the commons, point an agent at it, and stop waiting for data access.

Everything above is public: the commons, the platform, the agents, the build scripts. All example data is synthetic; any resemblance to a real company is coincidental.

Page 1 of 10

Powered by WordPress & Theme by Anders Norén