|
| 1 | +--- |
| 2 | +name: create-site |
| 3 | +description: Creates a new AEM Edge Delivery site from scratch — GitHub repo from the boilerplate, aem-code-sync installation, initial DA content (nav, footer, homepage), and a live preview URL. Use this skill whenever a user wants to create a new AEM Edge Delivery site and no repository or DA content exists yet. |
| 4 | +license: Apache-2.0 |
| 5 | +metadata: |
| 6 | + version: "1.0.0" |
| 7 | +--- |
| 8 | + |
| 9 | +# Create a New AEM Edge Delivery Site |
| 10 | + |
| 11 | +This skill walks through the full onboarding flow for a new AEM Edge Delivery site. It handles everything that can be automated and clearly signals the steps that require human action. |
| 12 | + |
| 13 | +## When to Use This Skill |
| 14 | + |
| 15 | +Use this skill when: |
| 16 | +- A user wants to create a brand-new AEM Edge Delivery site from scratch |
| 17 | +- A user asks to "set up a new site", "create a new EDS project", or "onboard a new site" |
| 18 | +- No GitHub repository or DA content exists yet for the project |
| 19 | + |
| 20 | +**Do NOT use this skill for:** |
| 21 | +- Importing or migrating existing pages (use **page-import** skill) |
| 22 | +- Building or modifying blocks on an existing site (use **content-driven-development** skill) |
| 23 | + |
| 24 | +## Prerequisites |
| 25 | + |
| 26 | +- A GitHub account with permission to create repositories in the target org |
| 27 | +- An Adobe IMS account with access to DA (da.live) |
| 28 | +- `gh` CLI authenticated (`gh auth status`) or a GitHub personal access token with `repo` scope |
| 29 | +- Node.js (for DA token management via da-auth-helper) |
| 30 | + |
| 31 | +## Related Skills |
| 32 | + |
| 33 | +- **page-import** — Import existing pages into the newly created site |
| 34 | +- **content-driven-development** — Build and modify blocks once the site exists |
| 35 | +- **building-blocks** — Implement new block code |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +## Step 0: Create TodoList |
| 40 | + |
| 41 | +Create a checklist to track progress (use your agent's task-tracking tool if available): |
| 42 | + |
| 43 | +1. **Gather inputs** — org, repo name, site name collected |
| 44 | +2. **Create GitHub repository** — repo created from boilerplate template |
| 45 | +3. **Install aem-code-sync** *(human action)* — GitHub App installed on repo |
| 46 | +4. **Authenticate with DA** — valid IMS token obtained |
| 47 | +5. **Create initial content in DA** — nav, footer, index created |
| 48 | +6. **Trigger preview** — all three paths return 200/201 |
| 49 | +7. **Hand off** — preview URL and DA links delivered to user |
| 50 | + |
| 51 | +--- |
| 52 | + |
| 53 | +## Step 1: Gather Inputs |
| 54 | + |
| 55 | +Ask the user for the following. Do not proceed until all required inputs are provided. |
| 56 | + |
| 57 | +1. **GitHub org** — the GitHub organization or username where the repo will be created (e.g. `my-org`) |
| 58 | +2. **Project name** — the repository name, lowercase, hyphens only (e.g. `my-site`) |
| 59 | +3. **Site name** — the human-readable name used in content (e.g. `My Site`). If not provided, derive it from the project name. |
| 60 | + |
| 61 | +Store as: `{{ORG}}`, `{{REPO}}`, `{{SITE_NAME}}` |
| 62 | + |
| 63 | +--- |
| 64 | + |
| 65 | +## Step 2: Create GitHub Repository |
| 66 | + |
| 67 | +Create a new repository using the `adobe/aem-boilerplate` template. |
| 68 | + |
| 69 | +**Option A — GitHub CLI (preferred, handles auth automatically):** |
| 70 | +```bash |
| 71 | +gh repo create {{ORG}}/{{REPO}} \ |
| 72 | + --template adobe/aem-boilerplate \ |
| 73 | + --description "{{SITE_NAME}} — AEM Edge Delivery site" \ |
| 74 | + --public |
| 75 | +``` |
| 76 | + |
| 77 | +Check if `gh` is available with `gh auth status`. If not authenticated, run `gh auth login` first. |
| 78 | + |
| 79 | +**Option B — GitHub API (if `gh` CLI is not available):** |
| 80 | +``` |
| 81 | +POST https://api.github.com/repos/adobe/aem-boilerplate/generate |
| 82 | +Authorization: Bearer {{GITHUB_TOKEN}} |
| 83 | +Content-Type: application/json |
| 84 | +
|
| 85 | +{ |
| 86 | + "owner": "{{ORG}}", |
| 87 | + "name": "{{REPO}}", |
| 88 | + "description": "{{SITE_NAME}} — AEM Edge Delivery site", |
| 89 | + "private": false, |
| 90 | + "include_all_branches": false |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +To obtain a token: https://github.com/settings/tokens/new — scope: `repo`. |
| 95 | + |
| 96 | +**Success:** HTTP 201 (API) or exit code 0 (CLI). The repo is now live at `https://github.com/{{ORG}}/{{REPO}}`. |
| 97 | + |
| 98 | +--- |
| 99 | + |
| 100 | +## Step 3: Install aem-code-sync *(human action required)* |
| 101 | + |
| 102 | +The aem-code-sync GitHub App connects the repository to AEM's content delivery pipeline. This step cannot be automated — the user must complete it in the browser. |
| 103 | + |
| 104 | +Tell the user: |
| 105 | + |
| 106 | +> **Action required:** Install the AEM Code Sync app on your new repository. |
| 107 | +> |
| 108 | +> 1. Open this URL: https://github.com/apps/aem-code-sync/installations/new |
| 109 | +> 2. Under "Repository access", select **Only select repositories** |
| 110 | +> 3. Choose **{{ORG}}/{{REPO}}** from the list |
| 111 | +> 4. Click **Save** |
| 112 | +> |
| 113 | +> Reply "done" when complete. |
| 114 | +
|
| 115 | +Wait for confirmation before proceeding. |
| 116 | + |
| 117 | +**Verify:** After confirmation, check that `https://admin.hlx.page/status/{{ORG}}/{{REPO}}/main/` returns a valid JSON response (not 404). If it does, the app is correctly installed. |
| 118 | + |
| 119 | +--- |
| 120 | + |
| 121 | +## Step 4: Authenticate with DA |
| 122 | + |
| 123 | +DA requires Adobe IMS authentication. Choose the appropriate path: |
| 124 | + |
| 125 | +**Option A — da-auth-helper (preferred)** |
| 126 | + |
| 127 | +`da-auth-helper` (https://github.com/adobe-rnd/da-auth-helper) caches IMS tokens at `~/.aem/da-token.json`. Always check the cache first before triggering a new OAuth flow. |
| 128 | + |
| 129 | +1. Check for a valid cached token: |
| 130 | +```bash |
| 131 | +node -e " |
| 132 | + const fs = require('fs'); |
| 133 | + const p = process.env.HOME + '/.aem/da-token.json'; |
| 134 | + if (!fs.existsSync(p)) { console.log('No cache'); process.exit(1); } |
| 135 | + const t = JSON.parse(fs.readFileSync(p)); |
| 136 | + console.log('Valid:', t.expires_at > Date.now()); |
| 137 | + console.log('Expires:', new Date(t.expires_at).toISOString()); |
| 138 | +" |
| 139 | +``` |
| 140 | + |
| 141 | +2. If valid, capture the token and skip to Step 5: |
| 142 | +```bash |
| 143 | +DA_TOKEN=$(node -e "const t = require(process.env.HOME + '/.aem/da-token.json'); process.stdout.write(t.access_token);") |
| 144 | +``` |
| 145 | + |
| 146 | +3. If missing or expired, install da-auth-helper from GitHub (it is not published to npm) and refresh: |
| 147 | +```bash |
| 148 | +npm install -g github:adobe-rnd/da-auth-helper |
| 149 | +da-auth-helper token |
| 150 | +``` |
| 151 | +This opens a browser for Adobe IMS login and writes the new token to `~/.aem/da-token.json`. Then capture it as in step 2. |
| 152 | + |
| 153 | +**Option B — DA MCP is configured** |
| 154 | + |
| 155 | +If the DA MCP server is available, trigger the authentication tool to start the OAuth flow and share the authorization URL with the user. |
| 156 | + |
| 157 | +**Option C — Manual token** |
| 158 | + |
| 159 | +Ask the user to obtain an IMS token from their browser (e.g. from the DA network tab or an existing session) and paste it. Store as `{{DA_TOKEN}}`. |
| 160 | + |
| 161 | +--- |
| 162 | + |
| 163 | +## Step 5: Create Initial Content in DA |
| 164 | + |
| 165 | +Create the three mandatory pages every EDS site requires. Use the templates below exactly — they are pre-validated for EDS compliance. |
| 166 | + |
| 167 | +**Option A — DA MCP:** |
| 168 | +Call the DA create source tool three times with the content below. |
| 169 | + |
| 170 | +**Option B — DA API:** |
| 171 | + |
| 172 | +Write each file to a temp file first, then POST using `@` syntax. Inline multiline content with `-F 'data=...'` causes curl to fail (exit 26). Use `/usr/bin/curl` explicitly to avoid PATH resolution issues in subshells. |
| 173 | + |
| 174 | +```bash |
| 175 | +cat > /tmp/nav.html << 'EOF' |
| 176 | +<nav content> |
| 177 | +EOF |
| 178 | +/usr/bin/curl -s -o /dev/null -w "%{http_code}" -X POST "https://admin.da.live/source/{{ORG}}/{{REPO}}/nav.html" \ |
| 179 | + -H "Authorization: Bearer {{DA_TOKEN}}" \ |
| 180 | + -F "data=@/tmp/nav.html;type=text/html" |
| 181 | +``` |
| 182 | + |
| 183 | +Repeat for `footer.html` and `index.html`. |
| 184 | + |
| 185 | +**Verify:** After each POST, expect HTTP 201. If you get 401, the token has expired — return to Step 4. |
| 186 | + |
| 187 | +--- |
| 188 | + |
| 189 | +### nav.html |
| 190 | + |
| 191 | +```html |
| 192 | +<main> |
| 193 | + <div> |
| 194 | + <p><a href="/">{{SITE_NAME}}</a></p> |
| 195 | + </div> |
| 196 | + <div> |
| 197 | + <ul> |
| 198 | + <li><a href="/">Home</a></li> |
| 199 | + </ul> |
| 200 | + </div> |
| 201 | + <div></div> |
| 202 | +</main> |
| 203 | +``` |
| 204 | + |
| 205 | +### footer.html |
| 206 | + |
| 207 | +```html |
| 208 | +<main> |
| 209 | + <div> |
| 210 | + <p>© 2024 {{SITE_NAME}}. All rights reserved.</p> |
| 211 | + </div> |
| 212 | +</main> |
| 213 | +``` |
| 214 | + |
| 215 | +### index.html |
| 216 | + |
| 217 | +```html |
| 218 | +<main> |
| 219 | + <div> |
| 220 | + <h1>Welcome to {{SITE_NAME}}</h1> |
| 221 | + <p>Your new site is ready. Start editing this page in DA.</p> |
| 222 | + </div> |
| 223 | +</main> |
| 224 | +``` |
| 225 | + |
| 226 | +--- |
| 227 | + |
| 228 | +## Step 6: Trigger Preview |
| 229 | + |
| 230 | +Preview pulls the DA content into the AEM delivery pipeline and makes it accessible on the `.aem.page` domain. |
| 231 | + |
| 232 | +DA-sourced content requires the Bearer token on preview requests — even for public repos. Use `/usr/bin/curl` explicitly. |
| 233 | + |
| 234 | +```bash |
| 235 | +/usr/bin/curl -s -o /dev/null -w "%{http_code}" -X POST "https://admin.hlx.page/preview/{{ORG}}/{{REPO}}/main/nav" \ |
| 236 | + -H "Authorization: Bearer {{DA_TOKEN}}" |
| 237 | +/usr/bin/curl -s -o /dev/null -w "%{http_code}" -X POST "https://admin.hlx.page/preview/{{ORG}}/{{REPO}}/main/footer" \ |
| 238 | + -H "Authorization: Bearer {{DA_TOKEN}}" |
| 239 | +/usr/bin/curl -s -o /dev/null -w "%{http_code}" -X POST "https://admin.hlx.page/preview/{{ORG}}/{{REPO}}/main/" \ |
| 240 | + -H "Authorization: Bearer {{DA_TOKEN}}" |
| 241 | +``` |
| 242 | + |
| 243 | +**Success:** HTTP 200 or 201 for each. The homepage is now live at: |
| 244 | +``` |
| 245 | +https://main--{{REPO}}--{{ORG}}.aem.page/ |
| 246 | +``` |
| 247 | + |
| 248 | +--- |
| 249 | + |
| 250 | +## Step 7: Confirm and Hand Off |
| 251 | + |
| 252 | +Tell the user: |
| 253 | + |
| 254 | +> **Your site is ready!** |
| 255 | +> |
| 256 | +> - **Preview:** `https://main--{{REPO}}--{{ORG}}.aem.page/` |
| 257 | +> - **Browse content in DA:** `https://da.live/#/{{ORG}}/{{REPO}}/` |
| 258 | +> - **Edit homepage:** `https://da.live/edit#/{{ORG}}/{{REPO}}/index` |
| 259 | +> - **Edit nav:** `https://da.live/edit#/{{ORG}}/{{REPO}}/nav` |
| 260 | +> - **Edit footer:** `https://da.live/edit#/{{ORG}}/{{REPO}}/footer` |
| 261 | +> - **GitHub repo:** `https://github.com/{{ORG}}/{{REPO}}` |
| 262 | +> |
| 263 | +> To start developing locally: |
| 264 | +> ```bash |
| 265 | +> git clone https://github.com/{{ORG}}/{{REPO}}.git |
| 266 | +> cd {{REPO}} |
| 267 | +> npm install |
| 268 | +> aem up |
| 269 | +> ``` |
| 270 | +> |
| 271 | +> What would you like to do next — add more pages, customize a block, or set up a custom domain? |
| 272 | +
|
| 273 | +--- |
| 274 | +
|
| 275 | +## Troubleshooting |
| 276 | +
|
| 277 | +| Symptom | Likely cause | Fix | |
| 278 | +|---|---|---| |
| 279 | +| Step 2 returns 422 | Repo name already exists | Ask user for a different name | |
| 280 | +| Step 3 verify returns 404 | aem-code-sync not installed | Re-send the installation URL | |
| 281 | +| Step 4 cached token missing/expired | No prior DA session on this machine | Install da-auth-helper from GitHub (`npm install -g github:adobe-rnd/da-auth-helper`) and run `da-auth-helper token` | |
| 282 | +| Step 5 curl exits with code 26 | Inline multiline content in `-F` flag | Write content to a temp file and use `@/tmp/file.html` syntax | |
| 283 | +| Step 5 returns 401 | Expired or missing IMS token | Re-check `~/.aem/da-token.json` expiry; ask user for a fresh token | |
| 284 | +| Step 5 returns 403 | Token lacks permission for this org/repo | Confirm the user has write access to `{{ORG}}/{{REPO}}` in DA | |
| 285 | +| Step 6 returns 401 | DA-sourced content requires auth on preview | Add `-H "Authorization: Bearer {{DA_TOKEN}}"` to preview requests | |
| 286 | +| Step 6 returns 404 | aem-code-sync not installed correctly | Verify Step 3, then retry | |
| 287 | +| `curl: command not found` in scripts | PATH not resolved in subshell | Use `/usr/bin/curl` explicitly | |
| 288 | +| Preview URL shows blank page | nav or index not previewed | Re-run Step 6 for the failing path | |
| 289 | +
|
| 290 | +--- |
| 291 | +
|
| 292 | +## Reference |
| 293 | +
|
| 294 | +- Boilerplate: https://github.com/adobe/aem-boilerplate |
| 295 | +- aem-code-sync app: https://github.com/apps/aem-code-sync |
| 296 | +- DA docs: https://da.live/docs |
| 297 | +- DA Admin API: https://opensource.adobe.com/da-admin/ |
| 298 | +- DA Auth (IMS token helper): https://github.com/adobe-rnd/da-auth-helper |
| 299 | +- AEM Admin API: https://www.aem.live/docs/admin.html |
| 300 | +- Full onboarding guide: https://www.aem.live/developer/create-site.md |
| 301 | +
|
| 302 | +### DA URL patterns |
| 303 | +
|
| 304 | +- Browse folder: `https://da.live/#/{{org}}/{{repo}}{{folder-path}}` |
| 305 | +- Edit HTML document: `https://da.live/edit#/{{org}}/{{repo}}{{path-without-extension}}` |
| 306 | +- Edit JSON/sheet: `https://da.live/sheet#/{{org}}/{{repo}}{{path-without-extension}}` |
0 commit comments