MyronCMS Developers Hub Docs sandbox review

Content Capabilities

MIC Resolvers

A MIC resolver is a small runtime bridge from a rich-text token to reusable HTML. Authors store a token in a rich-text field. MyronCMS later resolves that token through a registered resolver when rendering the field.

Use MIC resolvers for structured content that belongs outside a single paragraph but should be inserted inside rich text, such as tables, forms, catalog cards, course references, quiz embeds, or extension-owned reusable blocks.

Mental Model

The lifecycle has four parts:

  1. A developer authors a resolver class under app/extensions/{vendor}/.
  2. The extension returns that resolver from bootstrap.php under micElementTypes.
  3. The loader registers the local slug as x.{vendor}.{slug} through MicElementRegistry::registerExtension().
  4. Rich-text rendering replaces matching [mic-*] tokens with resolver output.

The resolver interface is intentionally small:

interface MicElementResolverInterface
{
    public function resolve(string $id, array $context): ?string;
    public function describe(): array;
}

describe() makes the type discoverable. resolve() turns one item id into HTML.

Token Shape

Core tokens use:

[mic-{slug}-mic_0123456789abcdef]

Extension tokens use:

[mic-x.{vendor}.{slug}-mic_0123456789abcdef]

The runtime token matcher accepts ids shaped like mic_[a-f0-9]{16}. Near-miss strings are left alone. A matching token with no resolver output renders a missing marker instead of silently disappearing.

Human Path

A developer creates an extension resolver, returns it from bootstrap.php, and has an operator register, enable, and grant the extension. A content author can then insert the resolver's token into a rich-text field through an allowed UI path.

The resolver decides how to read extension-owned content. Extension storage must still follow the extension storage rules, including {vendor}_* table boundaries when migrations are used.

AI Path

An AI coding agent can author the local resolver files, update bootstrap.php, and run verification in the repository.

An installed MCP client cannot create the PHP resolver, enable the extension, or grant scopes. After the extension is registered, enabled, loaded, and scope-covered, an AI client may discover registered MIC type descriptors through the content MIC type listing action exposed to MCP.

Runtime Context

During rich-text resolution, MyronCMS passes a context array with these current keys:

KeyMeaning
pageIdCurrent page id when the renderer knows it.
fieldKeyRich-text field key being rendered.
channelRendering channel, such as an admin preview or public render.
userScopesScope list available to the render context.

Treat context keys as additive. The public interface is tagged @apiVersion 1, and future context growth should not require a method signature change.

Scopes

The resolver descriptor includes scopes. Use the least scope needed by the content lookup. Common read-only resolvers use:

'scopes' => [MyronApiScopes::CONTENT_READ],

The descriptor scopes are discovery and safety metadata for content capability use. They do not give a resolver permission to bypass extension grants, loader checks, or caller scope checks on separate actions.

Artifacts

Authoring artifacts:

  • app/extensions/{vendor}/bootstrap.php
  • app/extensions/{vendor}/{ResolverName}.php
  • optional extension tables under {vendor}_*

Runtime artifacts:

  • MicElementResolverInterface
  • MicElementRegistry
  • rich-text field values containing [mic-*] tokens
  • /api/v1/content/mics/types
  • MCP tools/list for the loaded type-listing action when the caller has content.read

Safety Boundary

Rich-text input is sanitized before MIC token resolution. Resolver output is not the same thing as arbitrary rich-text input; it is pre-blessed HTML returned by trusted local extension code.

Do not use a resolver to inject scripts, forms with unsafe handling, core admin chrome, public render hooks, or cross-extension data access. A resolver should return deterministic, accessible HTML for the requested id or null when it cannot resolve safely.

Verification

Run the MIC registry and Content Banks checks:

php app/tests/verify-mic-registry.php
php app/tests/verify-content-banks-mic.php

For a loaded extension, verify that:

  • knownTypes() includes x.{vendor}.{slug},
  • /api/v1/content/mics/types returns the descriptor for a content.read caller,
  • a valid token renders the expected HTML,
  • an unknown id renders a missing marker,
  • a near-miss token remains unchanged.

Failure Modes

FailureWhat it meansSafe response
Resolver never appears in known typesExtension did not load, was not enabled, lacked grants, or did not return the resolver from micElementTypes.Fix extension load state and bootstrap shape.
Descriptor slug mismatchdescribe() does not return the registered fully qualified slug.Return x.{vendor}.{slug} from describe().
Token remains unchangedThe token does not match the runtime token shape.Use [mic-x.{vendor}.{slug}-mic_0123456789abcdef].
Missing marker rendersThe token matched, but the resolver returned null or an empty string.Check the id and resolver lookup path.
AI client cannot create a resolverExpected behavior for installed MCP clients.Use local-authoring in the repository, then register and grant the extension.