본문으로 건너뛰기
Strata
로그인

Strata 문서

Strata는 AI 기반 문서 편집 플랫폼입니다. MCP (Model Context Protocol)를 통한 세분화된 AI 편집을 위해 설계된 섹션 기반 문서 모델로 Markdown 또는 HTML 문서를 업로드하여 조회, 댓글 및 편집할 수 있습니다.

설정

빠른 시작

AI 클라이언트를 Strata의 MCP 서버에 연결하여 문서를 읽고, 편집하고, 검색하고, 관리하세요. 대부분의 클라이언트는 OAuth를 자동으로 처리합니다 — 서버 URL만 제공하면 됩니다.

연결 정보

MCP 서버 URL
https://api.strata.space/mcp
인증
OAuth 2.1 with Dynamic Client Registration
사용 가능한 도구
app_get_section_content, browse_connector_resources, edit_document, export_presentation, find, get_agent_status, get_company_theme, get_document_graph, get_image, get_presence, get_publish_status, invoke_agent, invoke_connector_action, list_company_themes, list_connected_tools, manage_comments, manage_suggestions, publish_document, read_document, unpublish_document, validate_presentation
연동

클라이언트 설정

Claude Code를 사용하고 계신가요? Strata 플러그인이 가장 빠른 방법입니다. 명령어 하나로 MCP 서버를 등록하고 Spaces 스킬을 추가합니다.

Claude Desktop

claude_desktop_config.json에 추가하세요:

json
{
  "mcpServers": {
    "strata": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://api.strata.space/mcp"
      ]
    }
  }
}

OAuth 인증은 자동으로 처리됩니다 — 처음 사용 시 로그인이 요청됩니다.

Claude Code

CLI를 통해 Strata MCP 서버를 추가하세요:

bash
claude mcp add strata https://api.strata.space/mcp

OAuth 인증은 브라우저를 통해 자동으로 처리됩니다.

Cursor

~/.cursor/mcp.json 또는 .cursor/mcp.json에 추가하세요:

json
{
  "mcpServers": {
    "strata": {
      "url": "https://api.strata.space/mcp"
    }
  }
}

Cursor는 서버가 401을 반환할 때 자동으로 OAuth를 처리합니다.

VS Code (Copilot)

프로젝트의 .vscode/mcp.json에 추가하세요:

json
{
  "servers": {
    "strata": {
      "type": "http",
      "url": "https://api.strata.space/mcp"
    }
  }
}

VS Code 1.101+ 필요. "servers"("mcpServers" 아님)와 타입 "http"를 사용합니다. PKCE 및 동적 클라이언트 등록이 포함된 OAuth가 자동으로 처리됩니다.

Windsurf

~/.codeium/windsurf/mcp_config.json에 추가하세요:

json
{
  "mcpServers": {
    "strata": {
      "serverUrl": "https://api.strata.space/mcp"
    }
  }
}

Windsurf는 url 대신 serverUrl을 사용합니다. OAuth는 자동으로 처리됩니다.

Cline

Cline에서 MCP 서버 패널을 열고 설정에 추가하세요:

json
{
  "mcpServers": {
    "strata": {
      "url": "https://api.strata.space/mcp",
      "type": "streamableHttp"
    }
  }
}

"streamableHttp"(camelCase)를 사용합니다. OAuth가 필요할 때 Cline이 인증 버튼을 표시합니다.

Continue

~/.continue/config.yaml에 추가하세요:

yaml
mcpServers:
  - name: strata
    command: npx
    args:
      - "-y"
      - "mcp-remote"
      - "https://api.strata.space/mcp"

Continue는 아직 OAuth를 기본적으로 지원하지 않습니다. 대신 mcp-remote 브리지를 사용하세요 (아래 참조).

Zed

Zed의 settings.json에 추가하세요:

json
{
  "context_servers": {
    "strata": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://api.strata.space/mcp"
      ]
    }
  }
}

Zed는 OAuth를 기본적으로 지원하지 않습니다. 브라우저에서 OAuth 플로우를 처리하는 stdio 브리지로 mcp-remote를 사용합니다.

연동

Claude.ai와 ChatGPT

이 채팅 제품들은 Strata 에디터를 인라인으로 렌더링합니다. 위의 MCP 서버 URL을 호스트의 커넥터 설정에 추가하세요.

Claude.ai

설정 → 커넥터 → 사용자 지정 커넥터 추가

유료 플랜에서 이용 가능합니다. 조직 커넥터는 소유자가 추가합니다.

ChatGPT

설정 → 커넥터 → 만들기

개발자 모드(설정 → 앱 및 커넥터 → 고급)가 필요합니다. Plus, Pro 또는 Enterprise 플랜 전용입니다.

대안

범용 대안 (mcp-remote)

기본 OAuth 지원이 없는 클라이언트의 경우, mcp-remote를 stdio 브리지로 사용하세요. 전체 OAuth 플로우를 처리하며 모든 MCP 클라이언트와 호환됩니다:

json
{
  "mcpServers": {
    "strata": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://api.strata.space/mcp"
      ]
    }
  }
}

인증 상태가 ~/.mcp-auth/에 저장되어 서버당 한 번만 인증하면 됩니다.

참조

다음 단계

사용 가능한 모든 도구와 매개변수에 대한 전체 문서는 MCP 도구 참고를 확인하세요.

참조

블로그 디자인

첫 번째 YAML 프런트매터 블록에 blog: 매핑을 추가하여 게시된 글을 디자인합니다. 모양 패널도 같은 텍스트를 편집하며 다른 키와 주석은 보존합니다.

미리보기는 초안을 반영합니다. 게시하면 게시 테마에서 상속한 기본값을 포함한 전체 디자인이 저장됩니다. 이후 초안이나 프로필 테마를 바꿔도 해당 버전은 변경되지 않습니다. 프레젠테이션은 별도 설정을 사용합니다. 프런트매터는 공개 페이지와 설명에 표시되지 않습니다.

blog:의 알 수 없는 키, 잘못된 YAML, 유효하지 않은 값, 누락되거나 이름이 중복된 참조, 부족한 대비가 있으면 게시할 수 없습니다. 모든 오류를 수정하세요. 에이전트 편집은 blogValidation 결과를 반환합니다. 설정을 초기화하면 기본값을 상속합니다. 기본적으로 목차는 숨겨지고 읽기 영역은 불투명합니다.

요약은 최대 160자이며 태그는 각각 32자로 최대 10개입니다. 시리즈 이름은 최대 80자이고 순서는 양의 정수여야 합니다. 이름이 정확히 같은 글끼리 묶이며 중복 순서는 경고를 표시합니다. noindex는 프로필과 피드에는 글을 유지하지만 사이트맵에서 제외하고 검색 엔진에 색인하지 않도록 요청합니다. cover는 문서 안의 이미지 이름입니다. 이미지 바로 앞에 <!-- strata:name=cover -->를 넣어 이름을 지정합니다.

색상은 밝은 모드와 어두운 모드에 각각 따옴표로 감싼 #RRGGBB 값을 지정해야 합니다. background는 읽기 영역을, 배경 화면이 없으면 페이지도 채색합니다. 본문과 accent 링크는 두 모드 모두 실제 읽기 영역과 4.5:1 이상의 대비를 충족해야 합니다. 글꼴은 아래 목록에서 선택합니다. 반투명 읽기 영역은 불투명도 88%이며 단색 또는 그라데이션 전체에서 충분한 대비를 확보할 때만 사용할 수 있습니다.

배경 종류는 하나만 선택합니다. 그라데이션은 2~5개 색상을 허용하며 패턴은 아래 이름을 사용합니다. 이미지 배경은 문서의 이미지 이름을 지정합니다. HTML 배경은 html 코드 블록 이름을 지정하며 정적 대체 색상이나 이미지가 필요합니다. 기존 샌드박스에서 글 뒤에 실행되고 클릭이나 포커스를 받지 않으며 탭이 숨겨지면 멈춥니다. 동작 또는 데이터 줄이기, 성능이 제한된 기기, HTML 미리보기 비활성화, 오류가 있으면 대체 배경을 사용합니다. 인쇄와 PDF에서는 배경을 제외합니다. 페이지에 직접 HTML 또는 CSS를 적용하거나 글 전체를 HTML로 구성하는 방식은 지원하지 않습니다.

uses="frontmatter"를 선언한 HTML 블록은 strata.data.get("frontmatter").values를 읽습니다. 해석된 디자인 키는 blog.typography, blog.palette, blog.readingWidth, blog.blockControls, blog.tableOfContents, blog.readingSurface, blog.accent, blog.background, blog.fonts.heading, blog.fonts.body입니다. 색상은 현재 모드에 맞게 정해지고 미지정 글꼴은 생략됩니다. 공개 블록에는 이 디자인 값만 전달되며 다른 스칼라 메타데이터는 편집기에서만 사용할 수 있습니다. 배경에는 이 값과 색상 모드만 전달되고 다른 문서 데이터는 전달되지 않습니다.

필드와 허용 값

blog.typography
modern | editorial | expressive | technical
blog.palette
strata | paper
blog.readingWidth
focused | comfortable | wide | full
blog.blockControls
visible | hidden
blog.tableOfContents
visible | hidden
blog.accent
{ light: "#RRGGBB", dark: "#RRGGBB" }
blog.background
{ light: "#RRGGBB", dark: "#RRGGBB" }
blog.fonts.heading, blog.fonts.body
Manrope | Syne | Fira Code | Georgia | Times New Roman | Arial | Helvetica | Verdana | Trebuchet MS | Palatino | Courier New | IBM Plex Mono
blog.summary
string (1…160)
blog.cover
image.name
blog.tags
string[] (0…10 × 1…32)
blog.noindex
true | false
blog.series
{ name: string (1…80), order: integer (≥1) }
blog.wallpaper.color
{ light: "#RRGGBB", dark: "#RRGGBB" }
blog.wallpaper.gradient
{ type: linear | radial, stops: [{ light: "#RRGGBB", dark: "#RRGGBB" }, …] } (2…5)
blog.wallpaper.pattern
{ name: dots | grid | lines | paper | topographic | stars, tint: { light: "#RRGGBB", dark: "#RRGGBB" } }
blog.wallpaper.image
image.name
blog.wallpaper.html
codeBlock.name (language: html)
blog.wallpaper.fallback
{ color: { light: "#RRGGBB", dark: "#RRGGBB" } } | { image: image.name }
blog.readingSurface
opaque | translucent

완전한 HTML 배경 예제

markdown
---
blog:
  typography: editorial
  palette: paper
  readingWidth: comfortable
  blockControls: hidden
  tableOfContents: visible
  accent: { light: "#8a3515", dark: "#ffb788" }
  background: { light: "#fffdf8", dark: "#272119" }
  fonts: { heading: Georgia, body: Georgia }
  summary: "An astronomy journal about the night sky."
  tags: [astronomy, observation]
  noindex: false
  series: { name: "Night notes", order: 1 }
  readingSurface: opaque
  wallpaper:
    html: starfield
    fallback:
      color: { light: "#e7e0d4", dark: "#111827" }
---

# Night notes

Our first observing session began at twilight.

## The northern sky

The article stays on an opaque reading surface above the animation.

```html name=starfield uses="frontmatter"
<style>
  html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; }
  canvas { display: block; width: 100%; height: 100%; }
</style>
<canvas id="sky"></canvas>
<script>
  const canvas = document.getElementById('sky');
  const ctx = canvas.getContext('2d');
  let color = '#8a3515';
  function readDesign() {
    const source = strata.data.get('frontmatter');
    if (source?.kind === 'frontmatter') color = source.values['blog.accent'];
  }
  readDesign();
  window.addEventListener('strata:data', readDesign);
  function paint(time) {
    const width = canvas.clientWidth, height = canvas.clientHeight;
    if (canvas.width !== width || canvas.height !== height) {
      canvas.width = width;
      canvas.height = height;
    }
    ctx.clearRect(0, 0, width, height);
    ctx.fillStyle = color;
    for (let i = 0; i < 90; i++) {
      ctx.globalAlpha = 0.25 + 0.25 * Math.sin(time / 1800 + i);
      ctx.beginPath();
      ctx.arc((i * 137.508 % 100) / 100 * width,
        (i * 71.37 % 100) / 100 * height, 1 + i % 2, 0, Math.PI * 2);
      ctx.fill();
    }
    requestAnimationFrame(paint);
  }
  requestAnimationFrame(paint);
</script>
```
참조

인터랙티브 HTML 블록

html 태그가 지정된 코드 블록은 Strata 편집기와 내보낸 PDF에서 라이브 샌드박스 미리보기로 렌더링됩니다. 차트, 다이어그램, 3D 장면, 작은 인터랙티브 위젯을 일반적인 펜스 코드로 작성할 수 있습니다.

html 언어 태그를 붙인 펜스 코드 블록을 작성하세요. 마크업, 스타일, 스크립트는 격리된 미리보기에서 자동으로 실행됩니다. 편집할 때마다 깨끗한 상태에서 다시 렌더링되며, 독자는 미리보기와 소스를 전환해서 볼 수 있습니다.

미리보기는 완전히 격리되어 있습니다. 쿠키나 스토리지를 사용할 수 없고, 주변 페이지에 접근하거나 외부 URL을 쓸 수도 없습니다. WebSocket, 비콘, 폼 전송은 아예 제거되며 fetch는 아래에 나열된 검증된 /sandbox/ 자산에만 도달합니다. Doom 엔진은 이 경로로 자체 게임 데이터를 불러옵니다. 이러한 제약을 위반하는 것은 해당 미리보기 안에서만 실패하며 다른 곳에는 영향을 주지 않습니다.

Strata 디자인 토큰이 미리 로드되어 있습니다. var(--color-foreground), var(--color-muted-foreground), var(--color-primary), var(--color-border) 같은 CSS 변수는 앱 테마와 일치하며, 미리보기는 보는 사람의 라이트 또는 다크 모드를 자동으로 따라갑니다. 직접 지정한 색상은 작성한 그대로 사용되며 절대 조정되지 않으므로, 배경색과 글자색을 항상 함께 지정하세요. 둘 중 하나만 지정한 블록은 테스트하지 않은 모드에서 읽을 수 없게 될 수 있습니다.

미리보기는 높이 약 360 픽셀에서 시작한 뒤 내용에 따라 달라집니다. 내용이 길면 블록이 커지고 짧으면 줄어듭니다. 이 시작 높이는 상대 단위를 계산하는 기준이기도 하므로 height: 100%, 100vh, window.innerHeight를 모두 사용할 수 있습니다. three.js 장면이나 블록 전체를 채우는 차트에서 흔히 쓰는 방식입니다.

스크립트 오류, 처리되지 않은 프로미스 거부, 미리보기 내부에서 나온 console.error/console.warn 출력이 수집되어 미리보기 아래에 표시되며, 브라우저가 알려주는 경우 줄 번호도 함께 표시됩니다. 미리보기에는 자체 개발자 도구가 없으므로 블록이 렌더링되지 않은 이유는 이 패널에서 확인합니다.

문서 데이터로 차트 만들기

블록은 같은 문서 안에 이미 있는 데이터를 읽을 수 있으므로, 차트는 독자가 보는 숫자와 계속 일치합니다. 이름을 붙일 수 있는 소스는 네 종류입니다. json, csv, tsv, yaml 코드 블록은 자신의 시작 줄에서 name=sales처럼 이름을 붙입니다. 표는 바로 위 줄에 놓인 HTML 주석 <!-- strata:name=headcount -->로 이름을 붙입니다. 문서의 frontmatter는 예약된 이름 frontmatter로 항상 사용할 수 있으며 스칼라 필드만 전달됩니다. 이미지는 표와 마찬가지로 바로 위 줄에 놓인 HTML 주석 <!-- strata:name=hero -->로 이름을 붙입니다. 편집기에서는 이미지를 선택하고 데이터 이름 추가를 사용합니다. 블록이 바인딩할 수 있는 데이터는 이 네 종류뿐입니다. 이름은 영문자로 시작하고 영문자, 숫자, 하이픈, 밑줄이 이어지며 최대 64자이고 문서 안에서 고유해야 합니다.

html 블록은 자신의 시작 줄에서 uses="sales,headcount"처럼 사용할 소스를 선언합니다. 블록은 선언한 소스만 받고 문서의 나머지는 받지 않으며, 다른 문서의 데이터에는 접근할 수 없고 독자가 이 문서에서 이미 볼 수 없는 내용은 전달되지 않습니다. 블록의 코드나 선언을 수정하면 미리보기가 깨끗한 상태에서 다시 로드됩니다. 이미 선언한 이름 뒤의 데이터만 수정하면 실행 중인 미리보기가 그 자리에서 갱신됩니다. 한 블록이 선언할 수 있는 이름은 최대 여덟 개이며, 아홉 번째부터는 조용히 버려지지 않고 이유가 oversize인 unavailable로 전달됩니다.

미리보기 안에서 선언된 데이터는 사용자의 스크립트가 실행되기 전에 strata.data로 준비됩니다. strata.data.get(name)은 소스 하나를 반환하고, strata.data.names는 블록이 선언한 이름을 선언 순서대로 나열합니다. json, csv, tsv, yaml 소스는 파싱되지 않은 채 { kind: 'text', format, text } 형태로 전달되므로 블록이 원하는 파서로 직접 해석합니다. 표는 { kind: 'table', columns, rows } 형태로 전달되며 각 셀은 숫자나 날짜로 변환되지 않은 일반 텍스트입니다. frontmatter는 { kind: 'frontmatter', values } 형태로 전달됩니다. 전달된 값은 모두 깊게 동결되어 있습니다. 바인딩된 소스가 바뀌면 Strata가 새 스냅샷을 보내고 window에서 strata:data 이벤트를 발생시키며, detail에 새 데이터가 담깁니다. 이벤트가 발생하는 시점에 strata.data.get은 이미 그 스냅샷을 반환합니다. 미리보기가 스스로 데이터를 요청하는 일은 없으므로, 이벤트를 무시하는 블록은 처음 받은 데이터로 계속 동작합니다.

이미지는 { kind: 'image', url, width, height, alt } 형태로 전달됩니다. url은 이미지 자체의 바이트를 담은 데이터 URL이므로 블록은 네트워크 접근 없이 img 요소에 그대로 할당할 수 있습니다. Strata는 독자 본인의 권한으로 그 바이트를 가져와 미리보기가 시작되기 전에 인라인합니다. 미리보기는 따라갈 수 있는 링크를 보지 않고 직접 이미지를 요청하지도 않습니다. 이미지에는 별도 한도가 있어, 이미지 하나는 최대 3 MiB, 한 미리보기의 이미지 합계는 최대 12 MiB이며 한도를 넘으면 큰 것부터 제외됩니다. 바이트를 가져오지 못한 이미지는 이유가 unreachable인 unavailable로 전달됩니다. 프레젠테이션은 코드 없이도 이름이 붙은 이미지를 보여줄 수 있습니다. layout=image uses="hero"로 쓴 슬라이드 시작 줄이 이미지를 꺽 차게 그리고 본문에서 캐션을 읽습니다.

어떤 종류를 고를지는 그 숫자를 누가 또 읽는지에 달려 있습니다. json이나 csv 코드 블록은 간결하고 버전 간 비교가 깔끔하며 긴 계열을 본문 밖에 둘 수 있지만, 원시 텍스트로 전달되므로 파싱은 블록의 몫입니다. csv 줄을 쉼표로 나누는 것은 전형적인 실수인데, 쉼표가 들어 있는 따옴표 필드가 잘려 나가기 때문입니다. 이름을 붙인 표는 반대의 선택입니다. 독자는 코드 블록 대신 진짜 표를 보고, 블록은 첫 줄이 columns, 그 아래 줄이 rows로 이미 나뉜 상태로 받습니다. frontmatter는 제목이나 목표처럼 값 하나에 어울리며 계열에는 맞지 않습니다.

해결되지 않은 선언 이름도 { kind: 'unavailable', reason } 형태로 전달되므로 비어 있는 데이터와 없는 데이터를 구분할 수 있습니다. 이유는 문서에 그 이름을 가진 소스가 없으면 unknown, 두 소스가 같은 이름을 주장하면 duplicate, 미리보기가 열려 있는 동안 소스가 삭제되면 removed, 소스가 전달 한도를 넘으면 oversize, 이미지의 바이트를 가져오지 못하면 unreachable입니다. 문제가 된 소스만 제외되고 나머지는 계속 전달되므로, 데이터가 있다고 가정하지 말고 unavailable 종류를 확인해 메시지를 표시하십시오.

검증된 라이브러리

  • /sandbox/libs/mermaid.min.js — <script src="/sandbox/libs/mermaid.min.js"></script> then mermaid.initialize({ startOnLoad: false }); mermaid.run()
  • /sandbox/libs/d3.min.js — <script src="/sandbox/libs/d3.min.js"></script> — global `d3`
  • /sandbox/libs/three.module.min.js — <script type="module">import * as THREE from '/sandbox/libs/three.module.min.js'</script>
  • /sandbox/libs/doom.js — <script src="/sandbox/libs/doom.js"></script> is the whole block: it appends its own canvas and boots. Options go on the script tag: data-doom-warp="1,1", data-doom-skill="3", data-doom-manual (call Doom.start() yourself). To place the canvas, supply one with id="canvas". The reader clicks the preview once to give it keyboard focus; arrows move, Ctrl fires, Esc opens the menu. Music is off, sound effects work. First load pulls about 10 MB, then caches. Chocolate Doom compiled to WebAssembly (GPL-2.0-or-later, github.com/cloudflare/doom-wasm) with Freedoom game data (BSD-3-Clause, github.com/freedoom/freedoom). No commercial or shareware WAD is distributed.

이 밖의 외부 스크립트나 스타일 URL은 미리보기 안에서 로드되지 않습니다. 버전을 고정하려면 .min.js 앞에 -<version>을 삽입하세요(이전 버전도 계속 사용할 수 있습니다).

예시

html
<div id="chart"></div>
<script src="/sandbox/libs/d3.min.js"></script>
<script>
  const data = [4, 8, 15, 16, 23, 42];
  d3.select('#chart')
    .selectAll('div')
    .data(data)
    .join('div')
    .style('height', '18px')
    .style('margin', '2px 0')
    .style('background', 'var(--color-primary, #2c7cb0)')
    .style('width', (d) => d * 6 + 'px');
</script>

예시: json 코드 블록에 바인딩된 차트

markdown
```json name=sales
[
  { "quarter": "Q1", "revenue": 42 },
  { "quarter": "Q2", "revenue": 58 },
  { "quarter": "Q3", "revenue": 71 }
]
```

```html uses="sales"
<div id="chart"></div>
<script src="/sandbox/libs/d3.min.js"></script>
<script>
  function render() {
    const source = strata.data.get('sales');
    if (!source || source.kind !== 'text') return;
    d3.select('#chart')
      .selectAll('div')
      .data(JSON.parse(source.text))
      .join('div')
      .style('height', '18px')
      .style('margin', '2px 0')
      .style('background', 'var(--color-primary, #2c7cb0)')
      .style('width', (d) => d.revenue * 6 + 'px');
  }
  render();
  window.addEventListener('strata:data', render);
</script>
```

예시: csv 코드 블록에 바인딩된 차트

markdown
```csv name=signups
week,signups
"Jan 1, 2026",120
"Jan 8, 2026",148
"Jan 15, 2026",173
"Jan 22, 2026",162
```

```html uses="signups"
<div id="chart"></div>
<script src="/sandbox/libs/d3.min.js"></script>
<script>
  function render() {
    const chart = d3.select('#chart');
    chart.selectAll('*').remove();
    const source = strata.data.get('signups');
    if (!source || source.kind !== 'text') {
      chart.text('No signups data.');
      return;
    }
    // A csv source arrives as raw text. text.split(',') would tear
    // "Jan 1, 2026" in half; d3.csvParse honours the quotes.
    const rows = d3.csvParse(source.text, (row) => ({
      week: row.week,
      signups: Number(row.signups),
    }));
    const scale = d3
      .scaleLinear()
      .domain([0, Math.max(1, d3.max(rows, (d) => d.signups) || 0)])
      .range([0, 100]);
    const line = chart.selectAll('div').data(rows).join('div');
    line
      .style('display', 'flex')
      .style('align-items', 'center')
      .style('gap', '8px')
      .style('margin', '2px 0');
    line
      .append('span')
      .style('flex', '0 0 7rem')
      .style('color', 'var(--color-muted-foreground, #6b7280)')
      .text((d) => d.week);
    line
      .append('span')
      .style('height', '18px')
      .style('background', 'var(--color-primary, #2c7cb0)')
      .style('width', (d) => scale(d.signups) + '%');
    line.append('span').text((d) => d.signups);
  }
  render();
  // Edit a number in the csv block and this chart follows it.
  window.addEventListener('strata:data', render);
</script>
```

예시: 문서 표에 바인딩된 차트

markdown
<!-- strata:name=headcount -->

| Team | People |
| --- | --- |
| Growth | 12 |
| Platform | 27 |
| Support | 8 |

```html uses="headcount"
<div id="chart"></div>
<script>
  function render() {
    const chart = document.getElementById('chart');
    chart.textContent = '';
    const source = strata.data.get('headcount');
    if (!source || source.kind !== 'table') {
      chart.textContent = 'No headcount table.';
      return;
    }
    // columns is the table's first row; rows is everything under it, and
    // every cell is a string, so the numbers are yours to convert.
    const team = source.columns.indexOf('Team');
    const people = source.columns.indexOf('People');
    const counts = source.rows.map((row) => Number(row[people]) || 0);
    const widest = Math.max(1, ...counts);
    source.rows.forEach((row, index) => {
      const line = document.createElement('div');
      line.style.display = 'flex';
      line.style.alignItems = 'center';
      line.style.gap = '8px';
      line.style.margin = '2px 0';
      const label = document.createElement('span');
      label.style.flex = '0 0 7rem';
      label.style.color = 'var(--color-muted-foreground, #6b7280)';
      label.textContent = row[team];
      const bar = document.createElement('span');
      bar.style.height = '18px';
      bar.style.width = (counts[index] / widest) * 100 + '%';
      bar.style.background = 'var(--color-primary, #2c7cb0)';
      const value = document.createElement('span');
      value.textContent = row[people];
      line.append(label, bar, value);
      chart.append(line);
    });
  }
  render();
  // Type a new number into the table and this chart follows it.
  window.addEventListener('strata:data', render);
</script>
```

예: 문서의 이미지에 바인딩한 이미지

markdown
<!-- strata:name=hero -->

![The team on launch day](strata://image/img_01ARZ3NDEKTSV4RRFFQ69G5FAV)

```html uses="hero"
<figure id="card" style="margin:0"></figure>
<script>
  function render() {
    const card = document.getElementById('card');
    card.textContent = '';
    const source = strata.data.get('hero');
    if (!source || source.kind !== 'image') {
      card.textContent = 'No hero image.';
      return;
    }
    const image = document.createElement('img');
    // url already carries the bytes, so this needs no network access.
    image.src = source.url;
    image.alt = source.alt;
    image.style.width = '100%';
    image.style.borderRadius = '12px';
    const caption = document.createElement('figcaption');
    caption.style.color = 'var(--color-muted-foreground, #6b7280)';
    caption.textContent = source.width + '×' + source.height;
    card.append(image, caption);
  }
  render();
  // Swap the image in the document and this card follows it.
  window.addEventListener('strata:data', render);
</script>
```
참조

에이전트 프론트매터

에이전트 정의는 /Agents 폴더 아래에 있는 Markdown 문서입니다. YAML 프론트매터는 에이전트의 식별자, 도구 허용 목록, 오케스트레이터 노출 여부를 선언하고, 프론트매터 아래의 본문은 오케스트레이터가 사용자의 요청을 그대로 전달하는 시스템 프롬프트입니다. 모든 필드는 저장 시 서버에서 검증됩니다.

에이전트 프론트매터 필드
필드타입필수 여부기본값설명
autoInvokableboolean선택falsetrue인 경우, 설명이 사용자의 요청과 일치하면 채팅 오케스트레이터가 이 에이전트를 스스로 선택할 수 있습니다. false(기본값)인 경우에는 명시적 호출(@mention, MCP invoke_agent, 연결된 소스)에서만 실행됩니다.
connectorAccountsobject선택—Owner's personal account selected for each connector kind.
descriptionstring필수—이 에이전트를 언제 사용해야 하는지 한 문장으로 요약. 오케스트레이터의 자동 호출 카탈로그와 @mention 선택기에 노출되므로 에이전트의 역할을 구체적으로 적어 주세요.
enabledboolean선택true마스터 스위치. false인 경우, 프론트매터가 그 외에는 유효하더라도 모든 호출 표면에서 에이전트가 숨겨집니다.
modelstring선택—에이전트가 실행되는 모델을 재정의하는 선택 항목. 생략하면 플랫폼 기본 모델이 사용됩니다. 플랫폼 모델 레지스트리에서 해석 가능해야 합니다.
namestring필수—kebab-case 식별자 ([a-z0-9-])이며, 본인의 에이전트 중에서 고유하고 플랫폼에 예약된 에이전트 이름과 충돌하지 않아야 합니다. 채팅의 @mention 토큰과 MCP invoke_agent의 agentName 인수를 결정합니다.
pinnedResourcesPinnedResourceSpec[]선택—External resources pinned to this agent as standing knowledge. A compact manifest is injected into every run and the bodies are fetched live with the owner's connector grant. Omit or pass an empty list for no pinned knowledge.
toolsstring[]선택[]에이전트가 호출할 수 있는 플랫폼 도구의 허용 목록 (예: read_document, search_space). 에이전트 배너의 "사용 가능한 도구" 패널에서 유효한 이름을 모두 확인할 수 있습니다. 도구를 부여하지 않으려면 비워두거나 생략하세요.

예시

markdown
---
name: meeting-notes-summarizer
description: Summarizes meeting notes into a TL;DR with action items.
tools:
  - read_document
  - search_space
model: claude-sonnet-4-6
color: emerald
enabled: true
autoInvokable: false
---

You are a meeting-notes summarizer. Given the document body the
orchestrator hands you verbatim, produce a one-paragraph TL;DR and a
bulleted action-item list…
참조

프롬프트 프론트매터

프롬프트 템플릿은 /Prompts 폴더 아래에 있는 Markdown 문서입니다. YAML 프론트매터는 이름·설명·인수·오케스트레이터 노출 여부를 선언하고, 프론트매터 아래의 본문이 프롬프트 템플릿이며 {{argument}} 자리표시자는 렌더링 시점에 치환됩니다. 인수 값은 채팅 작성기의 슬래시 시트나 MCP prompts/get 요청을 통해 수집됩니다.

프롬프트 프론트매터 필드
필드타입필수 여부기본값설명
argumentsPromptArgument[]선택[]프롬프트 본문이 `{{name}}` 자리표시자로 참조하는 `PromptArgument` 항목의 정렬된 목록입니다. 슬래시 선택기가 작성자가 지정한 순서대로 필드를 표시할 수 있도록 와이어에서 순서가 보존됩니다. 최대 16개 항목.
autoInvokableboolean선택falsetrue인 경우, 설명이 사용자의 의도와 일치하면 채팅 오케스트레이터가 이 프롬프트를 스스로 선택할 수 있습니다. false(기본값)인 경우에는 사용자가 슬래시 토큰을 입력하거나 클라이언트가 MCP prompts/get을 호출했을 때에만 실행됩니다.
descriptionstring필수—프롬프트가 하는 일을 한 문장으로 요약. 슬래시 메뉴, MCP prompts/list, 그리고 autoInvokable: true일 때는 오케스트레이터의 도구 카탈로그에도 노출됩니다.
namestring필수—사람이 읽을 수 있는 프롬프트 제목. 슬러그화된 형태가 채팅 작성기의 슬래시 메뉴에 표시되는 /prompt:<slug> 토큰이 됩니다.

PromptArgument

위 `arguments` 배열의 각 항목은 다음과 같은 형태를 가집니다:

PromptArgument 필드
필드타입필수 여부기본값설명
descriptionstring필수—Short human-readable description shown in the slash-picker argument sheet, the MCP `prompts/list` payload, and the `loadUserPrompt` catalog so the user (or the model) knows what to fill in. 1-200 chars.
namestring필수—Identifier matched verbatim against the body's `{{name}}` placeholders. Matching is case-sensitive — `{{Focus}}` and `{{focus}}` are distinct placeholders. Restricted to ASCII letters, digits, and underscores (1-48 chars) so the same identifier is valid in YAML and the placeholder grammar.
requiredboolean선택falseWhen true, the slash-picker argument sheet blocks submit until a value is supplied; the `loadUserPrompt` catalog also flags it so the model knows it must ask the user to clarify. When false (default), an omitted argument substitutes the empty string into its placeholders at render time.

예시

markdown
---
name: Summarize document
description: Summarize the active document for a chosen audience.
autoInvokable: false
arguments:
  - name: focus
    description: What the assistant should focus on.
    required: true
  - name: audience
    description: Target audience for the summary.
    required: false
---

Summarize this document for {{audience}}, focusing on {{focus}}. Keep
the summary under 200 words and finish with a short action-items list.
참조

템플릿 프런트매터

문서 템플릿은 템플릿 폴더 안의 Markdown 문서입니다. YAML 프런트매터는 템플릿의 이름, 형식이 지정된 변수, 섹션 구성을 선언하며, 프런트매터 아래의 본문이 재사용되는 콘텐츠입니다. {{key}} 자리표시자는 갤러리, MCP createFromTemplate 액션 또는 에이전트의 create_document_from_template 도구로 문서를 만들 때 치환됩니다.

템플릿 프런트매터 필드
필드타입필수 여부기본값설명
descriptionstring필수—Sentence describing when to use this template. Surfaces in the gallery and in tool catalogs, so be specific about the document shape it produces.
namestring필수—Kebab-case identifier, unique among the templates in the same folder. Shown in the gallery alongside the document title.
sectionsTemplateSection[]선택[]Section contract: what a conforming instance must contain. Maximum 64 entries. Empty when the template declares no section structure.
variablesTemplateVariable[]선택[]Typed placeholders substituted at instantiation. Order is preserved across the wire so fill-in forms render fields in the author's chosen order. Maximum 16 entries. Empty when the template takes no variables.

TemplateVariable

위 `variables` 배열의 각 항목은 다음 형식을 가집니다:

TemplateVariable 필드
필드타입필수 여부기본값설명
keystring필수—Identifier matched verbatim against the body's `{{key}}` placeholders. Matching is case-sensitive. Restricted to ASCII letters, digits, and underscores (1-64 chars) so the same identifier is valid in YAML and the placeholder grammar.
kindunknown선택"text"Input kind. Defaults to free text.
labelstring필수—Human-readable label shown on the fill-in form. 1-80 chars.
requiredboolean선택falseWhen true, instantiation fails unless a value is supplied. When false (default), an omitted variable substitutes the empty string into its placeholders.

TemplateSection

위 `sections` 배열의 각 항목은 다음 형식을 가집니다:

TemplateSection 필드
필드타입필수 여부기본값설명
fillunknown선택"required"Fill discipline for the section. Defaults to required.
guidancestring선택""Instructions for whoever (or whatever) fills the section in. Optional; shown alongside the section in fill-in surfaces.
titlestring필수—Section title. Matches a heading in the template body verbatim.

예시

markdown
---
name: incident-postmortem
description: Standard postmortem with a verbatim escalation matrix.
variables:
  - key: incident_id
    label: Incident ID
    kind: text
    required: true
  - key: occurred_on
    label: Date of incident
    kind: date
    required: true
sections:
  - title: Timeline
    guidance: Chronological events from first alert to resolution.
    fill: required
  - title: Lessons learned
    guidance: What we change going forward.
    fill: optional
  - title: Escalation matrix
    fill: verbatim
---

## Timeline

Incident {{incident_id}} on {{occurred_on}}.

## Lessons learned

## Escalation matrix

Page the on-call lead, then the service owner…