Showing posts with label DevOps. Show all posts
Showing posts with label DevOps. Show all posts

CDC at WHOOP: Self-Service Replication for Hundreds of Postgres Tables

Mike's Notes

This article was mentioned in a recent Data Engineering Weekly from Ananth Packkildurai.

"WHOOP writes about replacing costly database replication that required data engineers to handle table and column changes. Its system records changes continuously, updates analytical copies every four hours, and automatically carries new tables and columns downstream. This reduces computing costs and lets service teams manage replication themselves, while teams needing fresher data can read the change records directly." - Ananth Packkildurai

Lots of great lessons here about implementing Change Data Capture (CDC).😎

Resources

References

  • Reference

Repository

  • Home > Ajabbi Research > Library >Subscriptions > Data Engineering Weekly
  • Home > Handbook > 

Last Updated

21/10/2026

CDC at WHOOP: Self-Service Replication for Hundreds of Postgres Tables

By: Jack Leitch
WHOOP: 26/09/2026

Jack Leitch: Staff Software Engineer, Data Platform.

...

A software engineer at WHOOP adds a new column to a Postgres table on Monday morning. By that afternoon, the column is queryable in Snowflake and available to any downstream model or dashboard, alongside every other column on that table. Nobody filed a ticket. No data engineer touched anything.

Change Data Capture (CDC) is the pattern that makes this possible: every insert, update, and delete on a source table is streamed out as an event, and downstream systems consume that stream to stay in sync. That workflow is the point of the CDC platform we run today, and getting there meant deliberately avoiding the streaming-upsert pattern most CDC-to-lake pipelines converge on.

The system it replaced

Debezium captured row changes from Postgres and published them to Kafka as JSON, with no schema registry sitting in front of it, so downstream consumers were reading loosely typed payloads. A Spark Structured Streaming job then upserted those events into Iceberg tables on a thirty-minute trigger. It worked. It also had four problems that got worse as WHOOP grew:

  1. The upserts were expensive. We ran one Spark Structured Streaming job per table, so hundreds of long-running streaming jobs sat continuously reconciling their targets on a thirty-minute cadence. These tables were queried heavily and there was real value in keeping them fresh, but the compute cost of continuously running one streaming job per table was the dominant issue: we were paying a lot for freshness that most consumers did not strictly need.
  2. Schema changes were manual. A new Postgres column would not appear downstream until someone filed a ticket, and the fix usually meant backfilling the entire table. Every schema change turned into a coordination problem across teams.
  3. Observability was thin. We had Spark job metrics and Postgres-side replication slot lag, but nothing meaningful from Debezium itself. No per-connector throughput, no per-connector lag, no visibility into what the source connector was actually doing.
  4. Per-table configuration lived in the wrong place. Kafka partitioning, topic settings, and the list of replicated tables did live in the owning service's own repo, but they lived separately from the normal Postgres config and Liquibase migrations that engineers touched day to day. So they got forgotten. New tables would land in Postgres and quietly not make it into CDC, sometimes for months.

The pipeline itself was fine. Its operating model wasn't. Every design choice put Data Platform on the critical path for something a service team should have owned.

The core idea: split streaming from upserts

Most CDC-to-lake systems merge two concerns into one job. They take a stream of change events and, in real time, produce a materialized replica of the source table. That is a legitimate goal, but it forces continuous upserts, which are expensive to run at scale.

We split them apart.

  • A Bronze layer captures every CDC event exactly as Debezium emits it. It is append-only. Small files, cheap writes, no reconciliation.
  • A Silver layer materializes the actual Postgres replica. It reads Bronze and upserts into Iceberg, but only every four hours.

For consumers, this gives two clean options. If you need the latest state of a table and can tolerate a few hours of staleness, you query Silver, and the table looks exactly like the Postgres source. If you need lower latency or you specifically want change semantics (inserts, updates, deletes), you query Bronze and filter by the CDC timestamp.

Very few consumers actually need the latter, so continuous upserts were the wrong default.

End-to-end CDC architecture: Postgres to Debezium to Kafka to Flink to Bronze and Silver Iceberg tables

Debezium and Postgres publications

We run one Debezium connector per Postgres database. Each connector reads from a Postgres publication using logical replication, serializes each event as Avro against the AWS Glue Schema Registry, and publishes one Kafka topic per table using the convention postgres_cdc.<service>.<schema>.<table>.

The set of replicated tables is driven by the Postgres publication itself, and the publication is managed with Liquibase migrations that live inside the service team's own GitHub repository. Adding a table looks like this:

-- Liquibase migration in the service repo
ALTER PUBLICATION cdc_publication ADD TABLE new_feature_table;

Some services skip the per-table dance entirely and declare the publication as FOR ALL TABLES, so anything they add to Postgres is automatically replicated. New tables just appear.

That is the entire ceremony. Debezium picks up publication changes on the next poll. The Flink job downstream discovers the new topic within a minute and starts writing it to Bronze. Silver picks it up on its next run and backfills from the latest snapshot. No PRs on our side, no tickets. The service team owns the decision and the migration is code-reviewed in the same repo as the schema change that motivated it.

The other property that falls out of this design is automatic schema evolution. When Debezium sees a new column, it registers a new Avro schema in Glue. The Flink sink writes the new column to Bronze on the next commit. Silver sees the new field on its next run and adds it to the Iceberg schema. A single ALTER TABLE in Postgres propagates through the entire stack with no human involvement. Supported type changes work the same way: widening a decimal(10,2) to decimal(12,2), for example, flows through Avro's schema evolution rules and Iceberg's promotion rules without breaking any downstream reads.

Each connector deploys through an internal Terraform module that standardizes the operational plumbing: IAM, secrets, Datadog monitors, and the Glue registries. We also build our own Debezium container image, which bundles a small JMX metrics exporter alongside the upstream Debezium jars. That exporter surfaces connector-level metrics in Datadog: replication lag (MilliSecondsBehindSource), events seen, errored tasks, and restarts. Those metrics route to the owning team's oncall, not ours, which was a specific goal. If a service's connector is falling behind, the team that owns the database is the first to know.

Flink: one job per database, fan-in and fan-out

Bronze is written by Flink. Bronze tables follow the convention bronze.<service>.<schema>.<table>, so the Postgres source and its Iceberg replica are directly identifiable from each other's names.

There is one Flink job per Postgres database, and each job uses a fan-in / fan-out pattern: it subscribes to every Kafka topic under that database's prefix, then routes each record to the correct Iceberg table based on the topic name.

One Flink job per database subscribing to N Kafka topics and writing to N Bronze Iceberg tables

A naive design would run one Flink job per table, which means N deployments, N sets of checkpoints, and N connectors to Kafka. For a service with fifty tables, that is fifty jobs to autoscale, monitor, and upgrade. The fan-in/fan-out pattern collapses that to one job per database, regardless of how many tables live in it.

The routing itself is handled by the Dynamic Iceberg Sink introduced in Iceberg 1.10.0. Each record carries its Iceberg table name derived from the source Kafka topic, and the sink handles the rest, including creating new tables when they appear. We rediscover Kafka topics every 60 seconds, so new tables added to a Postgres publication start flowing to Bronze within a minute of the publication change. No job restart is required.

Each Bronze record is the row plus five CDC metadata columns:

Column Meaning
cdc_op c (create), u (update), or d (delete)
cdc_ts Source database event timestamp
cdc_processed_at When Flink processed the record
cdc_source_lsn Postgres WAL log sequence number
cdc_source_tx_id Postgres transaction ID

Bronze tables partition by day(cdc_ts). Compaction runs nightly against the last two days and sorts by cdc_ts DESC, which optimizes for the most common access pattern: "give me the recent changes to this table." Older partitions are already fine.

Jobs deploy through the Flink Kubernetes Operator in Application Mode on our EKS clusters. The operator manages lifecycle, autoscaling, and savepoint-based restarts. An auto-discovery runner scans Glue for new CDC topic prefixes and posts to Slack if it spots a new service without a matching Flink deployment. We deliberately do not fully automate that step today because a handful of services carry PHI and need to be routed to a separate Iceberg catalog. Deciding which catalog a new service belongs in is currently a human call, but it is the kind of thing we plan to automate, with service owners declaring their routing intent at onboarding time rather than pinging us for a decision.

Why Flink instead of the MSK Connect Iceberg sink? We prototyped the MSK Connect option early and it did not hold up at our scale. The connector was still relatively immature, and we hit ceilings on throughput, checkpointing behavior, and observability that were hard to work around. Flink was more operational work to run, but it gave us autoscaling based on backlog, better checkpointing semantics, richer Prometheus metrics, and the ability to add custom routing logic.

Silver: making upserts cheap

Silver is where the actual Postgres replicas live, and it is where the two-layer architecture pays for itself.

Every four hours, a Spark job runs per service. It does three things: figures out what to process, runs MERGE INTO for tables that already exist, and backfills tables that just appeared.

Discovery. The job queries the Glue Schema Registry to find every CDC-enabled table for the service and derives the primary key for each one from the Avro key schema. No manual PK configuration lives anywhere, though we do allow overrides for edge cases (for example, a table with a mutable primary key needs its logical merge key to be declared explicitly).

Backfill (new tables only). For a table that has no Silver counterpart, the job takes the latest automated Aurora snapshot, exports it to S3 in Parquet using Aurora's built-in snapshot export, and merges it into a fresh Silver table. There is one subtle guard here: if the snapshot predates the moment the table was first added to CDC (which we know because Glue records schema creation time), we defer the backfill until a newer snapshot is available. Otherwise we would be seeding from a snapshot that misses events already in Bronze, and the reconciliation from there onward would look correct but silently miss rows.

Incremental (existing tables). The job reads Bronze events since the last watermark, groups by primary key to pick the latest state per row, and executes MERGE INTO on the Silver table. Deletes propagate the same way (via cdc_op = 'd').

Tables get batched into groups of five per Spark job to balance parallelism against resource cost. Each service's Silver flow is independently scheduled.

Four layered optimizations inside the Silver Iceberg table are what let MERGE INTO run in minutes rather than hours. They turn each merge from a full-table shuffle into a targeted, well-pruned operation, and without them Silver would not be cost-viable at our scale.

Bucket partitioning on primary key

Silver tables partition by bucket(N, primary_key), where N is picked per table to target roughly consistent file sizes. Bucket partitioning distributes rows evenly across a fixed number of buckets regardless of PK distribution. That evenness is not just aesthetic. It is a prerequisite for the write-side optimization below.

Sort order and bloom filters within each bucket

Data within each bucket sorts by primary key, and bloom filter indexes are configured on the PK columns. Together they give Spark tight file-level pruning during MERGE: skip any file whose min/max range excludes the incoming PKs, and within a matching file, skip any Parquet row group whose bloom filter says the PK is definitely not present.

The read-side benefit for Snowflake is more limited. Snowflake's Iceberg reader uses min/max file statistics for pruning (which is why sorting matters) but doesn't currently use Parquet bloom filters. So the bloom filters are a Spark-side win; the sort order helps both.

Bucket pruning and Storage Partitioned Join

Two related optimizations do most of the write-side work. They're often talked about together but they are technically distinct.

The first is bucket pruning. When Spark plans a MERGE INTO between an incoming CDC micro-batch and the Silver table, it hashes the incoming primary keys, figures out which buckets they map to, and reads only those buckets from the target. No full table scan.

A five-key incoming batch hashing to buckets 3, 17, 42, 88, 101, with only those buckets highlighted in the 128-bucket Silver table

The second is Storage Partitioned Join. Because both sides of the merge share the same bucketing scheme, Spark can co-locate rows from the incoming batch with the rows already in the target and skip the shuffle that a normal join would need. Without SPJ, Spark would have to hash-repartition the entire target table to line it up with the incoming batch, which is often the largest single cost of a merge at scale.

Both optimizations depend on the same thing: an evenly bucketed target table. Skewed data breaks both, because a single hot bucket dominates the read on one side and the shuffle-avoidance on the other. That is why bucket partitioning is the foundation for everything else in this section.

SPJ plus bucket pruning are what made Silver viable. Merge jobs that would otherwise scan and reshuffle terabytes now touch a small fraction of the target table, and the runtime savings are order-of-magnitude.

Merge-on-Read

Silver tables use Iceberg's Merge-on-Read mode. Instead of rewriting entire Parquet files when a row updates, Iceberg writes a position delete file that marks which rows are stale. That skips the file rewrite on the write path, which is where most of the MERGE cost would otherwise land. Reads pay a small tax at query time to reconcile data and delete files, which we resolve during nightly compaction. Silver compaction sorts data back by primary key, which restores clean read performance and keeps future SPJ merges efficient.

We can afford these Silver optimizations because Silver runs every four hours rather than continuously. Larger batches amortize the fixed overhead of MERGE planning, and a job that runs six times a day is one we can actually tune, rather than firefight.

For teams that need lower latency, they read Bronze directly and filter on cdc_ts. Recent changes are cheap to scan there because Bronze compaction sorts by cdc_ts DESC and prunes small files aggressively for the last two days.

Audit trails from the same pipeline

CDC turned out to be a natural place to solve a problem that would otherwise need its own audit system.

Services that need audit trails on sensitive tables can opt into emitting audit context alongside their writes. When enabled, the service calls pg_logical_emit_message(true, 'audit', ...) inside the same transaction as the data change, embedding metadata like the acting user ID and the SQL query. The true argument matters: it makes the message transactional, so the message and the row change share the same xid and either commit together or not at all.

Debezium captures both. Flink writes row changes to their normal Bronze table and logical messages to a dedicated pg_logical_messages Iceberg table partitioned by day(cdc_ts) and the source table name. In Snowflake, a complete audit trail is a join:

select data.*, audit.user_id, audit.sql_query
from   postgres_cdc_prod.svc.sensitive_table as data
join   postgres_cdc_prod.svc.pg_logical_messages as audit
  on   data.cdc_source_tx_id = audit.cdc_source_tx_id
where  data.cdc_ts  >= dateadd(day, -30, current_timestamp())
  and  audit.cdc_ts >= dateadd(day, -30, current_timestamp());

Both sides get filtered by cdc_ts so partition pruning fires on the audit table as well as the data table. Postgres's transactional guarantees do the rest: every write to an audited table shares its transaction ID with any audit message emitted in the same commit, so the join gives you the transaction-level context (who, when, why) for any change. What the pipeline itself buys us: no separate audit system, and no risk of the audit trail drifting from the data.

The responsibility model this creates

The technical architecture reflects an organizational choice. Service teams own their data. Data Platform owns the infrastructure.

Component Owner
Debezium connector (via Terraform module) Service team
Publication contents (via Liquibase migration) Service team
Flink Bronze jobs Data Platform
Silver Spark jobs, backfills, maintenance Data Platform Data Platform
Snowflake catalog integration Data Platform Data Platform

Adding a table to CDC involves editing exactly one file, in the service's own repo. Everything downstream follows automatically. When a schema changes, no ticket is filed, because there is nothing for us to do. If we did our jobs right, Data Platform's involvement in the average CDC operation is zero.

For the analytical and modeling tables downstream of this (the ones that need explicit schema control and reproducibility), we manage them through Glacierbase, which handles the versioning problem for tables where controlled schema drift is not acceptable. The two systems complement each other: CDC handles ingestion where drift is expected and automatic; Glacierbase handles curated tables where every change should be a reviewed migration.

What this all buys

The two-layer split was about cost, not elegance. Continuous upserts were expensive, most consumers did not need the freshness they were paying for, and separating Bronze from Silver let us make the expensive operation infrequent and the cheap operation continuous. That in turn made the Silver optimizations worth investing in, because a job that runs six times a day can absorb serious tuning work.

Publication-driven self-service came out of the same accounting. Data Platform was the bottleneck for every schema change across every service, so we moved the source of truth into the service's own Liquibase migrations. New tables and new columns propagate downstream without our involvement.

The engineer from the opening paragraph doesn't need us. That is the whole design.

Nestspace

Mike's Notes

Thursday, 09/04/2026 (NZ time) was the longest day. I couldn't make a single mistake, so I turned off the phone and the internet to concentrate from 8am to 9pm, then slept like a log. I was a walking zombie yesterday. I'm glad I will never have to do this again.

This is the successful culmination of months of mentally challenging preparatory work for the new Pipi Core data centre.

A typical day for me is

  • 50% learning
  • 40% thinking
  • 10% doing

The less I do, the more productive the solutions. The faster the progress.

Speed will come from Pipi-driven automation, not Mike working harder.

Resources

References

  • Reference

Repository

  • Home > Ajabbi Research > Library >
  • Home > Handbook > 

Last Updated

23/07/2026

Nestspace

By: Mike Peters
On a Sandy Beach: 10/04/2026

Mike is the inventor and architect of Pipi and the founder of Ajabbi.

Inside the Pipi Core data centre, the careful migration and reorganisation of hundreds of thousands of Pipi-related files began and were completed yesterday. Each file or directory was placed in only one Nestspace, and then the historical Nestspaces were converted into zip​ archives

It is a good solution, but it took a month of trial and error to figure out. It had to be 100% correct to enable rapid, reliable data centre automation, self-managed by Pipi.

It was fascinating to watch the recent Lex Fridman interview with NVIDIA CEO Jensen Huang, who described NVIDIA's large-scale problem-solving process.

Problems to solve

A large number of problems had to be solved in parallel. Each problem affected the others.

  • Where to put self-organising Pipi swarms.
  • Pipi instances
    • Naming
    • Self-evolving
    • Versioning
  • How to use DevOps automation with all of the above.
  • The knock-on effects on
    • Namespaces
    • Backups
    • Replication
    • Accounts
    • Workspaces
    • i18n
    • Web URLs
    • Developer documentation
    • Training
    • etc.
  • Securing 100% security and privacy
  • Cross-platform and environment portability

This has led to changes in the underlying Pipi System Engine (sys) data model, which I will write about tomorrow.

Nestspace

The fundamental organising principle is to use a uniquely named directory, now named as a "Nestspace".

The unique name is a string combination made of

  • <pipi major version> (integer)
  • <pipi edition> (single lowercase letter)
  • <account type> (single lowercase letter)

Data Centre / DevOps

Here are some examples.

  • 6sb/
  • 9ae/

Backups

Customer backup examples.

  • pipi_9ae_ajabbi_data_pg_20260411
  • pipi_9ae_ajabbi_pipi_www_learn.ajabbi.com_20260411

Archiving

Here are some examples.

  • pipi_6sn_20180219.zip
  • pipi_9ae_20241211.zip

Next job

Now, I can start configuring the files and settings for each Nestspace. The necessary code has already been successfully tested. Eventually, this process will be completely automated.

  • Application.cfc
  • server.xml
  • Datasources
  • OS environment
  • Java
  • Application server
  • Cloud platform
  • REPL

Speed is King

Then each Pipi will be back in business and can run 24x7 in its own Nestspace, increasing DevOps speed by at least 10x. The priority now is to increase Pipi's Data Centre speed by 1000x using automation and keep going. What previously took a year can now be done in an hour. The over-optimistic complete deadline is June 2026.

But nothing happens as expected

It is hard to make completion predictions when this architecture is completely novel, and everything is uncharted territory and hellish difficult. Everything is a back-of-the-envelope guess. I'm slowly getting there ... 

"like a man riding a drunken donkey facing the tail, two steps forwards, one step backwards"

... enjoying the whole journey and it's a hell of a lot of fun. 

Future customers

The increase in speed will also directly benefit all future customers using the SaaS workspace applications. Deployments, configuration, and updates will also get the same 1000x speed increases at no extra cost.

Pipi Data Centre Operational

Mike's Notes

Very good news for Pipi.

Resources

References

  • Reference

Repository

  • Home > Ajabbi Research > Library >
  • Home > Handbook > 

Last Updated

26/02/2026

Pipi Data Centre Operational

By: Mike Peters
On a Sandy Beach: 25/02/2026

Mike is the inventor and architect of Pipi and the founder of Ajabbi.

The long-planned migration of Pipi 9 to its own data centre has been completed. It took 2 weeks to execute. The existing setup was split into an office network connected to the internet and an isolated data centre that is not connected to the internet.

Starting from zero

The initial data centre consists of a single 45U rack and some other shelving, with mainly older equipment. It will do for a start and can grow as more racks are added, equipment upgraded, and more servers are added, etc.

External hard drives being used in the shift

Issues

  • Terabytes of data on backup hard drives to shift
  • Clean reinstalls of many operating systems
  • 14 machines to configure
  • Adobe CS4 does not like Windows 11
  • Making do with what is available now
  • Go slow, think twice and get there faster

Opportunities

  • Pipi on 24x7x365
  • All systems can be turned on using multiple servers
  • DevOps automation is now possible
  • The development cycle will speed up 10x
  • The road to Pipi 10 with BoxLang is now open

Whats next

  • Seat-of-the-pants experimenting to tune the setup
  • Stress test to build resiliency and reliability

Developer access to Pipi, is coming

Mike's Notes

The data is precise on this one. Unfortunately, the current developer interest in NZ and Australia is 3% and 0%, respectively. I also can't find anyone in NZ who has the slightest technical understanding of what I'm doing. But there are plenty overseas, especially in MLOps. We speak the same language, even if the architecture and algorithms are radically different. Also, top-grade mathematicians get it. Internally, Pipi 9 uses a lot of maths.

Resources

References

  • Reference

Repository

  • Home > Ajabbi Research > Library >
  • Home > Handbook > 

Last Updated

08/12/2025

Developer access to Pipi is coming

By: Mike Peters
On a Sandy Beach: 02/12/2025

Mike is the inventor and architect of Pipi and the founder of Ajabbi.

The problem

To launch Pipi 9 with limited resources in 2026, the effort needs to be highly focused on developers who build large enterprise systems and have experienced failure, cost overruns, and staggering complexity. This is for them.

Waste

The staggering annual global cost of IT failures on big projects is around $US 3 trillion. How many schools or knee replacements would that be?

  • 15% succeed
  • 25% makes no difference
  • 60% fail

Web traffic stats

The steadily growing web traffic statistics of public interest in Pipi 9 are becoming very clear.

Since early 2019, the total traffic stats by country are;

  • China 19%
  • Singapore 16%
  • United States 15%
  • Hong Kong 11%
  • Brazil 10%
  • TOTAL 71%

Developer Accounts

The initial paid Developer Accounts will be restricted to experienced DevOps teams with great internal culture in those five countries. That also affects the language, currency, hours of support availability, etc. Later, as interest and resources grow, that list of countries can be expanded.

Personal Accounts

The free Personal Accounts will initially use an English interface and will not be restricted by country of residence. They will get community support.

Enterprise Accounts

The initial paid Enterprise Accounts will be supported by their associated Developer Accounts, who can charge them whatever they want for that service. They will initially use an English interface and will not be restricted by country of residence. Developer Accounts will be able to translate UI and documentation into any language and writing system.

Pipi 9 is in hiding

This engineering blog and the many other Ajabbi documentation websites are deliberately hidden from search engines. People are visiting because they are curious, as I write notes to myself and build, learning as I go. It is not easy to find the technical documentation unless you are really interested, clever and very determined. That has helped me find some early, keen technical fans who provide testing and feedback. It has also protected me from being overwhelmed by enquiries.

Communication constraints

I am a very slow writer, using assistive technology, have hearing problems and prefer video chats with people who speak good, clear English. I don't speak any other language apart from tiny bits of Maori, French and Spanish.

SEO and GEO

The SEO/GEO settings will be fixed when

  • Pipi 9 matures and becomes ready for public use
  • Community support is in place
  • Bugs fixed
  • Enough self-help documentation to help people get started.

Developer Account waitlist

There will be a signup queue to control demand, so scaling is steady with a positive resource feedback loop to solve the chicken-and-egg problem. The small queue is growing now. I will pick the best candidates with the highest chance of success. They will gain a first-mover advantage in building large, custom enterprise systems faster and at a much lower cost. The first ones will get free unlimited support. 

Relying on word-of-mouth recommendations.

There will be no marketing or sales, just good, clear documentation, live demos, and regular bookable office hours (NZ daytime) for having a chat.

Inflexion point

In the future, as workspaces mature and Pipi 10 becomes even easier to work with, resource constraints will disappear, teams will grow, and an inflexion point will be reached. Anyone will then be able to sign up.

Updates to Versioning Engine

Mike's Notes

This week's changes to the Versioning Engine (ver).

Resources

References

  • Reference

Repository

  • Home > Ajabbi Research > Library >
  • Home > Handbook > 

Last Updated

16/10/2025

Updates to Versioning Engine

By: Mike Peters
On a Sandy Beach: 16/10/2025

Mike is the inventor and architect of Pipi and the founder of Ajabbi.

The recent UI workspaces work necessitated changes to Pipi's Versioning Engine (ver). That engine's data model was changed.

Objects that can change

  • Industry models
  • Industry Schema
  • Workspace UI's
  • User training material
  • Developer Documentation
  • Etc

Versioned namespaces

Every object has a versioned namespace. When a logged change to an object occurs, the Pipi Build Number increments.

On any day, if there is one or more changes to the Build Number, the daily Patch Release automatically increases by 1. The changes are then published in the Changelog.

Minor Release

On the second Friday of every third month, the Minor Release increases by 1. A big picture summary of the preceding three months is published in the Changelog.

Objects in sync

Changes to the workspace UI, developer documentation, user training materials, and related materials need to be kept in sync.

DevOps

Making sure that the recently added DevOps Engine (dvp) runs this sync process might work. It could be done using workflows.

Summary

The engines involved are 

  • Versioning
  • DevOps
  • Learning Object
  • Workspace
  • CMS

A roadmap to Pipi 10

Mike's Notes

Pipi 10 will run on BoxLang in production.

I sent draft notes to Ortus Solutions yesterday to discuss future use of BoxLang. I then edited the notes and shared them with the growing Pipi community. I will add the answers as more is discovered about what needs to be done to make it possible for Pipi 10 to use BoxLang.

Training is available on BoxLang Academy.

Can you spot any errors in my assumptions? Do you have other ideas or queries?

Contact me.

Update 04/06/2024, 05/06/2025

Cristóbal Escobar Henríquez from Ortus Solutions provided excellent answers to the questions sent via email. These answers have been added to the questions at the end of this article, which are slightly different from the original ones (all my fault). Thanks :)

Update 09/06/2025

Luis Majano from Ortus Solutions provided additional answers to my follow-up questions, which I sent by email. They have been added to the post below. Thank you, Luis.

Update 12/06/2025

Luis Majano from Ortus Solutions provided additional answers to my follow-up questions, which I sent by email. They have been added to the post below. Thank you, Luis.

Update 13/06/2025

Luis confirmed that BoxLang cannot use CommandBoc modules. It appears that BoxLang can currently handle 90% of my needs. The only real gap is that Pipi cannot currently autonomously configure BoxLang itself via the command line, which is needed for scaling.

This is sufficient to make a start, with the hope that Ortus will address these issues in the future.

I expect Pipi 10 to be a 12-month build after Pipi 9 is in full production.

Update 14/06/2025

There will be an online meeting with people from Ortus next week to discuss and confirm details regarding the migration plan, paid support, and sponsorship of Ortus' open-source.

Resources

References

  • Reference

Repository

  • Home > Ajabbi Research > Library >
  • Home > Handbook > 

Last Updated

14/06/2025

A roadmap to Pipi 10

By: Mike Peters
On a Sandy Beach: 21/05/2025

Mike is the inventor and architect of Pipi and the founder of Ajabbi.

Draft roadmap

  • This is a draft, so expect it to change
  • This roadmap is probably for the next 2-3 years at least
  • The finalised plan will be published for the Pipi Community.
  • No money is available right now.
  • A plan is needed to avoid rework.
  • Don't expect Ortus to do work for free.
  • Realistic expectations of what is possible.
  • Good income will come later from paying customers for solving complex problems.
  • Focus on the core by outsourcing other work to experienced contractors.
  • Open-source all modules on GitHub.

Ajabbi

  • The common name of 
    • A company to handle payments
    • Non-profit foundation to support users (to be established)
    • Research Institute for ongoing development (to be established)
  • Description
    • Solved a huge, expensive problem with no existing competitors
    • Pre-revenue start-up with no $$$
    • Growing community
  • Purpose
    • Act like other foundations (Wikimedia, Apache and Linux) and use the income surplus to support
      • Minority languages i18n
      • Open-source efforts (especially CFML, including Ortus)
      • User groups
      • User conferences
      • Book publishing
      • Open research grants
      • Etc

    Pipi

    • The name of the software
    • Mike has been the architect since 1997
    • Versions 1-4 were in production eventually with 300K lines of code, an 800-table database, ESRI Web GIS, 500 classes, 3K methods, a 5 FTE team and a 3-rack data centre
    • Versions 6-8 were working, non-production, undergoing refactoring
    • Version 9 works, moving to production (current)
    • Version 10 (planned)

    Current Pipi 9

    • Works great
    • Runs in a dev environment
    • Unique architecture with 20+ layers and hundreds of autonomous agents
    • Uses nature-inspired algorithms
    • Going from headless to a Pipi-generated UI
    • Migrating to a 42U server rack completely isolated from the internet.
    • Using old Windows server boxes will do for now.
    • The CFML code runs on ColdFusion Server 2021 Developer Edition.
    • The CFML code could run on ColdFusion MX, Open Blue Dragon, or Lucee. 
    • Uses <CF> tags as in Ben Forta, et al. (don't tell Michaela, I don't want to die)
    • Uses 300+ embedded config databases (MS Access)
    • Uses PostgreSQL for production data
    • Writes CFML code and then executes it
    • Writes SQL and then executes it to create and populate tables
    • Static HTML generator (90K page websites)
    • Uses XML, XML Schema, etc, internally
    • Mostly self-managing
    • Self-documenting
    • Currently rendering a 20,000-page static website for developers
    • The code base will self-grow 10x larger over time

    Planned Pipi 9

    • Some money is coming soon
    • Generate revenue from niche batch render jobs
    • Code generators and the generated code must be rewritten to be BoxLang compatible, so no refactoring by Ortus is required.
    • Pipi 9 will create Pipi 10
    • Pipi 10 to be BoxLang native
    • BoxLang (+++++++) paid support
    • Pipi 10 to become geodatabase capable
    • BoxLang will enable the future use of Python, PHP, etc

      Planned Pipi 10 Systems

      • Render System
        • Functions as an automated AI-assisted development environment
        • Isolated from the internet
        • Uses VM
        • Run on BoxLang installed on Windows on new 64 hardware
        • JDK 21+
        • Ortus to supply a ready-to-run VM image.
        • 100% self-managing via CommandBox dynamic CFML scripts
        • Renders working enterprise system modules (database, code, UI, API, user documentation)
          • MS SQL edition
          • MySQL edition
          • Oracle edition
          • PostgreSQL edition
        • Exports modules to the Staging System via manual hard drive transfers
      • Staging System
        • Connected to the internet
        • Uses VM
        • Runs on BoxLang installed on Debian
        • JDK 21+
        • Ortus to manage the BoxLang platform VM on a long-term contract
        • Uses PostgreSQL
        • Adds i18n to modules
        • Creates updates
        • Integrates i18n modules into customised enterprise systems for paying customers
        • Exports
          • Github
            • i18n modules to GitHub for open-source
            • i18n user documentation
          • Cloud
            • Customised i18n enterprise systems
            • System updates
      • Cloud System
        • Connected to the internet
        • Uses VM
        • Runs on BoxLang installed on Debian
        • JDK 21+
        • Ortus to manage the BoxLang platform VM on a long-term contract
        • VM hosted
          • AWS
          • Azure
          • Digital Ocean
          • GCP
          • IBM
          • etc
          • private cloud.
        • The customer chooses their production RDMS database(s) for their data.
          • MS SQL
          • MySQL
          • Oracle
          • PostgreSQL

      Questions for Ortus Solutions

      Answered by Cristóbal Escobar Henríquez, and Luis Majano.
      • Is a list of supported (or not supported) CFML tags available?
      • Is <Cf tags> style coding supported?
        • Yes, BoxLang fully supports CFML tags when running in CFML compatibility mode. This ensures legacy CFML applications can continue to function with minimal changes.
      • Is there a performance hit from using CML compatibility mode?
        • There is of course a penalty to pay if you are transpiling on the fly.  It's negligible to the point that we are faster in CFML mode than all Adobe engines even in transpile mode.  However, you can transpile to BX as part of your build process and then this won't exist.
      • Does BoxLang use CommandBox modules?
        • No.  BoxLang Modules are something new.  Eventually maybe, but for now, no.
      • Can BoxLang accept (CFML) command-line modules generated by Pipi without needing to be restarted?
        • Yes.
        • The ModuleService has the necessary API for you to load modules a-la-carte.  All of our integration testing uses this approach.
        • You can also uninstall them
      • Will these CF tags become compatible with BoxLang in future?
        • cfftp
          • This is done in our bx-ftp module
        • cfregistry
          • This can be sponsored if needed.
        • cfschedule
          • This is in progress, but can be accelerated by sponsorship
      • Could BoxLang use MS Access via JDBC on the isolated Render System, and how much would it cost to create a module to do this?
        • We can enable MS Access integration by building a custom module using the UCanAccess JDBC driver.
        • Estimated time: 10–15 hours (2–3 business days)
        • Note: This estimate covers driver integration only and does not guarantee full MS Access compatibility. As an alternative, we recommend migrating the database to SQLite, Derby, or MySQL for improved stability and long-term support.
      • What kinds of modules can be developed by Ortus?
        • Ortus can develop any module you need, whether it's for BoxLang, application features, integrations, or infrastructure. We tailor modules to your requirements, from core language enhancements to platform-level tools.
      • What is the cost for Ortus to provide dedicated platform support?
        • We offer dedicated platform support through our BoxLang+ and BoxLang++ plans, which include guaranteed response times, SLAs, priority bug handling, and access to our core engineering team.
        • You can review the full details and pricing here: https://boxlang.io/plans
        • We’d be happy to tailor a plan based on your service level and usage expectations.
      • Can patched VM images be supplied?
        • Yes, we can provide patched VM images as part of a BoxLang++ subscription. If you're not on a ++ tier, this can still be delivered through a separate consulting plan.
      • What about the time zone differences between New Zealand, the US, and Spain?
        • Our team operates mainly on Central Standard Time, but we can easily align with your schedule. If needed, we can also assign a developer located in the EU (CET) for better time zone overlap.
      • Would a 100% dedicated Ortus developer be possible in the future?
        • Yes, we offer team augmentation services, including assigning a dedicated developer to your project. We can adapt the engagement based on scope, timeline, and availability.
      • Is a 24/7/365 platform supported by Ortus possible in the future?
        • Yes, that’s absolutely possible. We can support a 24/7/365 production environment using our teams in El Salvador and Spain. This would require a custom service agreement or license tier beyond the standard BoxLang offerings, but we’re happy to scope and price this accordingly based on your needs in the future.

      Questions for the Pipi Community

      • Would support also be available from independent CFML contractors?

      • Where is the boundary between community contributions and paid contractors?

      • What other new BoxLang Modules would be helpful, including other coding languages?