Concepts

Contracts

The rules every write is checked against, the verdict they return, and how to write your own.

Contracts

A contract is a rule about an entry. Hollware runs the contracts of a collection on every write, and again when it publishes, and returns a verdict.

The verdict

{
  "ok": false,
  "phase": "write",
  "errors": [
    {
      "contract": "schema",
      "severity": "error",
      "path": "/frontmatter/description",
      "message": "Too big: expected string to have <=160 characters",
      "fix": "Shorten the description to 160 characters or fewer."
    }
  ],
  "warnings": []
}

Every violation has a path (a JSON Pointer into the entry), a message and a fix: an agent can act on it without reading your code.

Writes never fail on a contract

A draft that breaks a contract is saved, with the verdict. Work in progress is never lost, and the agent fixes it with update_draft. What a contract stops is publishing:

  • an error blocks publish, which answers blocked;
  • a warning asks for acknowledgement: publish answers needs_acknowledgement with the warnings, and publishes once they are sent back in acknowledgeWarnings.

validate runs the contracts on Markdown without saving anything.

Built in

These always run: the schema of the frontmatter, the components and their props, content safety (no raw HTML that runs script), and the size limit of an entry. Hollware ships more that a collection turns on:

ContractChecks
contracts.translationPair()the entry exists in every locale of its translation group
contracts.internalLinksResolve()links to other entries point at published ones, when publishing
contracts.imagesHaveAlt()every image has alternative text

Each takes { severity: 'warning' } to warn instead of block.

Your own

A contract is an object with an id, a severity, a description and a check, which returns the violations of an entry:

{
  id: 'seo-title-length',
  severity: 'warning',
  description: 'A title of at most 60 characters, which search engines show.',
  check: ({ frontmatter }) =>
    frontmatter.title.length <= 60
      ? []
      : [{
          path: '/frontmatter/title',
          message: `The title has ${frontmatter.title.length} characters; search engines show about 60.`,
          fix: 'Shorten the title to 60 characters or fewer.',
        }],
}

Write the fix for the agent that will read it: say what to do, not what went wrong.