plugins/aem/project-management/skills/authoring/SKILL.md
Generate comprehensive documentation for content authors taking over an AEM Edge Delivery Services project. Analyzes the project structure and produces a complete authoring guide with blocks, templates, configurations, and publishing workflows.
npx skillsauth add adobe/skills authoringInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate a complete authoring guide for content authors and content managers. This skill analyzes the project and produces actionable documentation.
Skip this step if allGuides flag is set (orchestrator already validated and navigated).
CRITICAL: If NOT skipped, you MUST execute the cd command. Do NOT use absolute paths — actually change directory.
ALL_GUIDES=$(cat .claude-plugin/project-config.json 2>/dev/null | node -e "
const d = require('fs').readFileSync(0,'utf8');
try { console.log(JSON.parse(d).allGuides ? 'true' : ''); } catch(e) { console.log(''); }
")
if [ -z "$ALL_GUIDES" ]; then
# Navigate to git project root (works from any subdirectory)
cd "$(git rev-parse --show-toplevel)"
# Verify it's an Edge Delivery Services project
ls scripts/aem.js
fi
IMPORTANT:
cd command above using the Bash toolproject-root/project-guides/If NOT skipped AND scripts/aem.js does NOT exist, respond:
"This skill is designed for AEM Edge Delivery Services projects. The current directory does not appear to be an Edge Delivery Services project (
scripts/aem.jsnot found).Please navigate to an Edge Delivery Services project and try again."
STOP if check fails. Otherwise proceed — you are now at project root.
YOU MUST SAVE THE FILE TO THIS EXACT PATH:
project-guides/AUTHOR-GUIDE.md
BEFORE WRITING ANY FILE:
mkdir -p project-guidesproject-guides/AUTHOR-GUIDE.mdWHY THIS MATTERS: Files must be in project-guides/ for proper organization and PDF conversion.
❌ WRONG: AUTHOR-GUIDE.md (root)
❌ WRONG: docs/AUTHOR-GUIDE.md
❌ WRONG: /workspace/AUTHOR-GUIDE.md
✅ CORRECT: project-guides/AUTHOR-GUIDE.md
MANDATORY OUTPUT: project-guides/AUTHOR-GUIDE.pdf
STRICTLY FORBIDDEN:
fstab.yaml — it does NOT exist in most projects and does NOT show all sites.plain.html filesconvert_markdown_to_html tool — this converts the FULL guide to HTML with raw frontmatter visible, which is NOT what we wantproject-guides/REQUIRED WORKFLOW:
mkdir -p project-guides to ensure directory existsproject-guides/AUTHOR-GUIDE.md (EXACT PATH - no exceptions)project-guides/AUTHOR-GUIDE.pdf- [ ] Phase 1: Gather Project Information
- [ ] Phase 2: Analyze Content Structure
- [ ] Phase 3: Document Blocks and Templates
- [ ] Phase 4: Document Configuration Sheets
- [ ] Phase 5: Generate Professional PDF
Whenever this skill runs — whether the user triggered it directly (e.g. "generate authoring guide") or via the handover flow — you must have the Config Service organization name before doing anything else. Do not skip this phase.
# Check if org name is already saved
cat .claude-plugin/project-config.json 2>/dev/null | node -e "
const d = require('fs').readFileSync(0,'utf8');
try { const o = JSON.parse(d).org; if(o) console.log('org: ' + o); } catch(e) {}
"
If no org name is saved, you MUST pause and ask the user directly:
"What is your Config Service organization name? This is the
{org}part of your Edge Delivery Services URLs (e.g.,https://main--site--{org}.aem.page). The org name may differ from your GitHub organization."
IMPORTANT RULES:
AskUserQuestion with predefined options — ask as a plain text questionOnce you have the org name (either from saved config or user input), save it for future use:
# Create config directory if needed
mkdir -p .claude-plugin
# Ensure .claude-plugin is in .gitignore (contains project config)
grep -qxF '.claude-plugin/' .gitignore 2>/dev/null || echo '.claude-plugin/' >> .gitignore
# Save org name to config file (create or update)
if [ -f .claude-plugin/project-config.json ]; then
cat .claude-plugin/project-config.json | sed 's/"org"[[:space:]]*:[[:space:]]*"[^"]*"/"org": "{ORG_NAME}"/' > /tmp/project-config.json && mv /tmp/project-config.json .claude-plugin/project-config.json
else
echo '{"org": "{ORG_NAME}"}' > .claude-plugin/project-config.json
fi
Replace {ORG_NAME} with the actual organization name provided by the user.
⚠️ MANDATORY DATA SOURCE — NO ALTERNATIVES ALLOWED
You MUST call the Config Service API. This is the ONLY acceptable source for site information.
❌ PROHIBITED APPROACHES (will produce incorrect results):
fstab.yaml — does NOT show all sites in repoless setupsREADME.md — may be outdated or incomplete✅ REQUIRED: Execute and save response:
ORG=$(cat .claude-plugin/project-config.json | node -e "
const d = require('fs').readFileSync(0,'utf8');
console.log(JSON.parse(d).org || '');
")
# Save response to file - Phase 2 depends on this file
curl -s -H "Accept: application/json" "https://admin.hlx.page/config/${ORG}/sites.json" > .claude-plugin/sites-config.json
📁 REQUIRED ARTIFACT: .claude-plugin/sites-config.json
API Reference: https://www.aem.live/docs/admin.html#tag/siteConfig/operation/getConfigSites
The response is a JSON object with a sites array (each entry has a name field). Extract site names and construct per-site URLs:
https://main--{site-name}--{org}.aem.page/https://main--{site-name}--{org}.aem.live/Multiple sites = repoless setup. Single site = standard setup.
Then fetch individual site config for code and content details.
First, check for valid auth token:
IMS_TOKEN=$(node -e "
const fs = require('fs');
try {
const t = JSON.parse(fs.readFileSync(process.env.HOME + '/.aem/ims-token.json', 'utf8'));
if (t.imsToken && t.imsTokenExpiry > Math.floor(Date.now()/1000) + 60) {
process.stdout.write(t.imsToken);
}
} catch (e) {}
")
if [ -z "$IMS_TOKEN" ]; then
echo "AUTH_REQUIRED"
fi
If AUTH_REQUIRED, invoke the auth skill before proceeding:
Skill({ skill: "project-management:auth" })
Then fetch site config:
IMS_TOKEN=$(node -e "
const fs = require('fs');
try {
const t = JSON.parse(fs.readFileSync(process.env.HOME + '/.aem/ims-token.json', 'utf8'));
process.stdout.write(t.imsToken || '');
} catch (e) {}
")
curl -s -H "Authorization: Bearer ${IMS_TOKEN}" "https://admin.hlx.page/config/${ORG}/sites/{site-name}.json"
Example response:
{
"code": {
"owner": "github-owner",
"repo": "repo-name",
"source": { "type": "github", "url": "https://github.com/owner/repo" }
},
"content": {
"source": {
"url": "https://content.da.live/org-name/site-name/",
"type": "markup"
},
"contentBusId": "..."
}
}
Extract from response:
code.owner / code.repo — GitHub repositorycontent.source.url — Content mountpath (e.g., https://content.da.live/org/site/)content.source.type — Content source type (markup, onedrive, google)Build URLs from content source:
https://da.live/#/{org}/{site}/ (derived from content.source.url)https://da.live/#/{org}/{site}/.da/library⚠️ Do NOT use fstab.yaml — use Config Service API instead.
# Check for language folders in content structure
ls -la /en /fr /de /es /it 2>/dev/null || echo "Check DA for language folders"
Output: Record whether project is multi-lingual and which languages are supported.
Read site config from Phase 1:
cat .claude-plugin/sites-config.json
ls nav.md footer.md 2>/dev/null || echo "Nav/footer likely in DA"
Document: Navigation and footer location (DA path or local file), menu structure, mobile behavior.
ls -la templates/ 2>/dev/null && ls templates/
If templates exist, document each: Template name, purpose, how to apply (metadata setting).
grep -E "\.section\." styles/styles.css 2>/dev/null | head -15
Document available section styles (e.g. dark, highlight, narrow) for the "Available Section Styles" table in the guide.
ls blocks/
Run block analysis silently. For each block determine: purpose, variants (e.g. from CSS .blockname.variant), and when authors should use it. Document ALL blocks in the project so authors know what's available.
For each template identified in Phase 2.2, document: name, purpose, required metadata fields, and how to apply (template: name in Metadata block).
Get the content path from the Config Service site config (content source). Block Library URL is https://da.live/#/{content-owner}/{content-path}/.da/library — the path varies by project. Note which blocks/templates appear in the library.
Location: /placeholders in DA (or /placeholders.xlsx)
ls placeholders.json 2>/dev/null
Document: | Field | Description | |-------|-------------| | Location | Where to find placeholders in DA | | Languages | Which language sheets exist (en, fr, etc.) | | Key strings | Important placeholders authors might need to update |
Location: /redirects in DA (or /redirects.xlsx)
ls redirects.json 2>/dev/null
Document: | Field | Description | |-------|-------------| | Location | Where to find redirects in DA | | Format | Source column → Destination column | | When to use | URL changes, deleted pages, renamed pages |
Location: /metadata in DA (or /metadata.xlsx)
ls metadata.json 2>/dev/null
Document:
| Field | Description |
|-------|-------------|
| Location | Where to find bulk metadata in DA |
| Patterns | URL patterns used (e.g., /news/*) |
| Properties | Which metadata properties are set in bulk |
Check for project-specific configuration sheets:
# Look for other Excel/JSON config files
ls -la *.xlsx *.json 2>/dev/null | grep -v package
project-guides/AUTHOR-GUIDE.md# [Project Name] - Author Guide
## Quick Reference
| Resource | URL |
|----------|-----|
| Document Authoring | https://da.live/#/{content-owner}/{content-path}/ |
| Preview (per site) | https://main--{site}--{org}.aem.page/ |
| Live (per site) | https://main--{site}--{org}.aem.live/ |
| Block Library | https://da.live/#/{content-owner}/{content-path}/.da/library |
| Bulk Operations | https://da.live/apps/bulk |
(**Content path** comes from the Config Service site config — e.g. content source like `content.da.live/org/site/` → use `org/site` for the path after `#/`. This can differ per project; do not use code.owner/code.repo unless the API explicitly maps them.)
### Sites
| Site | Content Source (DA) | Preview | Live |
|------|---------------------|---------|------|
| {site1} | [from site config] | https://main--{site1}--{org}.aem.page/ | https://main--{site1}--{org}.aem.live/ |
(One row per site from Config Service. **Content Source (DA)** is the content path for that site — use it to build DA and Block Library URLs: `https://da.live/#/{path-from-content-source}/` and `.../.da/library`. Path format varies by project, e.g. `audemars-piguet/arbres-fondationsaudemarspiguet`.)
## Getting Started
### Access Requirements
- [ ] DA access (request from admin)
- [ ] Preview/publish permissions
### Your First Page
1. Go to DA: [link]
2. Navigate to the correct folder
3. Create new document
4. Use blocks from Library sidebar
5. Add Metadata block at bottom
6. Preview → Publish
## Content Organization
### Site Structure
[Describe the folder structure in DA]
### Languages
[List supported languages if multi-lingual]
## Block Library
The **Block Library** is the sidebar in Document Authoring where you browse and insert blocks and templates into your document.
| What | Details |
|------|---------|
| **Open in DA** | Use the Library icon in the DA editor sidebar, or go directly to the Block Library URL (from Config Service content path for this project): `https://da.live/#/{content-owner}/{content-path}/.da/library` |
| **What's in it** | All blocks and templates listed in the "Available Blocks" and "Page Templates" sections below appear in the library |
| **How to use** | Click a block or template in the library to insert it at the cursor position in your document |
When creating or editing a page, use the Library sidebar to add blocks instead of typing block names manually.
## Available Blocks
| Block | Purpose | Variants | Usage |
|-------|---------|----------|-------|
| [name] | [what it's for] | [variant1, variant2] | [when to use] |
[Generate table rows for all blocks]
## Page Templates
| Template | Purpose | Required Metadata | How to Apply |
|----------|---------|-------------------|--------------|
| [name] | [what type of pages] | [key fields] | `template: [name]` in Metadata |
[Generate table rows for all templates]
## Configuration Sheets
| Sheet | Location | Purpose | When to Update |
|-------|----------|---------|----------------|
| Placeholders | `/placeholders` | Reusable text strings, translations | Changing labels, button text |
| Redirects | `/redirects` | Forward old URLs to new URLs | After deleting/moving pages |
| Bulk Metadata | `/metadata` | Apply metadata to multiple pages | Setting defaults by folder |
## Publishing Workflow
| Environment | Domain | Purpose |
|-------------|--------|---------|
| Preview | `.aem.page` | Test changes before going live |
| Live | `.aem.live` | Production site |
**Workflow:** Edit in DA → Preview → Publish → Live immediately
**Bulk:** https://da.live/apps/bulk
## Common Tasks
| Task | Steps |
|------|-------|
| **Create a Page** | Navigate to folder → New → Document → Add content → Add Metadata → Preview → Publish |
| **Edit a Page** | Open in DA → Make changes → Preview → Publish |
| **Delete a Page** | Add redirect first → Delete document → Publish redirects |
| **Update Navigation** | Edit `/nav` document → Preview → Publish |
| **Update Footer** | Edit `/footer` document → Preview → Publish |
## Sections and Section Metadata
**Sections** group content together. Create sections with horizontal rules (`---`).
**Add styles** with Section Metadata block at end of section:
| Section Metadata | |
|------------------|--------|
| style | [style-name] |
**Available Section Styles:**
| Style | Effect |
|-------|--------|
| [List project-specific styles in table format] |
## Page Metadata
| Property | Required | Purpose | Example |
|----------|----------|---------|---------|
| `title` | Yes | Page title for SEO | "About Us" |
| `description` | Yes | SEO description | "Learn about..." |
| `image` | No | Social sharing image | /images/og.jpg |
| `template` | No | Apply page template | project-article |
| [Add project-specific fields] |
## Images and Media
| Method | How |
|--------|-----|
| Drag & drop | Drag images directly into DA editor |
| AEM Assets | Use Assets sidebar in DA |
**Best Practices:** Descriptive filenames, always add alt text, images auto-optimized
## Troubleshooting
| Issue | Solution |
|-------|----------|
| Page not updating after publish | Wait 1-2 min for cache, hard refresh (Cmd+Shift+R) |
| Block not displaying correctly | Check structure matches expected format, verify variant spelling |
| Images not showing | Verify image uploaded to DA, check path is correct |
| Wrong template styling | Check `template` value in Metadata, ensure it matches template name exactly |
## Resources
| Resource | URL |
|----------|-----|
| DA Documentation | https://docs.da.live/ |
| Authoring Guide | https://www.aem.live/docs/authoring |
| Placeholders Docs | https://www.aem.live/docs/placeholders |
| Redirects Docs | https://www.aem.live/docs/redirects |
## Support Contacts
[Add project-specific contacts]
THIS STEP IS NOT OPTIONAL. YOU MUST GENERATE THE PDF NOW.
Save markdown to: project-guides/AUTHOR-GUIDE.md
---
title: "[Project Name] - Author Guide"
date: "[Full Date - e.g., February 17, 2026]"
---
IMMEDIATELY after saving the markdown, invoke the PDF conversion skill:
Skill({ skill: "project-management:whitepaper", args: "project-guides/AUTHOR-GUIDE.md project-guides/AUTHOR-GUIDE.pdf" })
Wait for PDF generation to complete (whitepaper skill auto-cleans source files)
DO NOT:
After PDF is generated, inform the user:
"✓ Author guide complete: project-guides/AUTHOR-GUIDE.pdf"
FINAL OUTPUT: project-guides/AUTHOR-GUIDE.pdf
All source files (.md, .html, .plain.html) are deleted after PDF generation. Only the PDF remains.
Location: project-guides/ folder
Data Source Validation (CRITICAL):
https://admin.hlx.page/config/{ORG}/sites.json)Content Validation:
Output Validation:
development
Start AEM Workflows on AEM as a Cloud Service using all available triggering mechanisms. Use when starting workflows manually via the Timeline UI, programmatically via WorkflowSession.startWorkflow(), via the HTTP Workflow API, through Manage Publication, or passing initial metadata and payload to a workflow instance.
development
Single entry point for all AEM as a Cloud Service Workflow skills. Covers workflow model design, custom process step and participant chooser development, launcher configuration, workflow triggering, and production support including debugging stuck/failed workflows, triaging incidents with Cloud Manager logs, thread pool analysis, and Sling Job diagnostics for the Granite Workflow Engine.
development
[BETA] Implement custom AEM Workflow Java components on AEM as a Cloud Service. This skill is in beta. Verify all outputs before applying them to production projects. Use when writing WorkflowProcess steps, ParticipantStepChooser implementations, registering services via OSGi DS R6 annotations, reading step arguments from MetaDataMap, accessing JCR payload via WorkflowSession adapter, reading and writing workflow metadata and variables, and handling errors with WorkflowException for retry behavior.
development
Start AEM Workflows on AEM 6.5 LTS using all available triggering mechanisms. Use when starting workflows manually via the Timeline UI, programmatically via WorkflowSession.startWorkflow(), via the HTTP Workflow API, through Manage Publication, through replication triggers, or passing initial metadata and payload to a workflow instance.