Org Skills

aem-edge-delivery-services

Build and review sites on AEM Edge Delivery Services (aem.live, formerly Franklin/Helix) — boilerplate project setup, content sources, blocks, loading phases, spreadsheets/JSON, preview/live and the Sidekick, with a 100 Lighthouse score as the bar.

Download .zip Raw Source
When agents use itUse this whenever the user works in an aem-boilerplate repo, writes or debugs a block (blocks/<name>/<name>.js with export default decorate(block)), edits scripts.js, delayed.js, styles.css or fstab.yaml, configures mountpoints or the configuration service, runs aem up, uses .aem.page/.aem.live or branch preview URLs, builds query-index, redirects or headers sheets, adds third-party scripts, fights LCP or PageSpeed failures on a PR, designs content models for Google Drive, SharePoint, Document Authoring or Universal Editor authoring, or asks whether EDS fits versus traditional AEM Sites. Also apply it when someone wants to add React, a bundler or npm build to an EDS project.

Install

Copilot (VS Code, Visual Studio, Copilot CLI and github.com) reads skills from the repository — commit them so the whole team gets them.

npx skills add AGCO-Global/org-skills --skill aem-edge-delivery-services -a github-copilot
# or with the org installer (adds .github/skills/aem-edge-delivery-services):
npx -y github:AGCO-Global/org-skills add skill aem-edge-delivery-services

Uses the open skills CLI. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, OpenCode, Windsurf and 60+ others — it asks which agent to install into.

npx skills add AGCO-Global/org-skills --skill aem-edge-delivery-services
# user-level instead of project-level:
npx skills add AGCO-Global/org-skills --skill aem-edge-delivery-services -g

Installs the aem-headless-skills plugin, which bundles all AEM / Headless skills and keeps them updated.

/plugin marketplace add AGCO-Global/org-skills
/plugin install aem-headless-skills@org-skills
# or just this skill, in this repository:
npx skills add AGCO-Global/org-skills --skill aem-edge-delivery-services -a claude-code

Use Download .zip above, then upload it under Customize → Skills → Upload skill. Team and Enterprise admins can sync this repo as a plugin marketplace instead.

Installs into .agents/skills/, which Codex reads.

npx skills add AGCO-Global/org-skills --skill aem-edge-delivery-services -a codex

Installs into Cursor's skills folder.

npx skills add AGCO-Global/org-skills --skill aem-edge-delivery-services -a cursor

Installs into Gemini CLI's skills folder.

npx skills add AGCO-Global/org-skills --skill aem-edge-delivery-services -a gemini-cli

Any tool with rules, instructions or custom prompts: use Copy SKILL.md above and paste it in. It is plain Markdown.

Commands use your normal git sign-in to GitHub, so they work while the repository is private. Node.js 20+ required.

Skill contents

AEM Edge Delivery Services

Edge Delivery is a "no build, no framework" platform: content is authored as documents or in Universal Editor, turned into semantic HTML at the edge, and decorated by small vanilla JS/CSS blocks loaded in strict phases. Every decision is judged by two questions: does it keep the page at a 100 Lighthouse score, and can an author create it without a developer?

1. When EDS fits

Situation Choose Why
Marketing/content site, performance and time-to-launch matter most EDS with document authoring Fastest pages, simplest authoring, no build pipeline
Same, but authors need AEM governance, MSM/workflows, structured components EDS + Universal Editor (AEM authoring) AEM author UX, EDS delivery
Deep integration with AEM components, personalization on AEM publish, complex OSGi logic Traditional AEM Sites Server-side Java/HTL model and existing component library
App-like, heavily stateful UI Headless/SPA, possibly embedded in EDS pages EDS blocks are for content, not apps

2. Project setup and content sources

  • Start from the aem-boilerplate GitHub template (use the Universal Editor variant of the boilerplate when authoring in AEM); install the AEM Code Sync GitHub app on the repo — it syncs code to the edge on every push.
  • Content source: Google Drive or SharePoint documents, Document Authoring (DA), or AEM authoring via Universal Editor. Classic projects declare it in fstab.yaml; newer projects can use the configuration service (including "repoless" multi-site setups). Check current aem.live docs for which applies to your project before editing either.
# fstab.yaml (document-based projects)
mountpoints:
  /: https://drive.google.com/drive/folders/<folder-id>
  • URLs: https://main--<repo>--<owner>.aem.page (preview) and .aem.live (live); every branch gets https://<branch>--<repo>--<owner>.aem.page. Keep branch names short and lowercase (they become hostnames).
  • Authors use the Sidekick browser extension to Preview (→ .page), Publish (→ .live), and unpublish. Production CDN points at .live.

3. Page structure and content modelling

  • A document becomes sections (split by --- horizontal rules), each containing default content (headings, paragraphs, lists, images, links) and blocks (tables whose first row is the block name).
  • Section Metadata table inside a section sets section classes/data (e.g. Style | highlight). A Metadata table at the end of the page sets <meta> (title, description, image, template, custom keys read via getMetadata).
  • Block options in the header row become classes: Columns (wide, dark)<div class="columns wide dark">.
  • Model for authors: prefer default content over blocks, few rows/columns, no invisible magic cells, names in plain language. If a block needs a manual to author, redesign it.
  • Reuse content with fragments (a fragment block referencing /fragments/...); header and footer are fragments loaded from /nav and /footer.

4. Writing blocks

blocks/cards/cards.js   → export default function decorate(block) { ... }
blocks/cards/cards.css  → all selectors scoped under .cards
import { createOptimizedPicture } from '../../scripts/aem.js';

export default function decorate(block) {
  const ul = document.createElement('ul');
  [...block.children].forEach((row) => {
    const li = document.createElement('li');
    li.append(...row.children);
    [...li.children].forEach((col) => {
      col.className = col.querySelector('picture') ? 'cards-card-image' : 'cards-card-body';
    });
    ul.append(li);
  });
  ul.querySelectorAll('picture > img').forEach((img) => img.closest('picture')
    .replaceWith(createOptimizedPicture(img.src, img.alt, false, [{ width: '750' }])));
  block.replaceChildren(ul);
}
  • Decorate the existing DOM; don't discard author content or rebuild it from hard-coded strings. Keep blocks small (a few hundred lines at most) and single-purpose; variants via classes, not new blocks.
  • Use aem.js helpers (createOptimizedPicture, loadCSS, loadScript, getMetadata, readBlockConfig, toClassName, decorateIcons). Never edit scripts/aem.js — it is the shared library upgraded from upstream; put project logic in scripts/scripts.js.
  • CSS: mobile-first, scoped to the block class, CSS custom properties from styles/styles.css; no global resets inside blocks.
  • Async decorate is fine; await only what's needed before first paint.

5. Loading phases and performance

  • Eager (loadEager): decorate the page and load the first section only, so the LCP element (usually the hero image or H1) renders with minimal JS/CSS. Nothing third-party here.
  • Lazy (loadLazy): remaining sections and blocks, header/footer, lazy-styles.css, fonts.
  • Delayed (scripts/delayed.js, a few seconds after load): analytics, tag managers, chat, consent, marketing pixels. This is where third-party scripts go.
  • Target a 100 Lighthouse/PageSpeed score on mobile. Protect LCP: don't lazy-load the first image, don't insert content above the fold after load, reserve space to avoid CLS, keep eager payload tiny (the boilerplate keeps pre-LCP payload in the ~100 KB range).
  • Auto-blocking (buildAutoBlocks in scripts.js) creates blocks from content patterns (e.g. hero from a leading picture + H1, fragments from links) so authors don't have to — keep it deterministic and cheap.

6. Spreadsheets, JSON and site config

  • Any sheet is served as JSON (/data/offices.json{ total, offset, limit, data: [...] }, ?offset=&limit=, multi-sheet via ?sheet=). Use it for lists, lookups and block data instead of hard-coding.
  • query-index: an index definition produces /query-index.json with page metadata for listings, search and sitemaps; filter client-side or build a per-section index for large sites.
  • Redirects sheet for 301s; response headers and other site settings via the project configuration (older projects used config sheets, newer ones the configuration service) — verify the current mechanism in aem.live docs.
  • Forms: use the current EDS forms approach (form block backed by a sheet, or AEM Forms for EDS) — confirm availability and submission handling before designing.

7. Development workflow

  • Local: npm i -g @adobe/aem-cli, then aem uphttp://localhost:3000, serving local code with content proxied from preview.
  • npm run lint (ESLint airbnb-base + Stylelint) must pass; no build step, no transpile, ship ES modules as written.
  • PR workflow: push a branch, test on <branch>--<repo>--<owner>.aem.page, include before/after test URLs in the PR. The Code Sync / PSI checks run PageSpeed on those URLs — a PR that drops the score is not mergeable in spirit even if the check is overridden.

Deliverable format (block spec)

  1. Block name and purpose, variants (class options).
  2. Authoring table: rows/columns authors fill, with an example and what's optional.
  3. Resulting DOM after decoration and the CSS/responsive behaviour.
  4. Data: sheets/JSON/query-index used, with fields.
  5. Performance: loading phase, LCP impact, images and third-party scripts.
  6. Test URLs (branch preview) and lint/PSI results.

Anti-patterns to reject

  • Adding React/Vue, a bundler, TypeScript build or npm runtime dependencies to page delivery.
  • Editing scripts/aem.js; forking boilerplate internals instead of using scripts.js.
  • Third-party scripts in head.html or eager phase; anything that blocks or delays LCP.
  • Huge multi-purpose blocks; blocks that ignore author content and hard-code copy.
  • Author-hostile models: deep nested tables, positional magic, JSON in cells.
  • Global CSS leaking from blocks; unscoped selectors.
  • Content or config hard-coded in JS that belongs in a sheet or metadata.
  • Merging PRs without branch test URLs or with a PageSpeed regression.