php artisan boost:add-skill contentful/rich-text
Save this content to: AGENTS.md
---
package: contentful/rich-text
source_path: AGENTS.md
repo: https://github.com/contentful/rich-text.php
---
# Agent Guide
<!-- Generated by seed-golden-context | Last updated: 2026-05-11 -->
Read this file first. It tells you where to find context in this repo.
## Quick Reference
| What you need | Where to look |
|---|---|
| How this repo is structured | [ARCHITECTURE.md](./ARCHITECTURE.md) |
| How to build/test/run | [CONTRIBUTING.md](./CONTRIBUTING.md) |
| Why decisions were made | [docs/ADRs/](./docs/ADRs/) |
| What this repo does | [README.md](./README.md) |
| PR review rules | [.bito/guidelines/](./.bito/guidelines/) |
| Active specs/work | [docs/specs/](./docs/specs/) |
## Sharp Edges & Invariants
- **`parse()` and `parseCollection()` are deprecated.** Always use `parseLocalized($data, $locale)` and `parseCollectionLocalized($data, $locale)`. Using the un-localized variants will silently resolve embedded assets in the default locale, causing bugs in multi-locale content (see [#65](https://github.com/contentful/rich-text.php/issues/65) and [ADR-003](./docs/ADRs/003-locale-aware-parsing.md)).
- **Never push `CatchAll` with `pushNodeRenderer()`.** It must be appended with `appendNodeRenderer()`. Pushing it prepends it to the stack, making it highest-priority and silently suppressing all other renderers.
- **`EmbeddedImage` renderer is opt-in.** It is disabled by default because enabling it changes output for existing `EmbeddedAssetBlock` nodes (a behavior change). Call `$renderer->enableEmbeddedImageRenderer(true)` explicitly.
- **Public interfaces are part of the API contract.** `ParserInterface`, `RendererInterface`, `NodeInterface`, `NodeMapperInterface`, and `NodeRendererInterface` are the public API surface. Changes to method signatures require a major version bump and BC check sign-off.
- **`AssetInterface` does not expose `getFile()` or `getTitle()`.** The `EmbeddedImage` renderer uses `method_exists()` checks at runtime because adding these to the interface would be a BC break. Do not add these methods to `AssetInterface` without a major version.
- **Node type strings must match the Contentful Rich Text schema exactly.** Each `Node` class has a static `getType()` method returning the Contentful API node type string (e.g., `"paragraph"`, `"embedded-asset-block"`). These strings are the keys in the `Parser` mapper map and must not be changed.
- **This is a publish-and-forget library.** There is no deployment, no environment config, no secrets. All runtime behavior is determined by constructor arguments supplied by the consuming application.
- **PHPStan runs at level 5.** Static analysis must pass at that level. Adding `@phpstan-ignore-line` is acceptable for documented edge cases (e.g., dynamic method checks in `EmbeddedImage`), but requires a comment explaining why.
- **BC breaks are checked automatically on CI** (`roave/backward-compatibility-check`). The check is currently non-blocking (`|| true`), but BC breaks should be intentional and documented with a CHANGELOG entry and major version bump.
## Key Conventions
- **Commit format:** Conventional Commits-style prefixes (`feat`, `fix`, `chore`, `docs`, etc.) — not enforced by a hook but expected.
- **Branch strategy:** `master` is the release branch; feature branches use `feat/`, `fix/`, `chore/`, `docs/` prefixes; PR targets are always `master`.
- **Test location:** `tests/Unit/` mirrors `src/`; `tests/Integration/` covers end-to-end rendering flows; `tests/Fixtures/` holds JSON fixture data.
- **PHP version support:** PHP 8.0–8.4 are all actively tested in CI. Do not introduce syntax or features that break any supported version.
- **No build step:** This is a pure PHP library. There is no compile step, no asset pipeline, no transpilation.
## Integration Points
**Upstream (this repo consumes):**
- `contentful/core` ^3.0|^4.0 — `LinkResolverInterface` for resolving embedded entries/assets; `AssetInterface` and `ImageFile` for the EmbeddedImage renderer.
- Contentful Rich Text JSON schema — input format; must stay in sync as the platform adds node types.
**Downstream (consumes this repo):**
- `contentful/contentful.php` — primary consumer via Composer.
- PHP applications consuming the Contentful CDA — direct Packagist installs.
## Build & Quality
```bash
# Install dependencies
composer install
# Full verification loop
composer test && composer lint-static-analysis && composer test-for-bc-breaks
```
Read this file first. It tells you where to find context in this repo.
| What you need | Where to look |
|---|---|
| How this repo is structured | ARCHITECTURE.md |
| How to build/test/run | CONTRIBUTING.md |
| Why decisions were made | docs/ADRs/ |
| What this repo does | README.md |
| PR review rules | .bito/guidelines/ |
| Active specs/work | docs/specs/ |
parse() and parseCollection() are deprecated. Always use parseLocalized($data, $locale) and parseCollectionLocalized($data, $locale). Using the un-localized variants will silently resolve embedded assets in the default locale, causing bugs in multi-locale content (see #65 and ADR-003).CatchAll with pushNodeRenderer(). It must be appended with appendNodeRenderer(). Pushing it prepends it to the stack, making it highest-priority and silently suppressing all other renderers.EmbeddedImage renderer is opt-in. It is disabled by default because enabling it changes output for existing EmbeddedAssetBlock nodes (a behavior change). Call $renderer->enableEmbeddedImageRenderer(true) explicitly.ParserInterface, RendererInterface, NodeInterface, NodeMapperInterface, and NodeRendererInterface are the public API surface. Changes to method signatures require a major version bump and BC check sign-off.AssetInterface does not expose getFile() or getTitle(). The EmbeddedImage renderer uses method_exists() checks at runtime because adding these to the interface would be a BC break. Do not add these methods to AssetInterface without a major version.Node class has a static getType() method returning the Contentful API node type string (e.g., "paragraph", "embedded-asset-block"). These strings are the keys in the Parser mapper map and must not be changed.@phpstan-ignore-line is acceptable for documented edge cases (e.g., dynamic method checks in EmbeddedImage), but requires a comment explaining why.roave/backward-compatibility-check). The check is currently non-blocking (|| true), but BC breaks should be intentional and documented with a CHANGELOG entry and major version bump.feat, fix, chore, docs, etc.) — not enforced by a hook but expected.master is the release branch; feature branches use feat/, fix/, chore/, docs/ prefixes; PR targets are always master.tests/Unit/ mirrors src/; tests/Integration/ covers end-to-end rendering flows; tests/Fixtures/ holds JSON fixture data.Upstream (this repo consumes):
contentful/core ^3.0|^4.0 — LinkResolverInterface for resolving embedded entries/assets; AssetInterface and ImageFile for the EmbeddedImage renderer.Downstream (consumes this repo):
contentful/contentful.php — primary consumer via Composer.# Install dependencies
composer install
# Full verification loop
composer test && composer lint-static-analysis && composer test-for-bc-breaks
How can I help you explore Laravel packages today?