Skip to content

2026-05-13 — petrova.codes build plan and stack decision

Status: proposed Author: ops@devarno.cloud Decides for: distribution surface architecture, stack, deployment, build pipeline

petrova.codes is a reserved domain (per 2026-05-08 decision) for the artifact distribution surface. PRODUCT.md and DESIGN.md define its purpose and visual dialect. A four-stream synthesis analysis (primary plan + alternative approach + critical review + factual verification) identified the optimal architecture and exposed three blocking implementation issues requiring decision docs before code execution.

  • Framework: Astro 5, fully static (output: "static"), no SSR
  • Deploy: Vercel, separate project from petrova.host and petrova.blog
  • Domain: petrova.codes (custom domain, manual Vercel project setup by operator)
  • Environment: Node 20+, npm install with --no-audit --no-fund, standard Astro build

Rationale: Static sites are cache-friendly, deploy fast, and require no runtime. Astro 5 aligns with existing site/ and dashboard/ (polyrepo-shaped monorepo pattern). Separate Vercel project isolates from dashboard/ SSR requirements and site/ editorial scope.

Versioning is first-class, not inferred. Per critical review finding #4, artifacts (skills, prompts, schemas) have no embedded version field. Semantic versioning is applied via a single source file:

codes/src/data/versions.yaml — canonical version registry:

skills:
petrova-act: "0.1.0"
petrova-boundary-check: "0.1.0"
# ... (11 total, one per skill)
prompts:
00-bootstrap: "0.1.0"
# ... (11 total, one per prompt)
cli: null # null until GitHub Release exists

pull-content.ts reads this file at prebuild. Every artifact stamped with its version. Updates to versions.yaml are PRed for audit (MR-7 append-only workflow).

Content collections: Three Astro content collections with Zod schemas:

  • skills (content type)
  • prompts (content type)
  • schemas (data type — JSON Schema rendering)

Each artifact carries: name, version (from versions.yaml), description, updated (git log ISO date), status (enum: published/draft/deprecated), optional source path for attribution.

codes/scripts/pull-content.ts — prebuild script with three phases:

  1. Hard-fail guards. Assert all source directories exist and are non-empty: ../skills/ (≥1 subdir), ../core/prompts/ (≥1 .md), ../spec/verbs/ (≥1 .schema.json). Exit with clear error message on failure. Never silently produce empty collections.

  2. Content transformation and copy:

    • Skills: read SKILL.md, extract existing name/description, stamp version/updated/status, write to src/content/skills/<slug>.md
    • Prompts: extract title from first H1, no existing frontmatter, stamp full frontmatter, write to src/content/prompts/<slug>.md
    • Schemas: read JSON Schema, extract $id/title/description, emit .md stub with JSON in code block, write to src/content/schemas/<slug>.md
  3. Machine-consumable indices:

    • public/manifest.json — flat JSON array of all artifacts (type, slug, name, version, description, updated, status, url) for client-side search
    • public/llms.txt — structured text index per llms.txt spec for agent consumption

Wipes destination directories idempotently before copy. Logs counts per collection.

Critical blocker resolved: Vercel’s default shallow clone does not fetch git submodules. core/prompts/ is a git submodule. Without explicit config, the prompts collection is silently empty on Vercel builds.

Resolution: Set ENABLE_GIT_SUBMODULES=1 in the Vercel project environment variables (manual step by operator during project setup — cannot be done via code).

GitHub Releases do not yet exist. Critical review #6 confirmed zero releases. The /cli page is published as “coming soon” stub with npx install instructions only — no broken GitHub Release links.

Once a tagged release exists, update /cli and versions.yaml CLI entry. This decision does not block the codes/ launch.

Vercel rebuild is triggered only on changes to codes/, skills/, spec/verbs/, or core/prompts/. Ignores unrelated monorepo changes (registry updates, decision docs, dashboard tweaks):

"ignoreCommand": "git diff HEAD~1 --name-only | grep -qE '^codes/|^skills/|^spec/verbs/|^core/prompts/'"

Distribution dialect per DESIGN.md: utilitarian, no editorial serif, system-sans body, monospace for labels/code. Single layout (Distribution.astro), one component (ArtifactCard.astro). Iron-oxide accent tokens shared with other surfaces. No nav, no sidebar — task-completion optimized.

Indexing: No noindex meta tag (opposite of blog). Artifacts should be discoverable via search engines.

Search: Client-side filter over pre-rendered manifest.json on the index page. No backend required. No pagination.

  1. Content partition (see 2026-05-13-petrova-codes-content-partition.md) — Ensures blog and codes don’t duplicate content.
  2. Submodule support on Vercel — Documented as environment variable ENABLE_GIT_SUBMODULES=1 (operator responsibility).
  3. Versioning mechanismversions.yaml is the canonical source.
  4. CLI releases — Deferred; /cli page is stub.
  • Separate repo, not monorepo. Rejected: increases blast radius, breaks polyrepo pattern already established by site/ and dashboard/.
  • 11ty instead of Astro. Rejected: loses consistency with existing stack, Astro 5 content collections are well-suited.
  • MCP API as content source. Rejected: build-time network dependency on petrova.host creates fragility; file copy is more resilient.
  • Single-page searchable index (pkg.go.dev pattern). Partially accepted: added client-side filter on index page (hybrid approach).

For code:

  • New codes/ package: package.json, astro.config.mjs, vercel.json, TypeScript config, 6 pages, 1 layout, 1 component, 1 stylesheet, 1 prebuild script
  • versions.yaml created with "0.1.0" baseline for all artifacts
  • skills/petrova-*/SKILL.md not edited; sourced as-is by prebuild

For docs:

  • Two new decision docs (this and partition doc)
  • Vercel project setup instructions (manual, not automated)

For deployment:

  • Vercel project petrova-codes created manually by operator with:
    • Root Directory: codes/
    • Environment: ENABLE_GIT_SUBMODULES=1
    • Connected to GitHub repo petrova-codes/petrova at main branch

For in-flight phases:

  • No active phases affected; this is new surface

For invariants:

  • MR-3 (sibling files): skills/petrova-*/SKILL.md is a sibling consumed by both codes/ and blog/.
  • MR-4 (absolute dates): This decision is dated 2026-05-13.
  • MR-7 (append-only): All choices recorded here; no retroactive edits on deployment.
  • MR-12 (CLAUDE.md projection): No consumer CLAUDE.md references this; it’s operator-facing.
  1. codes/ builds cleanly: cd codes && npm install && npm run build with 0 errors, 0 warnings
  2. Expected page counts: 11 skills, 11 prompts, 13 schemas, 1 index, 1 cli stub, 1 404 page
  3. dist/manifest.json is valid JSON with correct artifact counts
  4. dist/llms.txt is non-empty with Skills/Prompts/Schemas sections
  5. No noindex meta tag in rendered HTML
  6. Detail pages render with ArtifactCard component and copy-to-clipboard buttons
  7. Submodule is fetched during build (validate via Vercel environment variable set)
  • PRODUCT.md — distribution surface definition
  • DESIGN.md — Distribution dialect spec
  • docs/decisions/2026-05-08-petrova-domain-pivot.md — domain acquisition
  • docs/decisions/2026-05-13-petrova-codes-content-partition.md — content partitioning (blocks this decision)
  • Four-stream synthesis analysis (OpenCode planning session)
  • Subagent: OpenCode planning session (synthesis analysis + critical review)
  • Human: awaiting confirmation