Files
wp-materialize/AGENTS.md

6.1 KiB
Raw Blame History

wp-materialize Agents Specification

Purpose

wp-materialize is an automation compiler that materializes specified Markdown files in Git repositories (or local directories) into WordPress posts. Git / filesystem state is the single source of truth; WordPress is a derived, materialized view.

The system is declarative, atomic, incremental, and fail-fast. It never guesses intent, never partially updates WordPress, and never mutates state unless correctness is proven ahead of time.

This document is the authoritative agent-facing spec to be fed to Codex or other build agents.


Core Principles (Non-Negotiable)

  1. Git / Filesystem as Source of Truth WordPress content must exactly reflect declared Markdown sources and manifests.

  2. Declarative Configuration Only No implicit discovery, no heuristics, no inference.

  3. Atomic Execution A full dry-run validation must succeed before any WordPress mutation occurs.

  4. Incremental Updates Only content whose source timestamp is newer than its cached materialization timestamp may be updated.

  5. Fail Fast, Fail Loud Any configuration, validation, or conversion error aborts the entire run.


High-Level Architecture

The system operates in two strictly separated phases:

Phase 1: Pure Evaluation (Dry Run)

  • Read global config
  • Discover and load repositories / directories
  • Load and validate all .wp-materialize.json manifests
  • Resolve inheritance (categories, tags, subdirectories)
  • Convert Markdown → HTML (in-memory only)
  • Resolve titles, timestamps, taxonomy
  • Determine incremental update set
  • Detect all errors

If any error occurs, execution stops here.

Phase 2: Side-Effect Application

  • Create missing WordPress categories
  • Create or update WordPress posts
  • Update cached timestamps only for successfully applied posts

Global Configuration

Location:

.config/wp-materialize/config.json

Responsibilities:

  • WordPress root directory (where wp CLI is executed)
  • Repository storage directory
  • List of Git repositories to clone / pull
  • List of non-git directories to manage

Runtime State (Separate from Config)

Mutable runtime state must be stored separately, e.g.:

.config/wp-materialize/state.json

State includes:

  • Last successful materialization timestamp per post
  • Cached per-post source timestamps

Config must remain declarative and diffable.


Repository and Directory Rules

  • Each managed directory must contain a .wp-materialize.json manifest.
  • Any directory listed under subdirectories must contain its own manifest.
  • Missing manifests are hard errors.
  • No implicit recursion is allowed.

Per-Directory Manifest: .wp-materialize.json

Each manifest defines a scope boundary.

Top-Level Fields

categories

{
  "content": ["Systems", "Infrastructure"],
  "inherit": true
}
  • content: array of category paths
  • inherit: true → append to parent effective categories
  • inherit: false → override parent categories entirely

tags

{
  "content": ["automation", "wordpress"],
  "inherit": true
}

Semantics identical to categories.

subdirectories

{
  "content": ["design", "notes"],
  "inherit": true
}
  • Controls traversal explicitly
  • Included subdirectories must have their own manifest
  • inherit: false cuts traversal

File-Level Configuration

Each file listed under files represents a WordPress post.

"files": {
  "post.md": {
    "title": "Explicit Title",
    "categories": { "content": ["Overrides"], "inherit": false },
    "tags": { "content": ["extra"], "inherit": true }
  },

  "essay.md": {
    "use_heading_as_title": {
      "level": 1,
      "strict": true
    }
  }
}

Title Rules

  • If use_heading_as_title is specified:

    • Extract the specified heading level
    • Use it as the WordPress post title
    • Remove that heading from the body
    • Promote remaining headings by one level
    • If strict: true, exactly one matching heading must exist
  • Otherwise, title must be provided


Markdown → HTML Conversion

  • Conversion occurs only during dry run
  • No HTML is written or sent to WordPress during evaluation
  • Conversion errors are fatal

Category Materialization

  • Categories are treated as hierarchical paths

  • If a declared category path does not exist in WordPress:

    • It is automatically created during the apply phase
  • Category creation:

    • Must be planned during dry run
    • Must occur before post updates

Tags are not auto-created.


Timestamps and Incremental Updates

Timestamp Sources

  • Git repository:

    • Use Git commit timestamps
  • Non-git directory:

    • Use filesystem timestamps

The source of timestamps must be deterministic per repository.

Cached Metadata

  • Each post stores a cached source timestamp representing the last successful materialization
  • Failed runs must not update cached timestamps

Incremental Rule

On each run:

  • Compare current source timestamp vs cached timestamp
  • Only posts where source_timestamp > cached_timestamp are eligible for update
  • Unchanged posts are treated as no-ops

Post Identity

Each WordPress post must store stable metadata:

_wp_materialize_source = <repo_name>:<relative_path>

This identity is used for:

  • Idempotent updates
  • Safe renames
  • Incremental comparison

Atomicity Guarantee

  • If any dry-run validation fails:

    • No WordPress calls are executed
    • No categories are created
    • No cached timestamps are updated
  • Apply phase executes only after full validation succeeds


Error Handling

All errors are fatal:

  • Missing manifests
  • Invalid inheritance
  • Invalid Markdown
  • Missing or ambiguous titles
  • Invalid category/tag resolution
  • Timestamp resolution failures

No warnings. No partial success.


Implementation Notes

  • Language: Python

  • The implementation must prioritize:

    • Determinism
    • Readable error messages
    • Testable pure functions for evaluation phase

This document is the contract. Implementation must not relax or reinterpret it.