stitch-sdk-domain-design
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseStitch SDK Domain Design
Stitch SDK 领域设计
This skill teaches you how to perform Stage 2 of the generation pipeline: reading tool schemas and producing — the intermediate representation that drives codegen.
domain-map.json本技能将教你如何执行生成流水线的第2阶段:读取工具Schema并生成——这是驱动代码生成(codegen)的中间表示。
domain-map.jsonYour Inputs
你的输入
- — raw MCP tool schemas captured from the server (includes
tools-manifest.json)outputSchema - — Zod schema defining valid domain-map structure (the canonical contract)
ir-schema.ts - Existing — the current IR (if extending, not starting fresh)
domain-map.json - The skill — for understanding the pipeline context
stitch-sdk-development
- —— 从服务器捕获的原始MCP工具Schema(包含
tools-manifest.json)outputSchema - —— 定义有效domain-map结构的Zod Schema(标准契约)
ir-schema.ts - 现有—— 当前的中间表示(IR)(如果是扩展而非从零开始)
domain-map.json - 技能 —— 用于理解流水线上下文
stitch-sdk-development
Your Output
你的输出
A valid with two sections: and , validated by .
domain-map.jsonclassesbindingsir-schema.ts[!IMPORTANT] Your output is validated twice by the codegen: structurally (Zod IR schema) and semantically (projection steps verified againstfrom the tools-manifest).outputSchema
一个有效的,包含和两个部分,并通过验证。
domain-map.jsonclassesbindingsir-schema.ts[!IMPORTANT] 你的输出会被代码生成工具两次验证:结构验证(通过Zod IR Schema)和语义验证(投影步骤与tools-manifest中的进行校验)。outputSchema
Designing Classes
设计领域类
Each class represents a domain entity. Ask: "What noun does the user interact with?"
json
{
"Stitch": {
"description": "Main entry point. Manages projects.",
"constructorParams": [],
"isRoot": true,
"factories": [
{ "method": "project", "returns": "Project", "description": "Create a Project handle from an ID." }
]
}
}每个类代表一个领域实体。思考:“用户会与哪个名词交互?”
json
{
"Stitch": {
"description": "Main entry point. Manages projects.",
"constructorParams": [],
"isRoot": true,
"factories": [
{ "method": "project", "returns": "Project", "description": "Create a Project handle from an ID." }
]
}
}Key decisions:
关键决策:
| Field | Purpose | Example |
|---|---|---|
| Fields stored on the instance | |
| Per-field data source mapping with optional | See below |
| Which param is injected from a parent class | |
| Which param the | |
| Local factory methods (no API call) | |
| 字段 | 用途 | 示例 |
|---|---|---|
| 存储在实例中的字段 | |
| 带可选 | 见下文 |
| 从父类注入的参数 | |
| | |
| 本地工厂方法(无API调用) | |
Field Mapping
字段映射
Use when a param needs a different source field, prefix stripping, or a fallback:
fieldMappingjson
{
"constructorParams": ["projectId", "screenId"],
"fieldMapping": {
"projectId": { "from": "name", "stripPrefix": "projects/" },
"screenId": { "from": "id", "fallback": { "field": "name", "splitOn": "/screens/" } }
}
}- : Removes a resource name prefix from the value
stripPrefix - : If the primary field is missing, splits an alternate field on a delimiter
fallback
当参数需要不同的源字段、前缀去除或回退时,使用:
fieldMappingjson
{
"constructorParams": ["projectId", "screenId"],
"fieldMapping": {
"projectId": { "from": "name", "stripPrefix": "projects/" },
"screenId": { "from": "id", "fallback": { "field": "name", "splitOn": "/screens/" } }
}
}- :从值中移除资源名称前缀
stripPrefix - :如果主字段缺失,使用分隔符分割备用字段
fallback
Designing Bindings
设计绑定
Each binding maps one MCP tool to one class method. Ask: "Who owns this action?"
每个绑定将一个MCP工具映射到一个类方法。思考:“谁拥有这个操作?”
Arg routing
参数路由
| Type | Meaning | Code generated |
|---|---|---|
| From | |
| From method parameter | |
| Template interpolation | |
| Wrap self field as array | |
Optional params use . Renamed params use .
"optional": true"rename": "newName"| 类型 | 含义 | 生成的代码 |
|---|---|---|
| 来自 | |
| 来自方法参数 | |
| 模板插值 | |
| 将自身字段包装为数组 | |
可选参数使用。重命名参数使用。
"optional": true"rename": "newName"Response Projections
响应投影
The array tells codegen how to navigate the API response. Each step is a :
returns.projectionProjectionSteptypescript
{ prop: string; index?: number; each?: boolean; fallback?: string }| Projection | Generated code | Use when |
|---|---|---|
| | Direct return (whole response) |
| | Array inside object |
| | Deeply nested single item |
| | Collect all items across arrays |
| | Navigate nested properties |
Decision: Use when extracting a single item. Use when collecting all items (array result). You cannot use both on the same step.
"index": 0"each": true[!TIP] Everyin a projection is validated against the tool'spropat codegen time. If you typo a property name, codegen will fail with a diagnostic listing the available properties.outputSchema
returns.projectionProjectionSteptypescript
{ prop: string; index?: number; each?: boolean; fallback?: string }| 投影方式 | 生成的代码 | 使用场景 |
|---|---|---|
| | 直接返回(整个响应) |
| | 对象内的数组 |
| | 深层嵌套的单个项 |
| | 收集数组中的所有项 |
| | 导航嵌套属性 |
决策:提取单个项时使用。收集所有项(数组结果)时使用。你不能在同一步骤中同时使用两者。
"index": 0"each": true[!TIP] 投影中的每个都会在代码生成时与工具的prop进行验证。如果你输入了错误的属性名称,代码生成会失败并显示诊断信息,列出可用的属性。outputSchema
Return class wrapping
返回类包装
When is set, the extracted data is wrapped in a domain class constructor:
returns.classjson
{ "returns": { "class": "Screen", "projection": [{ "prop": "screens" }], "array": true } }The codegen automatically spreads into the data if the child class declares one.
parentField当设置时,提取的数据会被包装到领域类的构造函数中:
returns.classjson
{ "returns": { "class": "Screen", "projection": [{ "prop": "screens" }], "array": true } }如果子类声明了,代码生成工具会自动将其展开到数据中。
parentFieldCache-aware methods
缓存感知方法
Add a field with a structured to check before calling the API:
cacheprojectionthis.datajson
{
"cache": {
"projection": [{ "prop": "htmlCode" }, { "prop": "downloadUrl" }],
"description": "Use cached HTML download URL from generation response if available"
}
}When the cached property is a nested object (like with a ), use multiple projection steps to drill into it.
FiledownloadUrlGenerated code:
typescript
if (this.data?.htmlCode?.downloadUrl) return this.data?.htmlCode?.downloadUrl;
// ... else call API添加带有结构化的字段,以在调用API前检查:
projectioncachethis.datajson
{
"cache": {
"projection": [{ "prop": "htmlCode" }, { "prop": "downloadUrl" }],
"description": "Use cached HTML download URL from generation response if available"
}
}当缓存的属性是嵌套对象(比如带有的)时,使用多个投影步骤深入其中。
downloadUrlFile生成的代码:
typescript
if (this.data?.htmlCode?.downloadUrl) return this.data?.htmlCode?.downloadUrl;
// ... else call APIDecision Framework
决策框架
When mapping a new tool, answer these questions:
-
Which class? Look at which fields the tool requires. If it needsfrom
projectId, it belongs onselforProject. If it needs nothing from self, it belongs onScreen.Stitch -
Which method name? Use the verb from the tool name, simplified.→
generate_screen_from_text.generate→edit_screens.edit -
Arguments from self or param? If the caller already has the data (because they're calling a method on themselves), use. If they need to provide it, use
self.param -
How deep is the return? Check the tool'sin
outputSchema. Build thetools-manifest.jsonarray step-by-step to navigate to the useful data.projection -
Should it cache? If the data is available from a previous response (like generation), add a cache field with the projection path.
映射新工具时,回答以下问题:
-
归属哪个类? 查看工具需要哪些字段。如果它需要来自的
self,则属于projectId或Project类。如果它不需要来自self的任何数据,则属于Screen类。Stitch -
方法名称是什么? 使用工具名称中的动词,简化处理。→
generate_screen_from_text。generate→edit_screens。edit -
参数来自self还是param? 如果调用者已经拥有数据(因为他们在调用自身的方法),使用。如果需要调用者提供数据,使用
self。param -
返回数据的深度如何?查看中的工具
tools-manifest.json。逐步构建outputSchema数组以导航到有用的数据。projection -
是否需要缓存? 如果数据可以从之前的响应中获取(比如生成结果),添加带有投影路径的cache字段。
Validation
验证
After editing :
domain-map.jsonbash
bun scripts/generate-sdk.ts # Validates IR + projections, then generates
npx tsc --noEmit # Type check
npx vitest run # Unit tests
bun scripts/e2e-test.ts # E2E tests
bun scripts/validate-generated.ts # Lock integrityIf a projection is invalid, you'll see:
❌ Binding "Project.generate" projection step 2:
property "screenz" not found in outputSchema.
Available properties: screens, components, metadata编辑后:
domain-map.jsonbash
bun scripts/generate-sdk.ts # 验证IR和投影,然后生成代码
npx tsc --noEmit # 类型检查
npx vitest run # 单元测试
bun scripts/e2e-test.ts # 端到端测试
bun scripts/validate-generated.ts # 锁定完整性如果投影无效,你会看到:
❌ Binding "Project.generate" projection step 2:
property "screenz" not found in outputSchema.
Available properties: screens, components, metadata