POSTCARRY 1.0.0 / FIELD GUIDE
Carry the content.
Keep the evidence.
A practical guide to moving a supported Hugo blog into an editable Astro project. Built for maintainers who want a reviewable handoff.
Linux x64 · Node.js 22.12+ · Local browser · No account
1. Your first result
Extract the complete buyer ZIP into a new folder on Linux x64. Install Node.js 22.12 or newer if it is not already available. Open a terminal in the extracted folder and check node --version. The buyer ZIP bundles Linux runtime dependencies and Hugo; no package download is needed for the sample workflow on the tested host.
node start.mjs
Open the printed http://127.0.0.1:PORT address in Chrome. Keep the terminal open. Choose Try Harbor Notebook. Nothing is uploaded to an external service.

Expect four authored pages: two published and two excluded from the build. The published routes are /notes/tide/ and /notes/gear.html. /old-tide/ is an alias to Tide & timber. One original SVG is copied byte for byte.
Choose a page in the left column. Switch between Original Markdown and Carried Markdown. Then choose Build & compare. A sample build takes a few seconds on the tested host; larger projects take longer. Wait for its result before opening another baseline.

2. Capture your own source
Use a trusted local copy of your Hugo project. The capture command below explicitly runs its Hugo templates in a temporary copy. Do not use it on an untrusted downloaded repository. The web app never runs imported templates or npm scripts.
For capture, the single-page template must expose exactly one article containing .Content, and the original title and date. You can add the marker to your existing single template in the copy. The minimum capture template is:
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>{{ .Title }}</title>
<body><main>
<h1>{{ .Title }}</h1>
<time datetime="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}">
{{ .Date.Format "2006-01-02" }}
</time>
<article data-postcarry>{{ .Content }}</article>
</main></body></html>The original sample uses layouts/_default/single.html. This marker isolates authored article content from navigation and theme wrappers; all content inside that marker is compared. Your source requires an explicit, timezone-bearing date on every authored page. Dates and lastmod values retain their textual offsets in exported metadata.
chmod +x tools/hugo node tools/capture.mjs \ /absolute/path/to/trusted-hugo-copy \ /absolute/path/to/new-baseline.postcarry.json \ 2026-10-03T00:00:00Z \ "$PWD/tools/hugo"
Choose the intended build clock; the example clock is fixed for reproducibility. Keep the new baseline file outside the source folder. Existing output files are never overwritten. The command reads and hashes the source before and after the Hugo build and native page-list capture. If those hashes differ, capture fails. Symlinks are refused. Generated public, resources, node_modules, .git and the Hugo lock at the source root are excluded; other source files are inventoried.
Choose Open a baseline in PostCarry and select the new JSON file. A bare folder or arbitrary Hugo output is insufficient: the source, native HTML, page lists, clock and hashes must travel together.
3. Review, correct, and compare
The plan shows authored-page membership, exact native routes, aliases, resources and findings. Draft and future pages remain in the handoff but are excluded from the published site at the captured clock. Unknown metadata, raw HTML, custom shortcodes and other unsupported constructs stop the migration.
Correction happens in a working source copy. Review the indicated file and line, replace the unsupported construct deliberately, capture a new baseline, then reopen it. PostCarry does not silently delete unknown content or edit your source.

Build & compare builds only PostCarry's generated pinned Astro scaffold. It compares native rendered article text in document order, structural blocks, headings and IDs, code, lists/tables, figure fields, link destinations, timestamps, aliases, local fragments and asset hashes. Syntax-highlighting spans and presentation wrappers are ignored; code characters are retained, with one terminal newline normalized. Prose whitespace is collapsed. External links are compared but never visited.

Hugo and Astro rendering rules are not identical. A build can succeed while comparison fails. In that case, the differences remain visible and export stays blocked. Unsupported typography/rendering variants may require source correction; there is no “ignore and certify” button.
4. Export and reopen
Choose Download Astro project. Extract into a new folder. Keep proof.json and migration-plan.json with the handoff. The latter includes source dispositions, original-to-target routes and resource hashes.
| Folder or file | Purpose |
|---|---|
| src/content/posts/ | Editable Markdown and supported frontmatter. |
| original-metadata/ | Exact original frontmatter text, including typed TOML dates and offsets. |
| unpublished/ | Converted draft/future Markdown, retained outside published output. Native renders are retained separately in unpublished-rendered/. Draft/future leaf-bundle resources are kept in unpublished-assets/, outside dist/. |
| public/ and dist/ | Copied assets and the already built static recipient site. |
| headings.mjs, routes.json | Native heading-ID mapping and exact route/alias instructions. |
| package.json, package-lock.json | Pinned Astro starter dependencies; acquire once when rebuilding independently. |
To view the included built site, serve dist with a local static server, for example:
python3 -m http.server 8080 --directory dist
Open http://127.0.0.1:8080/notes/tide/ for the example. The starter adds a neutral article index at / unless an authored route already occupies it; it does not migrate your homepage design, navigation or taxonomy pages. For a fresh independent rebuild of the exported starter:
npm ci npm run build
The starter's dependency installation requires network access once; its compiled dist is already usable. Use the built site to check exact routes. The development server exposes temporary /carry-generated/ routes before finalization. When intentionally changing headings, update headings.mjs; when changing URLs, update the route map. Any edits invalidate the old proof; recapture and rebuild for new evidence.

Use Save baseline to retain the frozen project as JSON. Reopen it through Open a baseline to reproduce the transformation. Reopening deliberately resets build proof; run the comparison again. Save and download before closing the terminal. Ctrl+C stops the server and deletes its temporary build folders.
5. Eligibility and boundaries
| Supported | Exact boundary |
|---|---|
| Markdown | UTF-8 .md with YAML or TOML frontmatter; standalone pages and leaf bundles. Headings, paragraphs, emphasis, inline links/images, lists, blockquotes, fenced/inline code, GFM tables and strikethrough. |
| Metadata | title, description, date, lastmod, draft, slug, url, aliases, tags, categories and publishDate. Dates require explicit RFC3339 timezones. Unknown fields block and remain in the saved source baseline. |
| Shortcodes | Angle-delimited figure, ref, relref and highlight with language only. Figure supports src/alt/title/caption/attr/attrlink/link/target/rel/width/height. Custom classes, percent delimiters and options are refused. Literal shortcode text in code must use Hugo's documented comment escape. |
| Resources | Local PNG, JPEG, WebP, GIF, SVG and PDF in static/ or a leaf bundle. Bytes are copied unchanged. SVG is never executed in the review UI. Check your own assets before deployment. |
| Routes | Native page-list authority; root-relative slash-terminated or .html paths, aliases and internal fragments. No query-bearing primary routes, traversal, malformed escapes or normalized collisions. |
| Limits | 500 Markdown pages; 5,000 source files; 250 MiB source bytes plus published and unpublished native article HTML; 1 MiB each recognized text/native HTML file; 20 MiB binary resource; 360 MiB serialized baseline intake. Limits are rejection boundaries, not a speed guarantee. |
| Excluded | Multilingual sites, branch-bundle authored pages, modules/mounts, config directories, custom outputs, custom shortcode overrides/render hooks, raw HTML, footnotes, reference-style links, task-list controls, custom typographer mappings and expiry scheduling. |
Theme design, homepage, menus, taxonomy styling, RSS, search, comments and deployment are outside this content migration. No universal Hugo compatibility, SEO or accessibility-compliance claim is made. Remote assets are not fetched or checked for availability. Native comparison can reject a rendering variant even when its syntax looks eligible.

6. Troubleshooting
| Message or symptom | Next action |
|---|---|
| Baseline import fails | A new import clears the previous review and proof immediately. Read the error shown in view, repair or recapture the baseline, and reopen it. Build & compare must pass again before download. |
| esbuild EACCES after extraction | Re-extract with a tool that preserves Unix executable permissions, such as unzip. Python zipfile extraction can discard them. |
| Astro cannot write its config directory | Use a writable XDG_CONFIG_HOME and ASTRO_TELEMETRY_DISABLED=1 when rebuilding the recipient in a restricted environment. |
| node: command not found | Install Node.js 22.12+ and reopen your terminal. |
| Permission denied for tools/hugo | Run chmod +x tools/hugo. The bundled binary is Linux x64 only. |
| Missing article marker/title/date | Add the documented capture wrapper in your working copy and recapture. |
| Source hash changed | Stop editing/build watchers during capture, choose a new output path, then retry. |
| Unknown field or shortcode | Decide its meaning in your source. This version does not infer custom rendering. Never remove meaningful content merely to obtain a pass. |
| Unreachable link or missing fragment | Repair the original link/anchor or supply the missing local resource, then recapture. |
| Build finishes, comparison fails | Read the first differing token. Check punctuation, captions, dates and custom rendering. The output has not been verified; export remains disabled. |
| App cannot resolve dependency | Re-extract the complete Linux buyer archive. For development use npm ci with network access and your writable npm cache. |
| File already exists | Choose a new baseline filename. PostCarry refuses silent overwrites. |
7. Privacy, provenance and removal
The app binds to 127.0.0.1, checks exact Host/Origin and a random mutation token, and serves no arbitrary filesystem routes. Imported source is displayed as text. The baseline includes your source files and rendered HTML; do not share it if those are private. The recipient ZIP includes original metadata and excluded drafts/future content—review its contents before sharing.
The bundled sample and illustrations are original fictional material. Runtime screenshots were captured from the running app and generated site on Linux x64, Node 22.22.2, Chrome 152.0.7977.82, Hugo 0.167.0 and Astro 7.3.5. Other hosts and Hugo versions are unverified. Open-source libraries keep their own licenses; see THIRD-PARTY-NOTICES.md and bundled dependency license files.
To uninstall, stop the terminal process, delete the extracted PostCarry folder and any saved baselines/downloads you no longer need. Your original Hugo source was never edited by the app. No account cancellation is needed.