# AGENTS.md
<!-- Generated by APM CLI from distributed .apm/ primitives -->
<!-- Build ID: 3f44f43cfd01 -->

## Global Instructions

# Jahia JavaScript Module Development

## Context

You are helping develop a **Jahia JavaScript Module** — a React-based template set for Jahia 8+. The module renders content from Jahia's JCR (Java Content Repository) using server-side React components (`.server.tsx`) and optional client-side islands (`.client.tsx`). Content is modelled in CND files, managed via Page Builder or jContent, and queried with JCR-SQL2 or GraphQL.

## Agent Principles

1. **Always invoke a skill before any Jahia task** — skills are the canonical source of patterns, gotchas, and API syntax. Never operate from memory alone.
   1a. **Always load CND reference files before writing any CND** — Jahia-specific patterns (`choicelist[linkTypeInitializer]`, `mix:title`, child nodes for CTAs, `jmix:image` weakreferences) are not in your training data. Before writing any CND, read the reference files: `find "$(git rev-parse --show-toplevel 2>/dev/null || pwd)" -name 'cnd-jahia-mixins*' -not -path '*/node_modules/*' | head -3`. When working interactively through skill chains, prefer `@jahia-cnd-author` (it loads these files for you).
2. **Never use `yarn dev` from an agent** — it is an interactive file watcher for human developers only. Always deploy with `yarn build && yarn jahia-deploy` (one-shot, non-interactive).
   2a. **Use the TypeScript LSP for API discovery, never grep.** When you need to know a function's signature or what a module exports, call `mcp__ide__getDiagnostics` on the file after writing it — the LSP reads live type definitions and reports mismatches, wrong argument counts, and missing exports. Never run `grep` on `node_modules` to find a function name or signature.
3. **Never hardcode URLs** — all navigable links must come from contributed content (JCR nodes, `j:linkType`, `buildNodeUrl`). This is a CMS: content owns the URLs.
4. **Never use `j:linkType: "external"` for internal pages** — use `"internal"` + `j:linknode`. External URLs break on environment changes, language switches, and vanity URL rewrites.
5. **Always verify before creating** — check that content types are deployed, site keys are correct, and parent area nodes exist before creating content via MCP.
   5a. **Create content as subtrees, not node by node** — `content.create` takes `children`, nested up to five levels, and creates the whole graph atomically. One call creates a section with its list and every card inside it; one call per page area block is the ceiling. A run that creates each card in its own call spends a model turn per node: the benchmark measured 83 calls for four pages where 20 would do. Call `page.structure` once per page for the container paths, then batch.
   5b. **Add the images the content needs — never leave them out.** Upload each image with the MCP tool `media.upload.url` from a public HTTPS URL, such as `https://picsum.photos/seed/<word>/1600/900` (a different seed gives a different photo): it stores the file under `/sites/<siteKey>/files` and returns its path. Set the image property of the content (`weakreference, picker[type='image']`) to that path. When MCP tools load on demand, search for `media_upload_url`. To upload a local file instead, use `media.upload.create` then `media.upload.finalize`.
6. **All props are optional at runtime** — even mandatory CND fields. Always guard against `undefined` in views.
7. **Use MCP tools for all Jahia operations — never GraphQL curl.** The `jahia` MCP server covers site, page, content, media, and publication operations. Never fall back to `curl` + GraphQL mutations for anything the MCP server can do. Never write Python scripts — use JavaScript or bash only.
   7a. **`yarn` and `npx` must be run from the module root** — the module is a standalone project, not part of a monorepo. Running `yarn` from a parent directory fails with a workspace boundary error. Always `cd` to the module directory first.
   7b. **Use `grep`, not `ugrep`** — `ugrep` is not available on all systems and does not support the same regex syntax. Use `grep -rn` for plain text, `grep -rn -E` for extended regex, or `grep -rn -P` for Perl-compatible patterns (e.g. lookaheads). Never use `ugrep` or `(?m)` flags.
8. **Build accessible HTML from the start** — every view must use semantic HTML (`<main>`, `<header>`, `<nav>`, `<footer>`, `<section>`, `<article>`), include exactly one `<h1>` per page (in the template from `jcr:title` — never inside a component), use a strict heading hierarchy (h1 in template → h2 in components → h3 for sub-items), render every image node with `<JImage>` (when `docker/provisioning.yml` installs `javascript-modules-engine` 1.3 or later, see `jahia-dev-create-view` otherwise) and give every image an `alt` (an informative image takes the image node's `jcr:title`, which `<JImage>` uses by default, with a meaningful fallback such as the component title; a purely decorative image takes `alt=""`), ensure sufficient colour contrast (≥ 4.5:1 for body text), include a skip link at the top of the template, and never leave a landmark (`<nav>`, `<footer>`) empty.
9. **Review quality after each deploy** — after deploying and populating content, write the live page URLs to `pages-to-review.json` as a JSON array of URL strings, then invoke `/jahia-review` to run a full code and site review via subagents. Fix the blocking issues it reports (site violations and 🔴 Critical code issues) and iterate until the review passes; 🟡 Warnings and 🔵 Suggestions do not block. Once pages hold content, a review fix never renames or splits an area or moves content between areas. The review script writes `pages.json` on pass — never write it manually.
10. **Deploy iteratively** — deploy after each component with `yarn build && yarn jahia-deploy`, verify it renders, then move to the next. Don't accumulate components before deploying; a broken component is easier to diagnose in isolation.
    10a. **`{}` from `yarn jahia-deploy` means nothing was deployed.** When the output is `{}`, or the command fails with `Jahia installed nothing`, the previous version of the module is still running. During development the cause is usually a CND that Jahia cannot parse, such as `orderable` on a `+` child node line, because `yarn build` does not parse the CND. Invoke `/jahia-dev-debug` right away. Never work around a refused CND with the Groovy console, the JCR browser, uninstalls, or other provisioning endpoints.
11. **Collocate everything per component** — each component lives in `src/components/<Category>/<Name>/` containing its `definition.cnd`, `default.server.tsx`, `component.module.css`, and `types.ts`. Never centralize content types in `settings/definitions.cnd` — that file holds only namespace declarations and the module base mixin, and it is the only file that declares a namespace: a component `definition.cnd` never starts with a `<prefix = 'uri'>` line.
12. **Always build a page template first** — every website needs a root template at `src/templates/<ModuleName>Template/default.server.tsx`. It must include: a skip link, a `<nav>` built inline from children of the site's home node using `getChildNodes(renderContext.getSite().getNode('home'), -1, 0, n => n.isNodeType('jnt:page'))` (pages live under `home`, not directly under the site), a `<main id="main-content">` with `<h1>{title}</h1>` and Areas, and a `<footer>` that is never empty. The `<title>` tag must read `{title} | {siteName}`, built as a single string (`<title>{[title, siteName].filter(Boolean).join(" | ")}</title>`): React renders a `<title>` with several children as an empty `<title></title>`. Never set `jcr:title` to the full `Page | Site` string; `jcr:title` is always just the short page name (e.g. "Car Insurance"). Build and deploy before any page-specific components.
13. **SEO baseline** — every page template must render a `<title>` tag, all `<img>` must have descriptive `alt` text, all links must have visible text (no icon-only links without `aria-label`), and pages must have a single `<h1>` matching the page title.
14. **Capture work you repeat** — when you do the same multi-step task a second time in a session (same commands, same lookups, same fix) and no installed skill covers it, propose capturing it: give the name, one line on what it does, and whether it is a skill (a procedure) or an instruction (a standing rule). Write it only after the user agrees, with `/jahia-capture`.

## Canonical References

Always fetch these when uncertain about version-sensitive topics:

| Topic                                                   | URL                                                                                                                                         |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| Getting started / dev environment                       | https://academy.jahia.com/tutorials-get-started/front-end-developer/setting-up-your-dev-environment                                         |
| Hero section tutorial                                   | https://academy.jahia.com/tutorials-get-started/front-end-developer/making-a-hero-section                                                   |
| Blog / content listing                                  | https://academy.jahia.com/tutorials-get-started/front-end-developer/making-a-blog                                                           |
| Page templates                                          | https://academy.jahia.com/tutorials-get-started/front-end-developer/the-about-us-page                                                       |
| i18n (CND attribute, useTranslation, language switcher) | https://academy.jahia.com/documentation/jahia-cms/jahia-8-2/developer/javascript-module-development/preparing-for-internationalization-i18n |
| GraphQL API                                             | https://academy.jahia.com/documentation/developer/jahia/8/api-documentation/graphql-api                                                     |
| Native Jahia mixins & node types                        | https://github.com/Jahia/jahia/tree/master/war/src/main/webapp/WEB-INF/etc/repository/nodetypes                                             |
| JavaScript modules monorepo                             | https://github.com/Jahia/javascript-modules                                                                                                 |
| Developer training                                      | https://github.com/Jahia/developer-training/blob/main/js-training/slides.md                                                                 |
| Integration best practices                              | https://github.com/Jahia/gautier-braindump/blob/main/articles/integration-best-practices/README.md                                          |

## Local Development URLs

When Jahia is running at `http://localhost:8080` (default credentials: `root` / `root1234`):

- **Login**: http://localhost:8080/cms/login
- **GraphQL playground**: http://localhost:8080/modules/graphql-dxm-provider/tools/graphql-workspace.jsp
- **JCR browser**: http://localhost:8080/modules/tools/jcrBrowser.jsp
- **Definitions browser**: http://localhost:8080/modules/tools/definitionsBrowser.jsp
