Rendering Phases And Agent Kit For Agentic Generation

Rendering Phases and Agent Kit for Agentic Generation

Written for AI agents. See Log Methodology Note below for details.

Date: February 6, 2026
Status: Draft
Related: Design Logs #34, #50 (phases & headless), #80, #84, #76

Background

Jay Stack agentic generation relies on several existing pieces:

  1. Rendering phases (Design Logs #34, #50): Slow (build-time), fast (request-time), interactive (client). Contracts declare phase per tag; agents need to know which data is available when.
  2. Contract discovery and materialization (Design Log #80): We use a single command jay-stack agent-kit (renamed from contracts) that prepares the full agent kit: materializes dynamic contracts, writes contracts-index and plugins-index, and outputs to agent-kit/ only (no separate build/materialized-contracts/). Agents read from agent-kit to understand data shapes and bindings.
  3. Actions and params discovery via CLI (Design Log #84): jay-stack action <plugin>/<action>, jay-stack params <plugin>/<contract> (load params), and plugin .action.yaml files let agents discover valid prop/param values.

Today an agent must:

  • Know to run jay-stack agent-kit and read materialized contracts from agent-kit
  • Know to run jay-stack params / jay-stack action for discovery
  • Know jay-html syntax, headless script tags, jay: instances, phase semantics
  • Have instructions and context scattered (README, plugin docs, etc.)

Problem

We need a single, coherent folder that a coding agent can use to create jay-html files: instructions, contracts index, plugins index, and minimal content (which components and how to use them). Content is input for the agent to generate pages — agent-only, no CLI transform. Metadata (contract shape, phases) lives in the kit; content does not repeat it.

Questions and Answers

Q1: Where should the agent kit live?

Options:

A) src/.agent-kit/ — next to source, dot-prefix for “tooling”
B) agent-kit/ at project root — visible, not mixed with app source
C) build/agent-kit/ — generated; populated by CLI from contracts + plugin manifests

Answer: Option B — agent-kit/ at project root.

Rationale: Visible to agents and humans; not inside src/ so it doesn’t blur app vs instructions. Materialized contracts, contracts index, and plugins index live in agent-kit (single place; no build copy). Can be committed (instructions + content) or partially generated (contracts, plugins index, actions/params refs).

Q2b: Should we materialize plugin.yaml files?

Options:

A) Index onlyplugins-index.yaml lists plugin name + path to each plugin (e.g. node_modules/@wix/stores). Agent reads plugin.yaml from that path when needed.
B) Materialize — Copy each plugin’s plugin.yaml into agent-kit/plugins/<name>.yaml so the kit is self-contained; agent never touches node_modules.
C) Index + optional materialize — Index always; --materialize-plugins or similar copies plugin.yaml into agent-kit for offline/read-only use.

Answer: Option A for v1 (index only). Option B or C if we need a fully self-contained kit (e.g. agent has no filesystem access to node_modules).

Rationale: Index is enough for discovery; contract metadata is already in materialized-contracts. Materializing plugin.yaml duplicates data and must be kept in sync. Prefer index-only unless the agent cannot read plugin paths.

Q2: What belongs in the agent kit?

Proposed contents:

Item Purpose
README.md or INSTRUCTIONS.md How to generate jay-html: phases, headless usage, CLI commands, file layout
plugin.yaml (or symlink/copy) Optional: project-level plugin manifest or pointer to plugins in use
Contracts (materialized) agent-kit/materialized-contracts/ + contracts-index.yaml; jay-stack agent-kit writes here (no build copy). Agents discover contracts from here.
Plugins index Generated by jay-stack agent-kit; lists plugins (name, path, contracts). Single discovery point for which plugins/contracts exist.
Actions / params reference Optional: output of jay-stack params …, jay-stack action …, or curated list in references/
Content as Markdown Minimal: which components (plugin/contract) and how to use them. All other metadata (contract shape, phases) lives in the kit; do not repeat here.

Q3: How do we indicate headless components (including nested) with their properties?

We need to support nested components with specific props, e.g. “3 product cards with specific product IDs” — not only “one list key + forEach”. The content format must express:

  • Which components (plugin + contract) to use.
  • How to use them: page-level (key), or nested with static props (e.g. three product cards: productId: id1, id2, id3), or dynamic (forEach + trackBy + props from context).

Options:

A) Frontmatter (page-level) + minimal spec for nested — e.g. frontmatter: headless: [{ plugin, contract, key }]. Nested: list of { plugin, contract, props?: { productId: "id1" } | { forEach, trackBy, props } } so we can say “3 product cards, productId = x, y, z” or “product cards from list”.
B) Single minimal spec file per page — One YAML with page: { headless: [...] } and nested: [{ contract (or plugin/contract), props | forEach/trackBy/props }]. No duplication of contract metadata; just component ref + usage.
C) Block directives in markdown — e.g. ::: wix-stores/product-card productId="id1" for each instance; or one directive with forEach and props.

Answer: Minimal information only: component ref (plugin/contract) + how to use (key for page-level; for nested: either fixed props per instance or forEach + trackBy + props). All metadata (contract shape, phases, valid prop names) lives in the kit (contracts, plugins index); content does not repeat it. Prefer a single minimal spec (frontmatter for page-level, small YAML or inline for nested) so the agent has one clear place to read “what components + how”.

Rationale: Nested with specific IDs (e.g. 3 product cards) is a core case; the format must support both “list from data” (forEach) and “fixed set of instances with props”. Keeping content minimal avoids drift from contract metadata and keeps the kit as the single source of truth.

Q4: Who transforms content → jay-html?

Answer: Agent only. The content (markdown + minimal spec) is input to help the agent generate the pages. The agent reads the kit (instructions, contracts index, plugins index, materialized contracts) and the minimal content (which components, how to use them), then produces jay-html. No CLI transform step: content is not “compiled” into jay-html by the stack; it is guidance for the agent.

Q5: Should we specify params in the contract (like props) and generate the Params interface?

Background: Components that use URL/load params (e.g. product page with [slug]) today declare the params type manually, e.g. in product-page.ts:

export interface ProductPageParams extends UrlParams {
  slug: string;
}

The contract file (product-page.jay-contract) currently has only tags (ViewState); it has no declaration of params. Design Log #84 describes load params discovery via jay-stack params <plugin>/<contract> and withLoadParams.

Proposal: Specify params in the contract (similar to props), and generate the Params interface from the contract so the contract is the single source of truth. Example:

Contract (e.g. product-page.jay-contract):

name: product-page
params:
  slug: string # type is ignored; URL params are always string (UrlParams = Record<string, string>)
tags:
  - { tag: _id, type: data, dataType: string }
  # ...

Generated (e.g. from contract compiler): Params are always string in the generated type.

export interface ProductPageParams extends UrlParams {
  slug: string;
}

Answer: Yes. Add params to the contract format and generate ProductPageParams extends UrlParams { ... } in the same place we generate ViewState/Refs (contract compiler). The agent kit then exposes contracts that include params, so the agent knows which URL/load params a page expects. This is an addition to Phase 1 (contract format + codegen; agent kit materialization already emits contracts, so once contracts include params, the kit automatically exposes them).

Rationale: Single source of truth; component code (e.g. product-page.ts) can use the generated ProductPageParams instead of defining it manually; agents see params in the materialized contract. Reference: wix/packages/wix-stores/lib/contracts/product-page.jay-contract and wix/packages/wix-stores/lib/components/product-page.ts.

Design

Agent kit folder layout

agent-kit/
├── INSTRUCTIONS.md              # How to generate jay-html (phases, headless, CLI, layout)
├── materialized-contracts/      # Output of jay-stack agent-kit (no build copy)
│   ├── contracts-index.yaml    # Index of all contracts (static refs + dynamic materialized)
│   ├── plugins-index.yaml       # Index of plugins (generated with contracts command)
│   └── <plugin>/                # Per-plugin materialized dynamic contracts
│       └── *.jay-contract
├── plugins/                     # Optional: materialized plugin.yaml copies (if Q2b = materialize)
│   └── wix-stores.yaml
├── content/                     # Minimal: which components + how to use them (agent input)
│   ├── blog/
│   │   ├── index.md
│   │   └── [slug].md
│   └── shop/
│       └── index.md
└── references/                  # Optional: jay-stack params/action outputs
    └── wix-stores-params.json
  • INSTRUCTIONS.md: Summarize rendering phases (slow/fast/interactive), contract tags and phases, headless import + jay: instances, key and props, forEach/trackBy. List CLI: jay-stack agent-kit (writes to agent-kit/materialized-contracts/ and generates plugins index), jay-stack params <plugin>/<contract>, jay-stack action <plugin>/<action>. Describe src/pages layout and that page dir can have page.jay-html, page.jay-contract, page.conf.yaml (Design Log #50).
  • materialized-contracts/: Single place for materialized contracts and plugins-index.yaml; jay-stack agent-kit writes here (default or --output agent-kit/materialized-contracts). No copy in build/. Agents read contracts-index, plugins-index, and contract files from here.
  • content/: Minimal only. Which components (plugin/contract) and how to use them (key; or nested with props / forEach+trackBy+props). All other metadata is in the kit — do not repeat contract shape, phases, etc. here. Content is input for the agent to generate jay-html.

Content format (minimal)

Principle: Specify only which components (plugin/contract) and how to use them. Contract shapes, phases, and valid prop names come from the kit (contracts-index, materialized contracts, plugins index).

Page-level: YAML frontmatter with route and headless: [{ plugin, contract, key }].

Nested / instances with props: e.g. 3 product cards with specific product IDs — specify component (plugin/contract) and either:

  • Fixed instances: list of props per instance, e.g. [{ contract: product-card, props: { productId: "id1" } }, { productId: "id2" }, { productId: "id3" }], or
  • From list: forEach + trackBy + props (e.g. productId: "{_id}").

Example (minimal frontmatter + nested):

# content/shop/featured.md — minimal
---
route: /shop/featured
headless:
  - plugin: wix-stores
    contract: product-card
nested:
  - plugin: wix-stores
    contract: product-card
    instances:
      - { productId: 'prod-1' }
      - { productId: 'prod-2' }
      - { productId: 'prod-3' }
---
# Optional: prose for context; agent uses components above to generate jay-html.

Alternative for “cards from list”: nested: [{ plugin, contract, forEach: "products.items", trackBy: "_id", props: { productId: "{_id}" } }]. INSTRUCTIONS.md explains the format; the agent reads the kit for contract details and emits jay-html.

Rendering phases in the kit

INSTRUCTIONS.md should state:

  • Slow: Build-time; use for static data, SSG params (from jay-stack params).
  • Fast: Request-time; use for per-request data.
  • Interactive: Client; use for mutable UI state.

Contracts in agent-kit/materialized-contracts/ use phase: slow | fast | fast+interactive (Design Log #50). The agent should bind only tags that exist on the contract and be aware that phase affects when data is available (e.g. no interactive-only tags during slow render).

Discovery flow for the agent

  1. Read agent-kit/INSTRUCTIONS.md.
  2. Ensure contracts and plugins index exist: run jay-stack agent-kit (writes to agent-kit/materialized-contracts/: contracts-index.yaml, plugins-index.yaml, materialized contract files). Read contracts-index and plugins-index from there.
  3. For load params (e.g. SSG routes): run jay-stack params <plugin>/<contract>; use output when generating pages with dynamic routes.
  4. For prop values (e.g. product IDs): run jay-stack action <plugin>/<action> or read plugin action docs in the kit.
  5. For each page: read agent-kit/content/... (minimal: which components + how to use them). Use kit metadata (contracts, phases) to generate src/pages/.../page.jay-html (and optional page.jay-contract, page.conf.yaml per #50).

Implementation Plan

Phase 1: Agent kit structure, contract format (params), and instructions

  1. Define agent-kit/ layout and document it (e.g. in design log or README).
  2. Add INSTRUCTIONS.md template: rendering phases, headless usage, CLI commands, src/pages layout, reference to #50 (page.conf.yaml when jay-html is missing).
  3. Contract materialization: jay-stack agent-kit writes to agent-kit/materialized-contracts/ by default (no build copy) and generates plugins-index.yaml in the same folder. Design Log #80 implementation is extended so output directory defaults to or can be set to agent-kit/materialized-contracts/, and the command also emits a plugins index (plugin name, path, list of contracts).
  4. Params in the contract: Extend the contract format to include params (URL/load params), similar to props. Generate export interface <ComponentName>Params extends UrlParams { ... } from the contract (e.g. ProductPageParams extends UrlParams { slug: string }). Contract compiler emits this in the same generated output as ViewState/Refs. Materialized contracts in the agent kit then include params, so the agent knows which URL params a page expects. Reference: wix-stores product-page.jay-contract and product-page.ts.

Phase 2: Content format (minimal)

  1. Specify minimal content format: which components (plugin/contract) and how to use them (key; nested: fixed instances with props or forEach+trackBy+props). No repetition of contract metadata.
  2. Document in INSTRUCTIONS.md: page-level (route + headless list), nested (instances with props or from list).
  3. Add example agent-kit/content/ with one page-level and one nested example (e.g. 3 product cards with specific IDs).

Phase 3: Optional tooling

  1. Default output: jay-stack agent-kit defaults to agent-kit/materialized-contracts/ (or --output agent-kit/materialized-contracts), writes contracts-index and plugins-index. No separate build copy.
  2. Materialize plugin.yaml (optional): If Q2b option B/C is adopted, add flag or separate step to copy plugin.yaml files into agent-kit/plugins/.

Examples

Example 1: Agent kit INSTRUCTIONS.md (excerpt)

# Generating Jay-HTML Pages

## Rendering phases

- **Slow**: Build-time (SSG). Data and route params from loadParams.
- **Fast**: Per-request (SSR). Data from fast render.
- **Interactive**: Client. Mutable state.

Contracts list phase per tag. Only use tags in the phase where they are available.

## Headless components

1. Page-level: add `<script type="application/jay-headless" plugin="..." contract="..." key="...">` in head.
2. Nested / multiple instances: use `<jay:contract-name>` with props and optional inline template.
3. Discover contracts and plugins: read contracts-index.yaml and plugins-index.yaml (run `jay-stack agent-kit` first).
4. Discover params: `jay-stack params <plugin>/<contract>`.
5. Discover prop values: `jay-stack action <plugin>/<action>` or plugin actions in references/.

## Page layout

- One directory per route under src/pages/.
- Each page dir: page.jay-html (required for view), optional page.jay-contract, optional page.conf.yaml (used when jay-html is missing; see Design Log #50).

Example 2: Minimal content — page-level

---
route: /blog
headless:
  - plugin: my-cms
    contract: cms/blog-posts-list
    key: blog
---

Agent uses kit (contract shape, phases) to produce src/pages/blog/page.jay-html; no metadata repeated in content.

Example 3: Minimal content — nested with specific props (3 product cards)

---
route: /shop/featured
headless:
  - plugin: wix-stores
    contract: product-card
nested:
  - plugin: wix-stores
    contract: product-card
    instances:
      - { productId: 'prod-1' }
      - { productId: 'prod-2' }
      - { productId: 'prod-3' }
---

Agent produces page with one headless script (product-card) and three <jay:product-card productId="..."> instances. Contract details (props, phases) come from the kit.

Trade-offs

Approach Pros Cons
Agent kit at project root Single place for agent; clear separation from src One more top-level folder
Frontmatter + spec for headless Page-level simple; nested explicit in spec Two places to look (md + spec)
Block directives in markdown Single file Parsing and escaping in markdown
Agent-only transform (v1) No new CLI; flexible Consistency depends on instructions
Optional CLI later Reproducible builds from content More to build and maintain

Verification criteria

  1. An agent with access only to agent-kit/ and the repo can, after running jay-stack agent-kit (output in agent-kit/materialized-contracts/, including plugins-index), produce valid jay-html for a given route using the right headless components and bindings.
  2. Instructions clearly describe rendering phases and how they relate to contract tags.
  3. Content is minimal: component refs (plugin/contract) + how to use (key; nested instances or forEach). No repeated contract metadata.
  4. Agent-only: Content is input for the agent to generate jay-html; no CLI transform step.
  5. Discovery path (contracts-index, plugins-index, params/actions via CLI) is documented and usable as in #80 and #84.

Summary

  • Rendering phases (#34, #50): Document in the agent kit so agents know slow/fast/interactive and contract phase tags.
  • Contract materialization (#80): Materialized contracts and plugins index live in agent-kit only: agent-kit/materialized-contracts/ (no build copy). jay-stack agent-kit writes contracts-index, plugins-index, and materialized contract files here.
  • Plugin.yaml materialization (Q2b): Index-only by default; optionally materialize plugin.yaml into agent-kit/plugins/ for self-contained kit.
  • Nested components with props (Q3): Content format supports page-level (key) and nested — fixed instances with props (e.g. 3 product cards with specific productIds) or forEach+trackBy+props. Minimal: component ref + usage only; metadata in kit.
  • Agent-only (Q4): Content is input to help the agent generate pages; no CLI transform step.
  • Content format: Minimal — which components (plugin/contract) and how to use them. No repetition of contract shape, phases, or other metadata (all in kit).
  • Params in the contract (Q5, Phase 1): Specify params in the contract (like props), e.g. params: { slug: string } in .jay-contract; generate export interface ProductPageParams extends UrlParams { slug: string } from the contract. Agent kit then exposes params in materialized contracts; component code (e.g. product-page.ts) uses the generated type. Reference: wix-stores product-page.jay-contract and product-page.ts.
  • Agent kit folder: agent-kit/ with INSTRUCTIONS.md, materialized-contracts (contracts-index, plugins-index, contract files including params), optional plugin refs, and content/ as minimal spec so a coding agent can create jay-html consistently.

Implementation Results

Phase 1 (partial): Agent kit command and plugins index

Done:

  1. Plugins indexcontract-materializer.ts now writes plugins-index.yaml alongside contracts-index.yaml. Format: { materialized_at, jay_stack_version, plugins: [{ name, path, contracts: [{ name, type, path }] }] }. Path is relative to project root.
  2. jay-stack agent-kit command — New CLI command; default output is agent-kit/materialized-contracts. Same options as contracts (--output, --list, --yaml, --plugin, --dynamic-only, --force, --verbose). contracts command kept for backward compat (default build/materialized-contracts).
  3. Path fix — Default output is passed as relative path (agent-kit/materialized-contracts or build/materialized-contracts); CLI joins with projectRoot so path is correct.

Files changed:

  • stack-server-runtime/lib/contract-materializer.ts: Added PluginsIndexEntry, PluginsIndex; during materialization collect per-plugin (path + contracts) and write plugins-index.yaml.
  • stack-cli/lib/cli.ts: Extracted runMaterialize(projectRoot, options, defaultOutputRelative); added agent-kit command (default agent-kit/materialized-contracts); contracts command uses runMaterialize with default build/materialized-contracts.

Params in the contract (Q5) — implemented:

  • Params are always string: URL/load params are always strings (UrlParams = Record<string, string>). Contract format accepts params: { slug: string } (type values ignored); generated interface always uses string for each param.
  • Contract format: Optional params as object of param name → type (e.g. params: { slug: string }). Parsed into ContractParam[] with name only (no dataType).
  • Types: ContractParam { name: string } and Contract.params?: ContractParam[] in contract.ts.
  • Parser: contract-parser.ts parses params from YAML (object form); uses keys only (no type validation).
  • Codegen: contract-compiler.ts generates import { UrlParams } from '@jay-framework/fullstack-component'; and export interface <Name>Params extends UrlParams { <prop>: string; ... } when contract has params.
  • Tests: Parser tests for params (single, multiple, absent); compiler tests use expect(await prettify(result.val)).toBe(await prettify(...)) with full expected output (no toContain).

INSTRUCTIONS.md template (Phase 1):

  • When jay-stack agent-kit runs (and not with --list), after materializing contracts we call ensureAgentKitInstructions(projectRoot).
  • If agent-kit/INSTRUCTIONS.md does not exist, we create agent-kit/ and write a default INSTRUCTIONS.md (Design Log #85 Example 1): rendering phases, headless components, discovery (contracts-index, plugins-index, params, actions), page layout. We do not overwrite an existing INSTRUCTIONS.md.
  • stack-cli/lib/cli.ts: Added AGENT_KIT_INSTRUCTIONS_TEMPLATE constant and ensureAgentKitInstructions(projectRoot); agent-kit command action calls it after runMaterialize when !options.list.

Verification: jay-stack agent-kit creates agent-kit/materialized-contracts/contracts-index.yaml and plugins-index.yaml. With zero plugins, both files have empty arrays. Rebuild stack-server-runtime after changing contract-materializer so CLI picks up the new code.

Phase 1 (continued): Cursor skills (IDE-specific)

Created Cursor skills in .cursor/skills/ for IDE-native discovery. These mirror the agent-kit docs but are auto-discovered by the Cursor IDE agent.

Skills: jay-agent-kit, jay-html-authoring, jay-cli-commands, jay-contracts-and-plugins, jay-dev-server-test (pre-existing).

Phase 1 (continued): Agent kit as generated docs folder

Done:

The jay-stack agent-kit command now generates a self-contained agent-kit/ folder with comprehensive documentation that any AI agent can use to build a jay-stack website.

Generated files:

agent-kit/
├── INSTRUCTIONS.md              # Main entry point: overview, workflow, references
├── jay-html-syntax.md           # Jay-HTML template syntax + headless patterns
├── routing.md                   # Directory-based routing
├── contracts-and-plugins.md     # Reading contracts, plugin.yaml, indexes
├── cli-commands.md              # CLI commands: validate, params, action, dev
├── materialized-contracts/      # Generated contracts + indexes
│   ├── contracts-index.yaml
│   ├── plugins-index.yaml
│   └── <plugin>/...

Implementation:

  • stack-cli/agent-kit-template/ — Folder with actual .md files shipped with the package. Contains: INSTRUCTIONS.md, jay-html-syntax.md, routing.md, contracts-and-plugins.md, cli-commands.md.
  • stack-cli/lib/cli.tsensureAgentKitDocs(projectRoot, force?) resolves the template folder via import.meta.url (../agent-kit-template/ relative to dist/index.js or lib/ in dev), reads all .md files, and copies them to agent-kit/. Skips existing files unless --force.
  • stack-cli/package.json — Added agent-kit-template to files array for publishing.
  • Deleted the old agent-kit-templates.ts string constants approach — real files are simpler to edit and review.

Documentation coverage:

  1. INSTRUCTIONS.md — What jay-stack is, rendering phases table, full workflow (discover → read contracts → create pages → validate → test), quick start example, links to all reference docs.
  2. jay-html-syntax.md — File structure, data binding {expr}, conditionals if, loops forEach/trackBy, refs, headless patterns (key-based + instance-based with jay: prefix), page-level contracts, styling, complete example.
  3. routing.mdsrc/pages/ structure, static/dynamic routes ([param], [[param]], [...param]), route priority, page files (page.jay-html, page.jay-contract, page.conf.yaml), load params.
  4. contracts-and-plugins.md — plugins-index.yaml format, contracts-index.yaml format, plugin.yaml structure, .jay-contract format (tag types, phases, props, params, linked sub-contracts), step-by-step contract-to-jay-html mapping table.
  5. cli-commands.mdjay-stack agent-kit, validate, params, action, dev with examples and output formats.

Type-check: tsc --noEmit passes.

Update: .jay-action metadata in agent-kit (see Design Log #92)

The agent-kit docs and materialized indexes now include .jay-action metadata. plugins-index.yaml lists actions with { name, description, path } — matching the contract pattern where the index is a lightweight discovery layer and the .jay-action file at the path has full input/output schemas. Documentation templates updated: INSTRUCTIONS.md, contracts-and-plugins.md, cli-commands.md.


Log Methodology Note

Note: These design logs are written primarily for AI agents as part of the Design Log methodology and made accessible here for human readers. The language and structure are optimized for machine consumption — expect precise, specification-style prose rather than narrative documentation.