Skip to main content

working-on-plugins

Game plugin and adapter section design for Savecraft. Use when creating new plugins, designing GameState sections, adding sections to existing parsers, or working on section output in plugins/ or worker/src/adapters/. Triggers on section layout, progressive disclosure, GameState output, plugin sections, adapter sections, section sizing, or overview design.

설치로 이동

소스 정보

저장소
joshsymonds/savecraft.gg
최근 소스 활동
2026년 4월 13일 00:44
감지된 SKILL.md 언어
영어
스타
12
포크
0

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
working-on-plugins
description
Game plugin and adapter section design for Savecraft. Use when creating new plugins, designing GameState sections, adding sections to existing parsers, or working on section output in plugins/ or worker/src/adapters/. Triggers on section layout, progressive disclosure, GameState output, plugin sections, adapter sections, section sizing, or overview design.
# Working on Plugins: Section Design Both WASM plugins (`plugins/*/parser/`) and API adapters (`worker/src/adapters/`) produce the same `GameState` shape: `identity`, `summary`, and `sections`. This skill covers how to design sections so they work well with the MCP tools and AI consumers. For the ndjson contract, WASM runtime, and plugin build system, see `docs/plugins.md`. For API adapter architecture, see `docs/adapters.md`. ## Overview Section (Required) `get_save` embeds one section's data as the overview in its response. It picks the first match from this list: ``` character_overview → player_summary → overview → summary ``` **Every plugin MUST produce a section matching one of these names.** If none match, `get_save` falls back to the first section alphabetically — which may be a 200KB deck list or item dump. The overview section is the AI's first look at the save. It should contain enough context to answer "what is this character/save?" and guide the AI to the right detailed sections. ### What belongs in the overview - Identity: name, class, level, rank — whatever defines "who" - Key stats: currency, progression milestones, win/loss record - **Index of available sections** with pointers — deck names (not card lists), character names (not inventories), match list (not turn-by-turn logs) - Anything that helps the AI decide which section to fetch next ### What does NOT belong in the overview - Full item lists, card lists, or inventories - Turn-by-turn logs, match replays, or event histories - Large nested objects that the AI won't use to route **Target: overview section < 15KB.** A typical overview is 2-10KB. ## Section Size Limits | Limit | Value | Enforced by | |-------|-------|-------------| | Hard max per section | 80KB | `SECTION_SIZE_LIMIT` in `worker/src/mcp/tools.ts` — `get_section` rejects sections over this | | Overview target | < 15KB | Convention — keeps `get_save` response usable | | Individual item section | < 10KB typical | Convention — per-deck, per-character sections | If a section could exceed 80KB with realistic data, it MUST be split. ## Progressive Disclosure Pattern When a game has a large collection (decks, characters, items, matches), split into per-item sections with an index in the overview. ### Pattern ``` overview section: decks: [{name: "Slivers", format: "Brawl", section: "deck:Slivers"}, ...] deck:Slivers section: (full card list, ~5KB) deck:Control section: (full card list, ~3KB) ``` The AI sees the index in the overview and fetches individual items as needed. This is how D2R shared stash (`overview` + `tab1`, `tab2`, ...) and MTGA (`player_summary` + `deck:*`, `game:*`) work. ### When to split Split when **any** of these are true: - Collection has variable size controlled by the player (decks, blueprints, characters) - A single collection item can be > 5KB (full card lists, turn-by-turn logs) - Total collection could exceed 80KB (80 decks × 5KB = 400KB) ### Section naming for per-item sections Use `prefix:human_readable_name` — the AI requests sections by name, so readability matters. ``` deck:[HB] Slivers (MTGA deck) game:7a0be838-0033-4e16 (MTGA game log by matchId) tab1, tab2, tab3 (D2R stash tabs) character:Warrior (per-character sections) ``` ### Stale section cleanup The daemon sends `allSectionNames` in every `PushSave` message. The worker deletes any sections NOT in this list. Dynamic section names (deck:*, game:*) work correctly — the parser includes them all in the output, and the worker cleans up sections that no longer exist. ## Section Descriptions Section descriptions are the AI's guide for when to fetch a section. Write them as directives, not documentation. **Good** (tells AI when/why to fetch): ``` "Deck list for [HB] Slivers (Brawl) — main deck, sideboard, and command zone cards" "Turn-by-turn game log for match abc123 — use to analyze play sequencing and identify misplays" "Aggregated character stats: resistances, magic find, FCR/FHR breakpoints — use to evaluate gear upgrades" ``` **Bad** (explains what it is, not when to use it): ``` "Contains the player's deck data" "Game log information" "Character statistics" ``` ## Existing Section Patterns by Game | Game | Overview Section | Per-Item Sections | Reference | |------|-----------------|-------------------|-----------| | D2R Character | `character_overview` | None (sections are small) | `plugins/d2r/parser/main.go` | | D2R Stash | `overview` | `tab1`, `tab2`, ... | `plugins/d2r/parser/main.go:545` | | MTGA | `player_summary` | `deck:*`, `game:*` | `plugins/magic/parser/main.go` | | Clair Obscur | `overview` | `character:*` | `plugins/clair-obscur/parser/` | | WoW | `character_overview` | None (API data is bounded) | `worker/src/adapters/wow/` | | SDV | `player_summary` | None (data is naturally bounded) | `plugins/sdv/parser/main.go` | ## Attribution (Required) Every plugin must declare an `[attribution]` section in `plugin.toml` listing the third-party IP sources whose data it uses. The build pipeline reads this to embed legal disclaimers in views. ```toml [attribution] sources = ["wotc", "scryfall", "17lands"] ``` Valid source keys are defined in `views/src/attributions.ts`: `wotc`, `scryfall`, `17lands`, `blizzard`, `raiderio`, `ludeon`, `concernedape`, `kepler`. To add a new source, add it to the `SOURCES` record in that file first. The build fails if `[attribution]` is missing or uses an unknown key. ## Checklist for New Plugins - [ ] Overview section name matches `OVERVIEW_SECTION_NAMES` - [ ] Overview section < 15KB with realistic data - [ ] All sections < 80KB with realistic data - [ ] Large collections use per-item sections with index in overview - [ ] Section descriptions are AI-directive (when/why to fetch) - [ ] Section data is always a JSON object (not array, string, or scalar) - [ ] `[attribution]` declared in `plugin.toml` with valid source keys - [ ] Tested with a real save file — measure actual section sizes
GitHub에서 보기