White paper
A proposal for a new way of publishing essays or other written content. The idea is an architecture that sits underneath a published essay so that it keeps itself up to date, coined the "live and breathing essay".
Section 1 · Introduction
Most written content is published once and then left alone. A client update, a country guide, a market outlook or a running news story is accurate on the date it is issued, and it becomes less accurate as the subject moves on. Keeping it current is a manual task. Somebody has to reread the piece against what has happened since and revise the lines that no longer hold.
This paper proposes a solution, called the live and breathing essay. It is live because the document stays wired to the dataset it was written from, so it keeps getting tested against new evidence instead of being left alone. It is breathing because that test happens on a rhythm, one run a week, small and repeated.
An implementation of this architecture runs on the Global AI Regulation Tracker, under a tab called Enforcement Trends. The page reads as an ordinary essay. But behind the scenes it is rendered from a JSON file, which is a plain text file laid out so a machine can read it reliably, and in that file every statement in the essay is stored as its own record. Once a week a scheduled job checks the tracker dataset for new entries and proposes revisions to the statements those entries affect, for me to accept or reject.
The idea is to treat an essay like an application. At the core are five components: (1) the frontend essay a reader is served, (2) the backend mesh that holds every statement in it, (3) the algorithm that works out what has changed and rewrites only the part affected, (4) the scheduler that runs the algorithm on a clock, and (5) the approval mechanism a person uses to accept or reject each proposed change before it is published.
The frontend is an ordinary web page, but with two twists:
The 'mesh' is basically the data skeleton that sits behind the essay. Every statement lives in it as its own data object, and each one carries the metadata a machine needs to work with it, an identifier of its own, the source it rests on, the date it was last tested against that source, and the subject it answers for. Think of it as a graph.
JSON is the most viable format of this graph. See below example.
{
"statements": [
{ "key": "enf-014",
"source": "gpdp-2026-04",
"date": "2026-04-02",
"subject": { "topic": "enforcement",
"jurisdiction": "IT" },
"text": "Regulators act under existing privacy law."
},
{ "key": "gpm-021",
"source": "oj-l-2024-1689",
"date": "2025-08-01",
"subject": { "topic": "general purpose models",
"jurisdiction": "EU" },
"text": "Model providers carry transparency obligations."
}
],
"sources": {
"gpdp-2026-04": {
"title": "Provvedimento 2 April 2026",
"url": "https://example.org/gpdp/2026/04" },
"oj-l-2024-1689": {
"title": "Regulation (EU) 2024/1689",
"url": "https://example.org/eu/2024/1689" }
},
"manifest": [
{ "id": "gpdp",
"url": "https://example.org/gpdp/feed.xml",
"added": "2026-01-11" },
{ "id": "oj-l",
"url": "https://example.org/eu/oj/feed.xml",
"added": "2026-01-11" }
],
"ledger": ["9f2a41c8d6e0b537",
"1c7d90ab34f6e2d1",
"4e88b0195ac7f6d2"],
"routing": {
"enforcement / IT": "enf-014",
"enforcement / EU": "enf-014",
"general purpose models / EU": "gpm-021"
},
"residual": [
{ "hash": "6b18e5f2a90c4d73",
"date": "2026-06-19",
"subject": "insurance / SG",
"note": "Mattered, and no statement owns it." }
]
}
statements The prose a reader is served, one object
per statement, each carrying its key, its source, its date and its subject.sources The evidence the statements bind to, held once
and referred to by identifier, so several statements can rest on the same
instrument.manifest A declared list of everything the system is
allowed to read. Anything not on the list is never read, so adding a source is an
explicit change with a record.ledger A record of everything already taken in, stored
as a content hash of each item rather than a position in a feed. A content hash is a
short fingerprint computed from the item's own text, so the same item always produces
the same fingerprint and a changed item produces a different one. A position assumes the
feed is stable and ordered, and it fails without any error when it is not. With hashes,
running the job twice returns the same answer as running it once, and what counts as new
is whatever is not already in this list.routing Which statement answers for which subject.
This is the map the algorithm resolves against. Write it by hand while the document is
small, or derive it from what each statement already cites once it is not. Either way
it has to be rebuilt when statements are added or removed, and a statement that changes
home takes its future updates with it, so a rebuild is a change worth seeing rather
than a detail.residual Where items land when they matter but resolve
to no heading. Several items accumulating on one subject indicates that the document has
no heading covering that subject.
Listing 1. An example mesh, cut down to two statements. The fields above
sources are rendered to the page and the structures below it are not.
The algorithm should:
This component is configuration rather than code. A cron expression, a workflow schedule or a hosted trigger will run the algorithm on a clock.
Without the scheduler nothing starts a run and the document returns to manual maintenance.
A minimum viable approval mechanism performs five functions.
The approval mechanism can come in various forms, including:
A change is written to the mesh only after a person accepts it. The frontend rebuilds only then, carrying the date of that decision.
Side note. This component is optional. Connect the algorithm's output directly to the mesh and the document updates itself with nobody in the loop, which is a reasonable configuration where a wrong statement costs little and gets corrected on the next run. Include the approval mechanism where a person has to be accountable for what the document says. The running implementation includes it because the essay states what the law requires.
Here is how the five components work together in practice.
Everything above describes the architecture. In this section, I will walk through how this architecture is implemented on Google Cloud to power the Enforcement Trends essay on the Global AI Regulation Tracker. The frontend essay is served by Firebase Hosting, the mesh is one object in Cloud Storage, the algorithm is a Cloud Run service, the scheduler is a Cloud Scheduler job, and the approval mechanism is an admin dashboard I built and host separately from the site.
Enforcement Trends is an essay about how AI regulation is actually enforced around the world, including an insight into which areas or issues are more heavily scrutinised by regulators than others or whether there are differences in AI enforcement actions across markets. The essay is generated from the tracker's own dataset, and is updated each week against the entries added to the tracker in that week.
The date on the page is the date the essay last changed.
The page is rendered from one JSON file in a Cloud Storage bucket. Below is an excerpt of the live file, cut down to a single insight and with the long values elided. Each field in it does one job.
{
"schema_version": 2,
"generated_at": "2026-08-02T17:04:49.920Z",
"insights": [
{
"id": "fa_personal_data",
"type": "observation",
"heading": "Privacy, data protection and cyber dominate …",
"body": "<p>Privacy, data protection and cyber account …",
"examples": [
{ "country_code": "IT",
"label": "[20 December 2024] Italy's data protection …",
"href": "https://www.gpdp.it/home/docweb/…" }
],
"route": {
"scope": "thematic",
"categories": ["Data Privacy & Protection",
"Cybersecurity", "…"],
"jurisdictions": ["IT", "EU", "BR", "CN", "AU", "…"]
},
"provenance": {
"input_hash": "ead4a8d2fe7e1267592b3efa268d84fb",
"generated_at": "2026-08-02T17:01:51.352Z",
"model": "gpt-5.5"
}
}
],
"dataset": {
"entry_count": 4529,
"jurisdiction_count": 238,
"entry_hashes": ["a3a49e3706d3c698dcb8d5af60e255cd", "…"]
},
"backlog": {
"unrouted_hashes": ["6a40c1bdea47c5cd19c088c946f17d34", "…"],
"by_category": {
"Civil Rights & Liberties": [
"f9553ab247ab0ba5aaccf3f03a12f926", "…"]
}
}
}
id. The key. Everything downstream addresses an insight by
it. The routing map points at fa_personal_data rather than at the first
insight, so the essay can be reordered without anything else being touched.type. Whether the insight states what the entries already
show or what they point towards. Eight of the ten are observations and two are predictions,
and a prediction is amended against different evidence from an observation.heading and body. The rendered prose, and the
only two fields a reader sees. They are the output of a run rather than an input to one, so
nothing else in the file is derived from them.examples. The sources the insight rests on. Each one
carries a country code, a label and an href back to the instrument, so a
citation in the prose resolves to a tracker entry instead of being checked by hand.route. The subject. categories is what a new
tracker entry is matched against. jurisdictions records the places the insight
already covers and scope says whether it answers for a theme or for a place,
and neither is read when routing. Routing runs on this field alone, which is what keeps it
in code rather than in a prompt.provenance.input_hash. A hash of the inputs this insight
was built from, written every time it is regenerated. It is a record rather than a control.
What decides whether an insight is rewritten is step 5 below, which is whether anything
routed to it and whether any entry it cites has gone missing.provenance.generated_at. When this insight was last tested
against the evidence. It is separate from the generated_at at the top of the
file, which is when the file was last built. Most insights are older than the last
run.provenance.model. Which model wrote it. Insights in the
same file can carry different models, so a model change stays traceable afterwards.dataset.entry_hashes. The intake ledger. A content hash
for each of the 4,529 tracker entries the last run saw. What counts as new next week is the
set difference against this, so a doubled run finds nothing to do.backlog. The residual buffer.
unrouted_hashes holds entries that mattered but resolved to no insight, and
by_category groups them by subject, so a large group there is a subject with no
heading covering it. An entry that lands here is also written to the ledger, so the backlog is
a record rather than a queue. I read it when deciding whether the essay needs a new
insight.Listing 2. An excerpt of the live essay file, one insight of ten, with long values elided.
The four steps of 2.3 run in one Cloud Run service called updatebigpicture. Cloud
Run holds a container that starts when something calls it and stops when it finishes, so the
service costs nothing between runs. Here is what one run does.
essay.pending.json. The live essay.json is untouched until I accept
the changes in the dashboard.
Over two months the service handled a few dozen requests and sat idle the rest of the time, and a run takes minutes rather than hours.
updatebigpicture service, with two months
of request count and latency. The service is idle between runs and is invoked by the
scheduler in 3.4.
The scheduler is Cloud Scheduler, a managed cron service. You give it a schedule, a target to call and a way to authenticate, and it makes that call on time whether or not anything else is running. There is nothing to deploy and nothing to keep alive, and a job is one row in a console.
The job is bigpicture-weekly. It runs on 0 3 * * 1 in
Australia/Melbourne, which is three in the morning every Monday, and it calls the service in
3.3 with a signed token the service checks before it does anything. It ran on 3 August and the
next run is 10 August.
bigpicture-weekly, enabled, weekly, with its
last run and next run. The second job in the list is unrelated to the essay.
The approval mechanism is a simple private dashboard which has write permissions to
essay.json.
When I open it, it loads essay.pending.json, loads the live
essay.json, and computes a word level diff between the two. What it shows me is
the essay with insertions and deletions marked in place. Each marked run of words is a separate
decision, and the default on every one is accept.
essay.json, copies the draft and the full set of decisions into a
timestamped file under bigpicture/history/, and deletes the draft. Writing
essay.json fires a storage trigger that recomputes
essay.diff.json, which is what the show what changed toggle on the page reads.
The review is checked against a hash of the draft it was opened on. If a scheduled run produces a new draft while I have the old one open, accepting fails and tells me to reload.
Figure 7 runs all five components together, one week, on the services named above. The strip along the top is the same wiring as Figure 1, with the Google Cloud service under each component.
essay.json it reads. Cloud Scheduler starts the run, thirty eight entries are
collected, thirty seven change nothing, and the remaining one routes to a single statement.
The Cloud Run service proposes a revision to that statement and stops. You accept it in the
dashboard, one row in essay.json is written, and the page is rebuilt with the
date it was checked.
Table 1 names the service, feature or format in each stack that does the job of each component.
| Component | Claude | ChatGPT | Google Cloud | AWS | Azure |
|---|---|---|---|---|---|
| 1The frontend essay | An artifact, or a repo published to Pages. | A Canvas, or a repo published to Pages. | Firebase Hosting. | S3 behind CloudFront. | Static Web Apps. |
| 2The backend mesh | JSON files in a Project. | JSON files in a Project. | JSON in Cloud Storage, or Firebase Realtime Database. | JSON in S3, or DynamoDB tables. | JSON in Blob Storage, or Cosmos DB containers. |
| 3The algorithm | A Skill for the method, connectors for the sources, drafts to a repo. | Project instructions for the method, Actions for the sources, drafts to a repo. | Cloud Run, drafts to a second Cloud Storage file. | Lambda and Bedrock, drafts to a private S3 prefix. | Azure Functions and Azure OpenAI, drafts to a private Blob container. |
| 4The scheduler | Scheduled tasks. | Scheduled tasks. | Cloud Scheduler. | EventBridge. | A timer trigger on the function. |
| 5The approval mechanism | A pull request, which is a held draft, a redline and a decision at once. | A pull request, or the Canvas diff view. | A review console on Cloud Run, writing to Cloud Storage. | A review page on Amplify or API Gateway, writing to S3. | A review page on Static Web Apps, writing to Blob Storage. |
Table 1. The five components across five stacks, checked 6 August 2026. Slide sideways for the rest.
The live and breathing essay solves a problem every publisher of dated writing already has, which is that the content only stays useful while somebody keeps it current, and keeping it current by hand does not scale. Any field with writing that dates on a known schedule, and a dataset behind it that records when, can be built this way. Here is where I would start looking.
The paper is published under CC BY 4.0.
Sun, R. (2026). The Live and Breathing Essay: an architecture for published writing that maintains itself against a live dataset. Version 1.0, 3 August 2026. https://www.techieray.com/LiveAndBreathingEssay