# Template Workflows Guide for Modyo MCP

> **Critical Guide**: Template IDs can change during editing sessions, causing silent failures. This guide shows safe patterns for template operations.

---

## Table of Contents

1. [The Template ID Instability Problem](#the-template-id-instability-problem)
2. [Safe Template Editing Workflow](#safe-template-editing-workflow)
3. [Layout vs Template-Save Distinction](#layout-vs-template-save-distinction)
4. [Version Tracking](#version-tracking)
5. [Publishing Templates](#publishing-templates)
6. [Common Pitfalls](#common-pitfalls)
7. [Advanced Workflows](#advanced-workflows)

---

## The Template ID Instability Problem

### ⚠️ Critical Issue Discovered (Iteration 10)

**Template IDs can change between save operations**, causing:
- Silent failures (saving to wrong/stale ID)
- Changes not appearing after publish
- Version conflicts
- Lost work

### Example of the Problem

```typescript
// PROBLEMATIC WORKFLOW
// 1. Get template
const template = await template-get({ templateId: 561052 })

// 2. Modify body
const updatedBody = modifyTemplate(template.body)

// 3. Save changes
await template-save({ templateId: 561052, body: updatedBody })
// ✅ Save succeeds, but ID might have changed to 561056

// 4. Make more changes
const moreChanges = modifyAgain(updatedBody)

// 5. Save again with STALE ID
await template-save({ templateId: 561052, body: moreChanges })
// ❌ SILENT FAILURE: Saved to old version, not current template

// 6. Publish
await release-create({ template: [{ id: 561056, selected: true }] })
// ❌ Published wrong version, changes missing
```

### Why This Happens

- Modyo creates new template versions on certain operations
- Version IDs increment, but template ID can change
- No validation on template-save to reject stale IDs
- No etag or optimistic locking mechanism

---

## Safe Template Editing Workflow

### ✅ ALWAYS Follow This Pattern

```typescript
// SAFE WORKFLOW PATTERN

// 1. ALWAYS start by listing templates to get current ID
const templates = await template-list({
  platformSlug: "fed-team",
  siteId: 4612,
  type: "snippet"  // Optional: filter by type
})

// 2. Find the template you want to edit
const footerTemplate = templates.find(t => t.name === "footer_css")
const currentId = footerTemplate.id  // THIS IS THE CURRENT ID

// 3. Get template body
const template = await template-get({
  platformSlug: "fed-team",
  siteId: 4612,
  templateId: currentId  // Use ID from step 1
})

// 4. Modify body
const updatedBody = `<style nonce="{{csp_nonce}}">
.footer { /* updated styles */ }
</style>`

// 5. Save changes
await template-save({
  platformSlug: "fed-team",
  siteId: 4612,
  templateId: currentId,  // Use ID from step 1
  body: updatedBody
})

// 6. RE-FETCH ID immediately after save
const templatesAfterSave = await template-list({
  platformSlug: "fed-team",
  siteId: 4612,
  type: "snippet"
})
const newId = templatesAfterSave.find(t => t.name === "footer_css").id

// 7. Use NEW ID for any subsequent operations
console.log(`Template ID: ${currentId} → ${newId}`)
```

### The Golden Rule

**NEVER cache template IDs across operations.**

Always:
1. ✅ List templates
2. ✅ Get current ID
3. ✅ Perform operation
4. ✅ Re-list if doing more operations

Never:
1. ❌ Store ID and reuse later
2. ❌ Assume ID stays the same
3. ❌ Skip re-fetching after save

---

## Layout vs Template-Save Distinction

### When to Use `layout-update`

Use `layout-update` **ONLY** for layout templates:

✅ **Correct Usage**:
```typescript
// For layouts in layouts/site/*.html.liquid
await layout-update({
  platformSlug: "fed-team",
  siteId: 4612,
  templateId: 560972,  // base.html.liquid layout
  body: "<html>...</html>"
})
```

**Why**: Layout templates require special multipart/form-data handling.

### When to Use `template-save`

Use `template-save` for **everything else**:

✅ **Correct Usage**:
```typescript
// For snippets
await template-save({
  platformSlug: "fed-team",
  siteId: 4612,
  templateId: 561052,
  body: "{% snippet content %}"
})

// For CSS templates
await template-save({
  platformSlug: "fed-team",
  siteId: 4612,
  templateId: 561042,
  body: "body { margin: 0; }"
})

// For JS templates
await template-save({
  platformSlug: "fed-team",
  siteId: 4612,
  templateId: 561043,
  body: "console.log('loaded');"
})

// For error pages
await template-save({
  platformSlug: "fed-team",
  siteId: 4612,
  templateId: 560980,
  body: "<h1>404 Not Found</h1>"
})
```

### Quick Reference Table

| Template Type | Tool to Use | Example |
|---------------|-------------|---------|
| Layout (layouts/site/*.html.liquid) | `layout-update` | base.html.liquid |
| Snippet (any .liquid in shared/) | `template-save` | _footer.html.liquid |
| CSS Template (*.css.liquid) | `template-save` | root.css |
| JS Template (*.js) | `template-save` | app.js |
| Error Page (errors/*.html.liquid) | `template-save` | 404.html.liquid |
| Search Page (search/*.html.liquid) | `template-save` | index.html.liquid |

---

## Version Tracking

### Understanding Template Versions

Every template save creates a new version:

```json
{
  "id": 561052,
  "uuid": "24c13ca1-30e4-435f-8e53-27d4543b6b1f",
  "name": "footer_css",
  "status": "pending_changes",
  "versions": [
    {
      "id": 539450,
      "created_at": "2025-10-23T18:00:00.000-03:00"
    },
    {
      "id": 539451,
      "created_at": "2025-10-23T18:05:00.000-03:00"
    }
  ]
}
```

### Status Values

| Status | Meaning | Next Step |
|--------|---------|-----------|
| `draft` | Never published | Publish via release |
| `published` | Live on site | Can make changes |
| `pending_changes` | Published but has new edits | Publish to make changes live |
| `archived` | Deleted/hidden | Cannot publish |

### Version Workflow

1. **Initial Create**: Status = `draft`, Version 1
2. **First Publish**: Status = `published`, Version 1 live
3. **Make Changes**: Status = `pending_changes`, Version 2 created
4. **Publish Changes**: Status = `published`, Version 2 live

---

## Publishing Templates

### Two-Step Publishing Process

**Step 1: Get Publishable Elements**
```typescript
const elements = await release-get-elements-to-publish({
  platformSlug: "fed-team",
  siteId: 4612
})

// Response shows what can be published:
{
  "templates": [
    { "id": 561052, "name": "footer_css", "status": "pending_changes" },
    { "id": 560972, "name": "base", "status": "pending_changes" }
  ],
  "pages": [...],
  "widgets": [...],
  "menus": [...]
}
```

**Step 2: Create Release**
```typescript
await release-create({
  platformSlug: "fed-team",
  siteId: 4612,
  data: {
    template: [
      { id: 561052, selected: true },  // footer_css
      { id: 560972, selected: true }   // base layout
    ]
  }
})
```

### Publishing Related Changes Together

**Best Practice**: Publish related templates together to maintain consistency.

```typescript
// Example: Publishing footer changes
// - footer snippet (_footer.html.liquid)
// - footer CSS snippet (footer_css)
// - head snippet (_head.html.liquid) that references footer_css

await release-create({
  platformSlug: "fed-team",
  siteId: 4612,
  data: {
    template: [
      { id: 561052, selected: true },  // _footer.html.liquid
      { id: 561234, selected: true },  // footer_css
      { id: 561000, selected: true }   // _head.html.liquid
    ]
  }
})
```

### After Publishing

**CRITICAL**: Template IDs may change after publishing!

```typescript
// Before publish
const beforeId = 561052

// Publish
await release-create({ ... })

// After publish: MUST re-fetch
const templates = await template-list({ ... })
const afterId = templates.find(t => t.name === "footer_css").id

if (beforeId !== afterId) {
  console.log(`⚠️  Template ID changed: ${beforeId} → ${afterId}`)
}
```

---

## Common Pitfalls

### ❌ Pitfall 1: Caching Template ID

```typescript
// WRONG
const footerId = 561052  // Stored at beginning of session
// ... do other work ...
await template-save({ templateId: footerId, ... })  // May be stale
```

**Fix**: Always re-fetch before operations:
```typescript
// CORRECT
const templates = await template-list({ ... })
const footerId = templates.find(t => t.name === "footer_css").id
await template-save({ templateId: footerId, ... })
```

### ❌ Pitfall 2: Multiple Saves Without Re-fetching

```typescript
// WRONG
const id = 561052
await template-save({ templateId: id, body: "version 1" })
await template-save({ templateId: id, body: "version 2" })  // Stale ID
await template-save({ templateId: id, body: "version 3" })  // Stale ID
```

**Fix**: Re-fetch after each save:
```typescript
// CORRECT
let id = 561052
await template-save({ templateId: id, body: "version 1" })

// Re-fetch
const templates = await template-list({ ... })
id = templates.find(t => t.name === "footer_css").id

await template-save({ templateId: id, body: "version 2" })

// Re-fetch again
const templates2 = await template-list({ ... })
id = templates2.find(t => t.name === "footer_css").id

await template-save({ templateId: id, body: "version 3" })
```

### ❌ Pitfall 3: Using Wrong Tool for Layouts

```typescript
// WRONG - using template-save for layout
await template-save({
  templateId: 560972,  // base.html.liquid
  body: "<html>...</html>"
})
```

**Fix**: Use layout-update for layouts:
```typescript
// CORRECT
await layout-update({
  templateId: 560972,
  body: "<html>...</html>"
})
```

### ❌ Pitfall 4: Not Publishing After Changes

```typescript
// WRONG - forgot to publish
await template-save({ templateId: 561052, body: "..." })
// Changes not visible on live site!
```

**Fix**: Always publish:
```typescript
// CORRECT
await template-save({ templateId: 561052, body: "..." })

// Publish
await release-create({
  data: {
    template: [{ id: 561052, selected: true }]
  }
})
```

### ❌ Pitfall 5: Publishing Without Re-fetching ID

```typescript
// WRONG
await template-save({ templateId: 561052, body: "..." })
// ID might have changed to 561056
await release-create({
  data: {
    template: [{ id: 561052, selected: true }]  // Stale ID
  }
})
```

**Fix**: Re-fetch before publishing:
```typescript
// CORRECT
await template-save({ templateId: 561052, body: "..." })

// Re-fetch current ID
const templates = await template-list({ ... })
const currentId = templates.find(t => t.name === "footer_css").id

// Publish with current ID
await release-create({
  data: {
    template: [{ id: currentId, selected: true }]
  }
})
```

---

## Advanced Workflows

### Workflow: Editing Multiple Templates

When editing multiple related templates:

```typescript
// 1. List all templates once
const templates = await template-list({
  platformSlug: "fed-team",
  siteId: 4612
})

// 2. Get all templates to edit
const footer = templates.find(t => t.name === "_footer")
const footerCss = templates.find(t => t.name === "footer_css")
const head = templates.find(t => t.name === "_head")

// 3. Get bodies
const [footerBody, cssBody, headBody] = await Promise.all([
  template-get({ templateId: footer.id }),
  template-get({ templateId: footerCss.id }),
  template-get({ templateId: head.id })
])

// 4. Modify all bodies
const updatedFooter = modifyFooter(footerBody.body)
const updatedCss = modifyCss(cssBody.body)
const updatedHead = modifyHead(headBody.body)

// 5. Save all
await Promise.all([
  template-save({ templateId: footer.id, body: updatedFooter }),
  template-save({ templateId: footerCss.id, body: updatedCss }),
  template-save({ templateId: head.id, body: updatedHead })
])

// 6. RE-FETCH ALL IDs
const templatesAfter = await template-list({
  platformSlug: "fed-team",
  siteId: 4612
})

const newFooterId = templatesAfter.find(t => t.name === "_footer").id
const newCssId = templatesAfter.find(t => t.name === "footer_css").id
const newHeadId = templatesAfter.find(t => t.name === "_head").id

// 7. Publish all together with NEW IDs
await release-create({
  data: {
    template: [
      { id: newFooterId, selected: true },
      { id: newCssId, selected: true },
      { id: newHeadId, selected: true }
    ]
  }
})
```

### Workflow: Finding Templates by Path

When you know the path but not the ID:

```typescript
// 1. List templates
const templates = await template-list({
  platformSlug: "fed-team",
  siteId: 4612
})

// 2. Find by path
const template = templates.find(t =>
  t.path === "site/shared/general/_footer.html.liquid"
)

// 3. Use found ID
await template-save({
  templateId: template.id,
  body: "..."
})
```

### Workflow: Checking Template Status Before Publishing

```typescript
// 1. Get publishable elements
const elements = await release-get-elements-to-publish({
  platformSlug: "fed-team",
  siteId: 4612
})

// 2. Check if template needs publishing
const footerTemplate = elements.templates.find(t => t.name === "footer_css")

if (footerTemplate && footerTemplate.status === "pending_changes") {
  console.log("Footer has unpublished changes")

  // 3. Publish if needed
  await release-create({
    data: {
      template: [{ id: footerTemplate.id, selected: true }]
    }
  })
} else {
  console.log("Footer is up to date")
}
```

---

## Troubleshooting

### Issue: Changes Not Appearing After Publish

**Symptoms**:
- Saved template successfully
- Published successfully
- Changes not visible on live site

**Diagnosis**:
```typescript
// 1. Check if you published the current ID
const templates = await template-list({ ... })
const currentId = templates.find(t => t.name === "footer_css").id

// 2. Check what was published
const elements = await release-get-elements-to-publish({ ... })
const publishedId = elements.templates.find(t => t.name === "footer_css").id

if (currentId !== publishedId) {
  console.log("⚠️  Published wrong version!")
  console.log(`Current: ${currentId}, Published: ${publishedId}`)
}
```

**Solution**: Re-publish with correct ID.

### Issue: Template Save Returns Success But No Change

**Symptoms**:
- Save returns 200 OK
- No error message
- Changes don't apply

**Cause**: Saved to stale/old template ID

**Solution**: Always re-fetch ID before save:
```typescript
// Re-fetch fresh
const templates = await template-list({ ... })
const currentId = templates.find(t => t.name === "...").id

// Save with current ID
await template-save({ templateId: currentId, ... })
```

---

## Best Practices Checklist

Before any template operation:

- [ ] ✅ List templates to get current IDs
- [ ] ✅ Use correct tool (layout-update vs template-save)
- [ ] ✅ Re-fetch ID after each save
- [ ] ✅ Publish related templates together
- [ ] ✅ Re-fetch IDs after publishing
- [ ] ✅ Verify changes on live site
- [ ] ✅ Check status (draft/published/pending_changes)

---

## Related Documentation

- [CSS Organization Guide](./CSS_ORGANIZATION.md) - CSS templates vs snippets
- [Widget Workflows Guide](./WIDGET_WORKFLOWS.md) - Widget ID stability
- [Liquid Best Practices](./LIQUID_BEST_PRACTICES.md) - Liquid syntax patterns

---

**Last Updated**: October 23, 2025
**Source**: Iteration 10 findings from mcp-improvements.md
