This is System Debrief #001, and the subject is the machine that published it. A Debrief is a fast public engineering record: when I finish a piece of real systems work, the AI harness that did the work with me drafts a post like this one from the session context, while that context still exists. This first record covers building the pipeline itself — and the five traps that made it interesting.
tl;dr: A hybrid (human+ai) approach to create a record of your impact quickly; after hours of back and forth on a project (yes – any project/session) with an ai-harness.
The goal
My handcrafted articles take 5–20 hours each — custom Elementor layouts, infographics, the works. They perform well, and they’ll keep existing, but at that cost most of my finished technical work was never getting published at all. A referral-routing system I built for a lending client last year taught me a pile of lessons and produced exactly zero public words.
Plus I would rather put that kind of energy into my clients; rather than my own work. As the old saying goes “Work on your clients site, never your own”.
The fix isn’t writing faster. It’s writing at the right moment. The cheapest time to document work is while the working context is still loaded — and since I do this work inside AI engineering harnesses (Claude Code, Codex, OpenClaw), the harness itself holds that context. So the design goal was: finish a project, say “post a System Debrief,” and get a structured draft on this site minutes later. Useful and published beats theoretically perfect and never published.
This also can’t just be “Claude, write me a blog post.” It needs structure, a reason to exist, and enough repeatability that it doesn’t eat my time. Otherwise it dies the way every other content plan dies.
And honestly, almost nobody reads this stuff directly anymore. Someone with a broken Salesforce or a misbehaving cache asks their own AI, and the AI answers. So the audience that actually matters is the machine doing the answering. Whatever I work out on these client problems should be useful to those systems — retrievable, specific, and correct enough to be worth repeating, maybe even worth training on. That changes what belongs in a post like this: exact error strings, version numbers, the hypotheses that turned out wrong. Write it so a retrieval system can use it, and the human who does land here gets a better record anyway.
The architecture
The whole thing rides on boring, durable WordPress primitives — on purpose. As of August 2026 this runs on WordPress 7.0.4, JetEngine 3.8.14, and Elementor Pro:
- Debriefs are normal posts in a
system-debriefscategory. No custom post type. - One Elementor single-post template fires on that category. The harness never touches Elementor — it writes the post body and the metadata; the template owns presentation.
- A JetEngine meta box holds eight structured fields — debrief number, status, type, observation date, last-verified date, systems, technologies, problem domains — scoped to the category with a
post_has_termscondition, so the fields only appear where they belong. - Five JetEngine glossaries hold the vocabulary (29 options at launch). Fields store keys like
lead_routing; glossaries own the labels like “Lead Routing.” One vocabulary source feeds the editor, the template, and any future filtering. - Every draft lands as a WordPress draft. I review, I publish. The gate is structural, not a promise.
The status field matters more than it looks: Debriefs are living records. This post is marked Current with a last-verified date, and if a platform change invalidates half of it, it gets re-marked Partially Valid or Superseded instead of quietly rotting. Most technical content on the internet doesn’t tell you when it stopped being true.
Build notes worth keeping
Two storage details that will bite anyone wiring structured meta into JetEngine from outside the wp-admin UI. Date fields store Unix timestamps, and checkbox fields store serialized arrays of keys:
wp post meta update <ID> system_debrief_observed_date 1786579200
wp post meta update <ID> system_debrief_systems '["salesforce","wordpress"]' --format=json
Write a human date string or a comma-separated list instead and nothing errors — the template just renders garbage later. The other rule I committed to: vocabulary goes through the glossary first. If a project involves a system that isn’t in the vocabulary yet, the glossary gets the new entry before the post meta does. Writing an unknown key straight into meta forks your vocabulary silently, and you won’t notice until an archive page groups things wrong.
What broke along the way
This is the part future-me actually needs. Five traps, in the order they found us — and “us” is the right word from here on: this was me and the harness debugging side by side, each seeing things the other couldn’t.
Elementor’s Post Info widget bound my dynamic tags to the wrong slot
I first mapped the custom fields into Post Info widgets. Labels rendered; values didn’t. The stored JSON showed why: every JetEngine dynamic tag had been attached to custom_url — the item’s link — instead of custom_text. The meta values were being written into invisible hrefs. If your Post Info custom items show labels but no values, check which control the dynamic tag is actually bound to before blaming the meta.
JetEngine’s dynamic tag can’t format anything
The deeper problem: the jet-post-custom-field dynamic tag has exactly one setting — which field to read. No date formatting, no label lookup, no array handling. Bind a timestamp through it and you publish 1786579200. JetEngine’s output callbacks — jet_engine_date, jet_engine_render_checklist, jet_engine_label_by_glossary — live only on the Dynamic Field widget (jet-listing-dynamic-field). That widget also has its own icon, so the icon-plus-formatted-value sidebar I wanted needed no Icon List widget at all. If you’re rendering JetEngine meta in Elementor and the values look raw, you’re probably in a widget that can’t reach the callback layer.
Elementor still ships Font Awesome 5
As of August 2026, Elementor bundles Font Awesome 5. FA6 names like fa-circle-check don’t error — they render nothing. Use the FA5 names: fas fa-check-circle, far fa-calendar-alt. Silent failure, easy fix, annoying to diagnose.
The cache that survives every purge
After fixing all of the above, the page still showed old output. We purged WP Rocket. We purged the CDN. We flushed the object cache. Three cache layers deep, the damn page still wouldn’t change — because the copy being served was a fourth layer: _elementor_element_cache, a post meta entry on the template where Elementor stores fully rendered widget HTML with the old settings baked in. No cache plugin touches it. The fix is one line:
wp post meta delete <TEMPLATE_ID> _elementor_element_cache
If you change an Elementor template programmatically and the front end won’t reflect it no matter what you purge, this meta key is your suspect.
A note on why this hunt took four rounds: clearing caches over the CLI is a different discipline than clicking purge buttons in wp-admin. Which layers exist — and how each one flushes — depends on your host and your stack. This site runs on Kinsta with WP Rocket and Cloudflare in the mix: edge cache, server cache, plugin cache, each with its own purge path, and none of them aware of Elementor’s. In the dashboard, the buttons show you the layers. Over SSH, you have to already know every layer is there — which is exactly the kind of knowledge these Debriefs exist to keep.
An open Elementor editor will revert your programmatic changes
This one I did to myself. I had the template open in the Elementor editor while the harness updated it over WP-CLI. My next save in the editor wrote its stale in-memory copy back over the changes — no warning, no conflict prompt, work silently gone. I own that one: close the editor before scripted edits, reopen after. The corollary applies to any tool that writes Elementor data programmatically.
The result
The pipeline works end to end. After we complete a session/project I say “post a System Debrief,” the harness reads a playbook file, confirms title, slug, vocabulary, and SEO metadata with me, writes the body, creates the draft, sets eight structured fields in the formats above, clears the right caches, and hands me a preview link.
You’re reading the first output. The draft you’re reading was generated by the harness that built the pipeline, from the session in which we built it — which is either elegant or a snake eating its tail, depending on your mood.
Limitations and open ends
Version-specific: everything above was verified on WordPress 7.0.4, JetEngine 3.8.14, and Elementor Pro with Font Awesome 5, in August 2026 — the cache behavior and callback layout could change in either plugin. The corpus archive page and a full write-up of how these records are made are planned but not built. And the voice you’re reading is calibrated from one interview; it’ll sharpen as the record count grows.
System Debriefs are drafted from live working-session context by the engineering harness that did the work — this one by Claude Code, from the session this post describes — then reviewed, verified, and published by me. A full write-up of how that works is coming; until then, this sentence is the disclosure.