---
title: "Knowledge vs custom pages"
description: "How ComStack tells knowledge pages from custom pages, which editor each one uses, and why using the wrong tool is refused."
url: "https://comstack.ai/docs/mcp/page-types/"
---
## What this is

ComStack has two editable page types behind the MCP tools, and picking the wrong editor is the most common first-run mistake. This page explains how the server classifies a page as `knowledge` or `custom`, which tool edits each, and the guardrails that refuse a cross-type edit. (There is a third surface — the live voice agent — but it is not edited as a page.)

## How it works

Every document exposes a `page_type` of `knowledge` or `custom`, returned on each `get-project-state` live/draft entry and on `get-page-content`. The server **derives** it — you never set `page_type` directly:

- `custom` when `metadata.type` is `"custom"` **or** the document uses the `custom-page` template.
- `knowledge` otherwise (the default).

The type maps one-to-one to an editor:

| page_type | What it is | Edit with | Body shape |
|---|---|---|---|
| `knowledge` | Markdown on a structured template (docs, blog, product, FAQ…) | `create-page` / `update-page` | Markdown in `content` |
| `custom` | Vibe-coded Astro/HTML with full layout freedom | `upload-custom-page` | Opaque `body_source` + `<T>` / `data-t-key` markers |

The guard is fail-closed in both directions:

- `update-page` on a `custom` page is rejected: *"… is a CUSTOM page (metadata.type="custom"). Edit it with upload-custom-page (body_source + `<T key=…>` markers), not update-page. update-page edits knowledge (markdown) pages only."*
- `upload-custom-page` on a `knowledge` page is rejected with error code `wrong_tool_knowledge_page`: *"… is a KNOWLEDGE (markdown) page, not a custom page. upload-custom-page would overwrite its body with opaque body_source. Edit it with update-page, or pick a different slug for the custom page."*

So read `page_type` before you choose a tool.

## When to use it

- Deciding which tool edits an existing page you were handed by URL
- Choosing a template for a new page (markdown structure vs total layout freedom)
- Diagnosing a `wrong_tool_*` rejection

## Page type vs template

`page_type` is coarse — it picks the *editor*. The **doc template** is fine-grained — it picks the *fields and structure*. A `knowledge` page still chooses a template (`technical-doc-page`, `blog-post`, `solution-page`, …), each with its own required metadata; a `custom` page always uses the `custom-page` template. List templates via `get-project-state.available_doc_templates`; inspect one with `get-doc-template`.

## Example

```text
get-page-content(project_id, slug: 'pricing', language: 'en')
  -> { page_type: 'knowledge', path: '...', metadata: { ... }, content: '## ...' }

(knowledge -> markdown editor)
update-page(project_id, slug: 'pricing', content: '## ...')        (accepted)

(the same call on a custom page is refused:)
update-page(project_id, slug: 'home-hero')
  -> InvalidRequest: 'home-hero' is a CUSTOM page (metadata.type="custom").
     Edit it with upload-custom-page ...
```

## Common errors

- **`update-page` on a custom page** — rejected with a redirect to `upload-custom-page`. Re-issue the edit as a custom-page upload, or confirm you meant a different page.
- **`upload-custom-page` on a knowledge page (`wrong_tool_knowledge_page`)** — would overwrite markdown with opaque source. Use `update-page`, or pick a new slug for the custom page.
- **Assuming `page_type` is writable** — it is derived from `metadata.type` / the template. To make a page `custom`, author it through `upload-custom-page`; you cannot flip an existing knowledge page by setting a field.

## Related

- [First-run guide](/docs/mcp/guide.md) — where page-type selection sits in the flow
- [Custom pages](/docs/custom-pages.md) — authoring vibe-coded pages end to end
- [Publishing](/docs/mcp/publishing.md) — how either page type drafts and promotes
- [Tool catalogue](/docs/mcp/tools.md) — `update-page` vs `upload-custom-page`
- [Errors](/docs/mcp/errors.md) — the wrong-tool guards in the full error list
