e11

punah · Legacy WordPress, rebuilt as static infrastructure

A WordPress rebuild you can read end-to-end.

punah rebuilds legacy WordPress sites as maintainable static Astro infrastructure — captured into a typed bundle, composed from a primitive library, staged at <slug>.punah.pro for review before you commit to cutover.

Typed content records. Open primitive library. Substrate over template versioning.

Surface signal

Status

BETA

Substrate

One template

Staging

<slug>.punah.pro

Why this exists

A WordPress site that has been live for years is no longer a website. It is a continuous business risk.

Plugin sprawl, abandoned themes, fragile shared hosting, brittle PHP versions, an admin login surface scanned every minute by botnets. The site keeps serving traffic, so the risk stays invisible — until a plugin CVE lands, a host migration breaks the database, or a redesign quote comes back priced like a re-platform because nobody knows which of the seventeen page builders is load-bearing.

punah rebuilds the site as a static Astro deployment from a captured bundle, stages it at <slug>.punah.pro for review, and only then talks about DNS cutover. Nothing in production moves until the rebuild is one you can read end-to-end.

Self-sustained by design

Owned, not rented.

A rebuild that depends on a managed CMS, a shared hosting tenant, or a closed template format trades one captive runtime for another. punah ships a rebuild whose runtime is a directory of files — your files, on infrastructure scoped to you.

01

Static, by default.

The output is a directory of HTML, CSS, and images. No PHP runtime, no database, no admin panel exposed to the internet. The attack surface drops to whatever serves files — and that surface is one you can audit in an afternoon.

02

Your bundle, your S3 namespace.

The capture bundle — pages, posts, media, taxonomies, redirects — is stored on a customer-scoped S3 prefix. The rebuild reads from there. We don't aggregate your content into a shared lake, and there is no path where a third-party CMS holds the canonical copy.

03

Staged before cutover.

The rebuild lives at <slug>.punah.pro for as long as you need to review it. The legacy WordPress keeps serving traffic. DNS cutover is a deliberate event, not a deploy artifact — you sign off on the rebuilt site before it sees a single search-result click.

04

Off the shared edge.

punah staging runs on its own Hetzner box, on a separate trust zone from the rest of the Eleven11 fleet. Different SSH key, separate Caddy, no shared Docker network. A rebuild's blast radius is its own host.

05

Open primitive library.

Every shape on every rebuild — hero, prose, video portfolio, card grid — comes from a typed primitive in the substrate. Adding a new shape is a typed module and a register call. There is no proprietary template format and no per-customer fork to lose track of.

The primitive

Three layers you can name. Typed.

punah is built on a substrate, not a stack of templates. Typed records carry shape, a primitive library renders them, a composer wires shape to layout. Each layer is independently swappable; none of them is per-customer.

α · Typed content record

shape

customers/<slug>/content/*.json

Every page coming out of capture lands as a normalized JSON record with a shape — home, article, video-portfolio, article-portfolio, blog-index. Shape is narrow on purpose. New shapes earn their place by appearing in a second customer.

β · Primitive library

Hero · Prose · CardGrid · …

templates/brochure-v1/src/primitives/

Nine typed Astro primitives with locked Props. They never read content directly, never reach into composers, never hard-code colors. Visual tokens come from CSS custom properties at the layout level. Forking a primitive for one customer is forbidden.

γ · Composer

compose(page, site)

templates/brochure-v1/src/composer/

One pure function per shape. Takes a normalized page and a site, returns an ordered list of BlockSpec. No fetch, no file I/O, graceful downgrade when data is missing. The composer is the only place shape becomes layout — everything else is rendering.

How it fits the fleet

A rebuild is a flywheel input, not a one-shot.

punah doesn't live alone. The bundle comes from harvester, the audit motivation from Dhara, the surface delta lands in discovery, the post-cutover content surface is pr. Every rebuild produces typed evidence the rest of the fleet reads.

harvester

The phoenix_capture recipe takes a WordPress site — black-box or via REST when we have credentials — and produces an items.zip bundle on S3. punah reads from that bundle. The CPT-aware capture (wp/v2/types + wp/v2/taxonomies) means non-default post types come over typed, not as opaque HTML.

phoenix

phoenix is the internal name for the substrate; punah is the CLI you run. Same repo, same primitives, same composer. The split is naming discipline — phoenix is the engineering object, punah is what the customer sees.

dhara

Before the rebuild, Dhara audits the legacy WordPress and lays down the evidence that motivates the rebuild. After cutover, the static site is one fewer admin login surface for Dhara to flag — the rebuild is itself a remediation.

discovery

Each cutover emits a tech_fingerprint delta — WordPress + plugins present on the legacy host, WordPress absent on the rebuilt host. Discovery's intelligence graph picks up the change and the customer's surface risk recalculates.

pr

Once the rebuild is live and a customer wants ongoing content, the staged site can become a downstream pr consumer — HMAC-signed publishes from a pr pipeline land as new content records, trigger a rebuild, and ship. This is opt-in, post-cutover, and not part of the v1 rebuild itself.

tira

tira sees the customer state machine — capture, build, stage, hold, pinch, settle — and offers a rebuild button that shells the punah CLI. The CLI is the source of truth; tira is the operator viewer.

Surfaces & contracts

Six things you actually call.

Five CLI verbs and one review URL. The customer journey is the contract — every verb advances a stage, and a stage you haven't reached is one you can't skip past.

punah init <slug>

Scaffold the customer.

Creates customers/<slug>/ with state.yaml, config.yaml, an empty overrides directory, and the stage machine pinned at the start. Idempotent.

punah build --customer <slug>

Bundle to typed content to dist.

Pulls the bundle from S3, normalizes it into typed records with shape inference and embed extraction, runs the composer, and produces a static Astro dist. Reproducible per bundle SHA.

punah stage --customer <slug>

Atomic staging on phoenix-host.

rsyncs dist to /srv/<slug>.tmp, swaps the live directory in one mv, writes the per-customer Caddy vhost, validates and reloads in-container. The state machine advances to stage=stage.

<slug>.punah.pro

The review surface.

The rebuilt site, served by Caddy on phoenix-host, with TLS, a sitemap, robots, and absolute canonicals threaded from state.yaml. This is what the customer reads — for as long as they need to read it — before any DNS conversation.

customers/<slug>/overrides/

Tokens, not forks.

Per-customer tuning lives here as tokens.css and styles.css. Override the paper tone, swap an accent, add a token. What you cannot do is replace a primitive — that's a substrate change, made for everyone.

punah pinch --customer <slug>

Cutover, when you say so.

Flips canonical_origin from the staging subdomain to the customer's real domain, emits a 301 from the subdomain, and queues the A-record change for execution. Pinch is monotonic — it doesn't run before the customer signs off.

Senior engineering, visible

The proofs are in the substrate.

Five decisions visible in the typed records, the composer purity, the state machine, and the deploy shape — not adjectives, design choices.

Substrate over template versioning.

There is one template — brochure-v1 — and one substrate. Customer variation lives in typed content records and in tokens, never in a forked template tree. The cost of customer #N is the cost of a bundle and a tokens override, not the cost of another template to maintain.

Pure composers, typed Props.

Composers are pure functions. Primitives accept a typed Props object and never reach back to content. Props changes are breaking substrate changes that bump a version and update composers — not silent template tweaks that drift across customers.

Monotonic state machine.

state.yaml carries the stage — capture, build, stage, hold, pinch, settle — and progression is one-way. punah stage refuses to re-run from hold. punah pinch refuses to run without signoff. The CLI defends the customer journey rather than papering over it.

Atomic swap, never in-place writes.

Staging never writes to the live serving directory. The rebuild is rsynced to a sibling tmp directory and swapped in one mv. A failed stage leaves the previous build serving traffic — no half-deployed sites, no broken cutovers from a bad upload.

Reproducible builds.

Bundle SHA + content hash + template SHA + tokens hash determines the output. Rebuilding the same customer six months later from the same bundle produces the same dist. This matters when the question is whether the rebuild changed under you, or the legacy did.

Who this is for

Operators carrying a WordPress site that still earns.

punah earns its keep when the cost of operating a legacy WordPress — security drift, plugin sprawl, hosting fragility, redesign quotes priced like re-platforms — starts to exceed the cost of rebuilding the thing as files.

Operators sitting on a 5–10 year-old WordPress site that still drives the business and is now expensive to touch — every plugin update is a held breath.
Founders who inherited a site from an agency, lost the agency, and now own a CMS they can't audit — punah replaces the question "who can fix this?" with a directory of files.
Teams whose security posture cannot accept a public WordPress admin surface but whose content team isn't ready to migrate to a headless CMS yet.
Brochure and editorial sites with strong SEO equity that need to be rebuilt without losing rankings — Hold-on-subdomain plus delayed pinch is the cutover model.
Operators who want infrastructure they can read end-to-end — static files, a Caddy vhost, a typed bundle on S3 — instead of a CMS they can only operate.

FAQ

Final friction, reduced.

Will my SEO survive the rebuild?

The rebuild ships sitemap.xml, robots.txt, and absolute canonicals threaded from state.yaml. canonical_origin is the staging subdomain during review and auto-flips to your real domain at pinch. Redirects from the original URL map travel with the bundle. Hold-on-subdomain plus delayed pinch is exactly the cutover model that protects rankings — your legacy WordPress keeps serving until you sign off.

What does punah refuse to rebuild in v1?

WooCommerce, LMS, membership, paid tiers, shortcode translation. The v1 substrate is brochure and editorial. Anything with a runtime payments or accounts surface is a different shape of project and we'll tell you so up front rather than ship a rebuild that loses behavior.

Why one template? What if I want a custom look?

The look is per-customer. The substrate isn't. Tokens — paper tone, accent, type scale, spacing — live in customers/<slug>/overrides/tokens.css and override the brand-generated tokens. What we don't do is fork primitives per customer; if a customer truly needs a new shape, that shape lands in the substrate and is available to everyone.

What status is punah in today?

Beta. The first customer (yaqutali) is staged at yaqutali.punah.pro. The substrate is rich enough that subsequent customers should intake with zero template changes. Engagements are bookable now and we'll tell you which phase of the v1 plan a deferred capability sits in if you ask for it.

Discuss punah

Rebuild the site, before the next plugin CVE.

punah is in beta with the first customer staged. If you have a legacy WordPress that earns its keep and you'd rather not keep paying its operating tax, talk to us about a rebuild.

Direct line

Consultation requests stay owned. We reply from e11 after reviewing fit and timing.